1//===-- Attributes.cpp - Implement AttributesList -------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements the AttributesList class and Attribute utilities. 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm/Attributes.h" 15#include "AttributesImpl.h" 16#include "LLVMContextImpl.h" 17#include "llvm/Type.h" 18#include "llvm/ADT/StringExtras.h" 19#include "llvm/ADT/FoldingSet.h" 20#include "llvm/Support/Atomic.h" 21#include "llvm/Support/Mutex.h" 22#include "llvm/Support/Debug.h" 23#include "llvm/Support/ManagedStatic.h" 24#include "llvm/Support/raw_ostream.h" 25using namespace llvm; 26 27//===----------------------------------------------------------------------===// 28// Attribute Function Definitions 29//===----------------------------------------------------------------------===// 30 31std::string Attributes::getAsString() const { 32 std::string Result; 33 if (hasZExtAttr()) 34 Result += "zeroext "; 35 if (hasSExtAttr()) 36 Result += "signext "; 37 if (hasNoReturnAttr()) 38 Result += "noreturn "; 39 if (hasNoUnwindAttr()) 40 Result += "nounwind "; 41 if (hasUWTableAttr()) 42 Result += "uwtable "; 43 if (hasReturnsTwiceAttr()) 44 Result += "returns_twice "; 45 if (hasInRegAttr()) 46 Result += "inreg "; 47 if (hasNoAliasAttr()) 48 Result += "noalias "; 49 if (hasNoCaptureAttr()) 50 Result += "nocapture "; 51 if (hasStructRetAttr()) 52 Result += "sret "; 53 if (hasByValAttr()) 54 Result += "byval "; 55 if (hasNestAttr()) 56 Result += "nest "; 57 if (hasReadNoneAttr()) 58 Result += "readnone "; 59 if (hasReadOnlyAttr()) 60 Result += "readonly "; 61 if (hasOptimizeForSizeAttr()) 62 Result += "optsize "; 63 if (hasNoInlineAttr()) 64 Result += "noinline "; 65 if (hasInlineHintAttr()) 66 Result += "inlinehint "; 67 if (hasAlwaysInlineAttr()) 68 Result += "alwaysinline "; 69 if (hasStackProtectAttr()) 70 Result += "ssp "; 71 if (hasStackProtectReqAttr()) 72 Result += "sspreq "; 73 if (hasNoRedZoneAttr()) 74 Result += "noredzone "; 75 if (hasNoImplicitFloatAttr()) 76 Result += "noimplicitfloat "; 77 if (hasNakedAttr()) 78 Result += "naked "; 79 if (hasNonLazyBindAttr()) 80 Result += "nonlazybind "; 81 if (hasAddressSafetyAttr()) 82 Result += "address_safety "; 83 if (hasStackAlignmentAttr()) { 84 Result += "alignstack("; 85 Result += utostr(getStackAlignment()); 86 Result += ") "; 87 } 88 if (hasAlignmentAttr()) { 89 Result += "align "; 90 Result += utostr(getAlignment()); 91 Result += " "; 92 } 93 // Trim the trailing space. 94 assert(!Result.empty() && "Unknown attribute!"); 95 Result.erase(Result.end()-1); 96 return Result; 97} 98 99Attributes Attributes::typeIncompatible(Type *Ty) { 100 Attributes Incompatible = Attribute::None; 101 102 if (!Ty->isIntegerTy()) 103 // Attributes that only apply to integers. 104 Incompatible |= Attribute::SExt | Attribute::ZExt; 105 106 if (!Ty->isPointerTy()) 107 // Attributes that only apply to pointers. 108 Incompatible |= Attribute::ByVal | Attribute::Nest | Attribute::NoAlias | 109 Attribute::StructRet | Attribute::NoCapture; 110 111 return Incompatible; 112} 113 114//===----------------------------------------------------------------------===// 115// AttributeImpl Definition 116//===----------------------------------------------------------------------===// 117 118Attributes::Attributes(AttributesImpl *A) : Bits(0) {} 119 120Attributes Attributes::get(LLVMContext &Context, Attributes::Builder &B) { 121 // If there are no attributes, return an empty Attributes class. 122 if (B.Bits == 0) 123 return Attributes(); 124 125 // Otherwise, build a key to look up the existing attributes. 126 LLVMContextImpl *pImpl = Context.pImpl; 127 FoldingSetNodeID ID; 128 ID.AddInteger(B.Bits); 129 130 void *InsertPoint; 131 AttributesImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); 132 133 if (!PA) { 134 // If we didn't find any existing attributes of the same shape then create a 135 // new one and insert it. 136 PA = new AttributesImpl(B.Bits); 137 pImpl->AttrsSet.InsertNode(PA, InsertPoint); 138 } 139 140 // Return the AttributesList that we found or created. 141 return Attributes(PA); 142} 143 144//===----------------------------------------------------------------------===// 145// AttributeListImpl Definition 146//===----------------------------------------------------------------------===// 147 148namespace llvm { 149 class AttributeListImpl; 150} 151 152static ManagedStatic<FoldingSet<AttributeListImpl> > AttributesLists; 153 154namespace llvm { 155static ManagedStatic<sys::SmartMutex<true> > ALMutex; 156 157class AttributeListImpl : public FoldingSetNode { 158 sys::cas_flag RefCount; 159 160 // AttributesList is uniqued, these should not be publicly available. 161 void operator=(const AttributeListImpl &) LLVM_DELETED_FUNCTION; 162 AttributeListImpl(const AttributeListImpl &) LLVM_DELETED_FUNCTION; 163 ~AttributeListImpl(); // Private implementation 164public: 165 SmallVector<AttributeWithIndex, 4> Attrs; 166 167 AttributeListImpl(ArrayRef<AttributeWithIndex> attrs) 168 : Attrs(attrs.begin(), attrs.end()) { 169 RefCount = 0; 170 } 171 172 void AddRef() { 173 sys::SmartScopedLock<true> Lock(*ALMutex); 174 ++RefCount; 175 } 176 void DropRef() { 177 sys::SmartScopedLock<true> Lock(*ALMutex); 178 if (!AttributesLists.isConstructed()) 179 return; 180 sys::cas_flag new_val = --RefCount; 181 if (new_val == 0) 182 delete this; 183 } 184 185 void Profile(FoldingSetNodeID &ID) const { 186 Profile(ID, Attrs); 187 } 188 static void Profile(FoldingSetNodeID &ID, ArrayRef<AttributeWithIndex> Attrs){ 189 for (unsigned i = 0, e = Attrs.size(); i != e; ++i) { 190 ID.AddInteger(Attrs[i].Attrs.Raw()); 191 ID.AddInteger(Attrs[i].Index); 192 } 193 } 194}; 195} 196 197AttributeListImpl::~AttributeListImpl() { 198 // NOTE: Lock must be acquired by caller. 199 AttributesLists->RemoveNode(this); 200} 201 202 203AttrListPtr AttrListPtr::get(ArrayRef<AttributeWithIndex> Attrs) { 204 // If there are no attributes then return a null AttributesList pointer. 205 if (Attrs.empty()) 206 return AttrListPtr(); 207 208#ifndef NDEBUG 209 for (unsigned i = 0, e = Attrs.size(); i != e; ++i) { 210 assert(Attrs[i].Attrs.hasAttributes() && 211 "Pointless attribute!"); 212 assert((!i || Attrs[i-1].Index < Attrs[i].Index) && 213 "Misordered AttributesList!"); 214 } 215#endif 216 217 // Otherwise, build a key to look up the existing attributes. 218 FoldingSetNodeID ID; 219 AttributeListImpl::Profile(ID, Attrs); 220 void *InsertPos; 221 222 sys::SmartScopedLock<true> Lock(*ALMutex); 223 224 AttributeListImpl *PAL = 225 AttributesLists->FindNodeOrInsertPos(ID, InsertPos); 226 227 // If we didn't find any existing attributes of the same shape then 228 // create a new one and insert it. 229 if (!PAL) { 230 PAL = new AttributeListImpl(Attrs); 231 AttributesLists->InsertNode(PAL, InsertPos); 232 } 233 234 // Return the AttributesList that we found or created. 235 return AttrListPtr(PAL); 236} 237 238 239//===----------------------------------------------------------------------===// 240// AttrListPtr Method Implementations 241//===----------------------------------------------------------------------===// 242 243AttrListPtr::AttrListPtr(AttributeListImpl *LI) : AttrList(LI) { 244 if (LI) LI->AddRef(); 245} 246 247AttrListPtr::AttrListPtr(const AttrListPtr &P) : AttrList(P.AttrList) { 248 if (AttrList) AttrList->AddRef(); 249} 250 251const AttrListPtr &AttrListPtr::operator=(const AttrListPtr &RHS) { 252 sys::SmartScopedLock<true> Lock(*ALMutex); 253 if (AttrList == RHS.AttrList) return *this; 254 if (AttrList) AttrList->DropRef(); 255 AttrList = RHS.AttrList; 256 if (AttrList) AttrList->AddRef(); 257 return *this; 258} 259 260AttrListPtr::~AttrListPtr() { 261 if (AttrList) AttrList->DropRef(); 262} 263 264/// getNumSlots - Return the number of slots used in this attribute list. 265/// This is the number of arguments that have an attribute set on them 266/// (including the function itself). 267unsigned AttrListPtr::getNumSlots() const { 268 return AttrList ? AttrList->Attrs.size() : 0; 269} 270 271/// getSlot - Return the AttributeWithIndex at the specified slot. This 272/// holds a number plus a set of attributes. 273const AttributeWithIndex &AttrListPtr::getSlot(unsigned Slot) const { 274 assert(AttrList && Slot < AttrList->Attrs.size() && "Slot # out of range!"); 275 return AttrList->Attrs[Slot]; 276} 277 278 279/// getAttributes - The attributes for the specified index are 280/// returned. Attributes for the result are denoted with Idx = 0. 281/// Function notes are denoted with idx = ~0. 282Attributes AttrListPtr::getAttributes(unsigned Idx) const { 283 if (AttrList == 0) return Attributes(); 284 285 const SmallVector<AttributeWithIndex, 4> &Attrs = AttrList->Attrs; 286 for (unsigned i = 0, e = Attrs.size(); i != e && Attrs[i].Index <= Idx; ++i) 287 if (Attrs[i].Index == Idx) 288 return Attrs[i].Attrs; 289 290 return Attributes(); 291} 292 293/// hasAttrSomewhere - Return true if the specified attribute is set for at 294/// least one parameter or for the return value. 295bool AttrListPtr::hasAttrSomewhere(Attributes Attr) const { 296 if (AttrList == 0) return false; 297 298 const SmallVector<AttributeWithIndex, 4> &Attrs = AttrList->Attrs; 299 for (unsigned i = 0, e = Attrs.size(); i != e; ++i) 300 if (Attrs[i].Attrs.hasAttributes(Attr)) 301 return true; 302 return false; 303} 304 305 306AttrListPtr AttrListPtr::addAttr(unsigned Idx, Attributes Attrs) const { 307 Attributes OldAttrs = getAttributes(Idx); 308#ifndef NDEBUG 309 // FIXME it is not obvious how this should work for alignment. 310 // For now, say we can't change a known alignment. 311 unsigned OldAlign = OldAttrs.getAlignment(); 312 unsigned NewAlign = Attrs.getAlignment(); 313 assert((!OldAlign || !NewAlign || OldAlign == NewAlign) && 314 "Attempt to change alignment!"); 315#endif 316 317 Attributes NewAttrs = OldAttrs | Attrs; 318 if (NewAttrs == OldAttrs) 319 return *this; 320 321 SmallVector<AttributeWithIndex, 8> NewAttrList; 322 if (AttrList == 0) 323 NewAttrList.push_back(AttributeWithIndex::get(Idx, Attrs)); 324 else { 325 const SmallVector<AttributeWithIndex, 4> &OldAttrList = AttrList->Attrs; 326 unsigned i = 0, e = OldAttrList.size(); 327 // Copy attributes for arguments before this one. 328 for (; i != e && OldAttrList[i].Index < Idx; ++i) 329 NewAttrList.push_back(OldAttrList[i]); 330 331 // If there are attributes already at this index, merge them in. 332 if (i != e && OldAttrList[i].Index == Idx) { 333 Attrs |= OldAttrList[i].Attrs; 334 ++i; 335 } 336 337 NewAttrList.push_back(AttributeWithIndex::get(Idx, Attrs)); 338 339 // Copy attributes for arguments after this one. 340 NewAttrList.insert(NewAttrList.end(), 341 OldAttrList.begin()+i, OldAttrList.end()); 342 } 343 344 return get(NewAttrList); 345} 346 347AttrListPtr AttrListPtr::removeAttr(unsigned Idx, Attributes Attrs) const { 348#ifndef NDEBUG 349 // FIXME it is not obvious how this should work for alignment. 350 // For now, say we can't pass in alignment, which no current use does. 351 assert(!Attrs.hasAlignmentAttr() && "Attempt to exclude alignment!"); 352#endif 353 if (AttrList == 0) return AttrListPtr(); 354 355 Attributes OldAttrs = getAttributes(Idx); 356 Attributes NewAttrs = OldAttrs & ~Attrs; 357 if (NewAttrs == OldAttrs) 358 return *this; 359 360 SmallVector<AttributeWithIndex, 8> NewAttrList; 361 const SmallVector<AttributeWithIndex, 4> &OldAttrList = AttrList->Attrs; 362 unsigned i = 0, e = OldAttrList.size(); 363 364 // Copy attributes for arguments before this one. 365 for (; i != e && OldAttrList[i].Index < Idx; ++i) 366 NewAttrList.push_back(OldAttrList[i]); 367 368 // If there are attributes already at this index, merge them in. 369 assert(OldAttrList[i].Index == Idx && "Attribute isn't set?"); 370 Attrs = OldAttrList[i].Attrs & ~Attrs; 371 ++i; 372 if (Attrs) // If any attributes left for this parameter, add them. 373 NewAttrList.push_back(AttributeWithIndex::get(Idx, Attrs)); 374 375 // Copy attributes for arguments after this one. 376 NewAttrList.insert(NewAttrList.end(), 377 OldAttrList.begin()+i, OldAttrList.end()); 378 379 return get(NewAttrList); 380} 381 382void AttrListPtr::dump() const { 383 dbgs() << "PAL[ "; 384 for (unsigned i = 0; i < getNumSlots(); ++i) { 385 const AttributeWithIndex &PAWI = getSlot(i); 386 dbgs() << "{" << PAWI.Index << "," << PAWI.Attrs << "} "; 387 } 388 389 dbgs() << "]\n"; 390} 391