1 //===- AttributeImpl.h - Attribute Internals --------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file defines various helper methods and classes used by 11 /// LLVMContextImpl for creating and managing attributes. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_LIB_IR_ATTRIBUTEIMPL_H 16 #define LLVM_LIB_IR_ATTRIBUTEIMPL_H 17 18 #include "llvm/ADT/ArrayRef.h" 19 #include "llvm/ADT/DenseMap.h" 20 #include "llvm/ADT/FoldingSet.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/IR/Attributes.h" 23 #include "llvm/IR/ConstantRange.h" 24 #include "llvm/IR/ConstantRangeList.h" 25 #include "llvm/Support/TrailingObjects.h" 26 #include <cassert> 27 #include <cstddef> 28 #include <cstdint> 29 #include <optional> 30 #include <string> 31 #include <utility> 32 33 namespace llvm { 34 35 class LLVMContext; 36 class Type; 37 38 //===----------------------------------------------------------------------===// 39 /// \class 40 /// This class represents a single, uniqued attribute. That attribute 41 /// could be a single enum, a tuple, or a string. 42 class AttributeImpl : public FoldingSetNode { 43 unsigned char KindID; ///< Holds the AttrEntryKind of the attribute 44 45 protected: 46 enum AttrEntryKind { 47 EnumAttrEntry, 48 IntAttrEntry, 49 StringAttrEntry, 50 TypeAttrEntry, 51 ConstantRangeAttrEntry, 52 ConstantRangeListAttrEntry, 53 }; 54 AttributeImpl(AttrEntryKind KindID)55 AttributeImpl(AttrEntryKind KindID) : KindID(KindID) {} 56 57 public: 58 // AttributesImpl is uniqued, these should not be available. 59 AttributeImpl(const AttributeImpl &) = delete; 60 AttributeImpl &operator=(const AttributeImpl &) = delete; 61 isEnumAttribute()62 bool isEnumAttribute() const { return KindID == EnumAttrEntry; } isIntAttribute()63 bool isIntAttribute() const { return KindID == IntAttrEntry; } isStringAttribute()64 bool isStringAttribute() const { return KindID == StringAttrEntry; } isTypeAttribute()65 bool isTypeAttribute() const { return KindID == TypeAttrEntry; } isConstantRangeAttribute()66 bool isConstantRangeAttribute() const { 67 return KindID == ConstantRangeAttrEntry; 68 } isConstantRangeListAttribute()69 bool isConstantRangeListAttribute() const { 70 return KindID == ConstantRangeListAttrEntry; 71 } 72 73 bool hasAttribute(Attribute::AttrKind A) const; 74 bool hasAttribute(StringRef Kind) const; 75 76 Attribute::AttrKind getKindAsEnum() const; 77 uint64_t getValueAsInt() const; 78 bool getValueAsBool() const; 79 80 StringRef getKindAsString() const; 81 StringRef getValueAsString() const; 82 83 Type *getValueAsType() const; 84 85 const ConstantRange &getValueAsConstantRange() const; 86 87 ArrayRef<ConstantRange> getValueAsConstantRangeList() const; 88 89 /// Used when sorting the attributes. 90 bool operator<(const AttributeImpl &AI) const; 91 Profile(FoldingSetNodeID & ID)92 void Profile(FoldingSetNodeID &ID) const { 93 if (isEnumAttribute()) 94 Profile(ID, getKindAsEnum()); 95 else if (isIntAttribute()) 96 Profile(ID, getKindAsEnum(), getValueAsInt()); 97 else if (isStringAttribute()) 98 Profile(ID, getKindAsString(), getValueAsString()); 99 else if (isTypeAttribute()) 100 Profile(ID, getKindAsEnum(), getValueAsType()); 101 else if (isConstantRangeAttribute()) 102 Profile(ID, getKindAsEnum(), getValueAsConstantRange()); 103 else 104 Profile(ID, getKindAsEnum(), getValueAsConstantRangeList()); 105 } 106 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind)107 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind) { 108 assert(Attribute::isEnumAttrKind(Kind) && "Expected enum attribute"); 109 ID.AddInteger(Kind); 110 } 111 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind,uint64_t Val)112 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, 113 uint64_t Val) { 114 assert(Attribute::isIntAttrKind(Kind) && "Expected int attribute"); 115 ID.AddInteger(Kind); 116 ID.AddInteger(Val); 117 } 118 Profile(FoldingSetNodeID & ID,StringRef Kind,StringRef Values)119 static void Profile(FoldingSetNodeID &ID, StringRef Kind, StringRef Values) { 120 ID.AddString(Kind); 121 if (!Values.empty()) ID.AddString(Values); 122 } 123 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind,Type * Ty)124 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, 125 Type *Ty) { 126 ID.AddInteger(Kind); 127 ID.AddPointer(Ty); 128 } 129 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind,const ConstantRange & CR)130 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, 131 const ConstantRange &CR) { 132 ID.AddInteger(Kind); 133 CR.getLower().Profile(ID); 134 CR.getUpper().Profile(ID); 135 } 136 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind,ArrayRef<ConstantRange> Val)137 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, 138 ArrayRef<ConstantRange> Val) { 139 ID.AddInteger(Kind); 140 ID.AddInteger(Val.size()); 141 for (auto &CR : Val) { 142 CR.getLower().Profile(ID); 143 CR.getUpper().Profile(ID); 144 } 145 } 146 }; 147 148 static_assert(std::is_trivially_destructible<AttributeImpl>::value, 149 "AttributeImpl should be trivially destructible"); 150 151 //===----------------------------------------------------------------------===// 152 /// \class 153 /// A set of classes that contain the value of the 154 /// attribute object. There are three main categories: enum attribute entries, 155 /// represented by Attribute::AttrKind; alignment attribute entries; and string 156 /// attribute enties, which are for target-dependent attributes. 157 158 class EnumAttributeImpl : public AttributeImpl { 159 Attribute::AttrKind Kind; 160 161 protected: EnumAttributeImpl(AttrEntryKind ID,Attribute::AttrKind Kind)162 EnumAttributeImpl(AttrEntryKind ID, Attribute::AttrKind Kind) 163 : AttributeImpl(ID), Kind(Kind) {} 164 165 public: EnumAttributeImpl(Attribute::AttrKind Kind)166 EnumAttributeImpl(Attribute::AttrKind Kind) 167 : AttributeImpl(EnumAttrEntry), Kind(Kind) { 168 assert(Kind != Attribute::AttrKind::None && 169 "Can't create a None attribute!"); 170 } 171 getEnumKind()172 Attribute::AttrKind getEnumKind() const { return Kind; } 173 }; 174 175 class IntAttributeImpl : public EnumAttributeImpl { 176 uint64_t Val; 177 178 public: IntAttributeImpl(Attribute::AttrKind Kind,uint64_t Val)179 IntAttributeImpl(Attribute::AttrKind Kind, uint64_t Val) 180 : EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) { 181 assert(Attribute::isIntAttrKind(Kind) && 182 "Wrong kind for int attribute!"); 183 } 184 getValue()185 uint64_t getValue() const { return Val; } 186 }; 187 188 class StringAttributeImpl final 189 : public AttributeImpl, 190 private TrailingObjects<StringAttributeImpl, char> { 191 friend TrailingObjects; 192 193 unsigned KindSize; 194 unsigned ValSize; numTrailingObjects(OverloadToken<char>)195 size_t numTrailingObjects(OverloadToken<char>) const { 196 return KindSize + 1 + ValSize + 1; 197 } 198 199 public: 200 StringAttributeImpl(StringRef Kind, StringRef Val = StringRef()) AttributeImpl(StringAttrEntry)201 : AttributeImpl(StringAttrEntry), KindSize(Kind.size()), 202 ValSize(Val.size()) { 203 char *TrailingString = getTrailingObjects<char>(); 204 // Some users rely on zero-termination. 205 llvm::copy(Kind, TrailingString); 206 TrailingString[KindSize] = '\0'; 207 llvm::copy(Val, &TrailingString[KindSize + 1]); 208 TrailingString[KindSize + 1 + ValSize] = '\0'; 209 } 210 getStringKind()211 StringRef getStringKind() const { 212 return StringRef(getTrailingObjects<char>(), KindSize); 213 } getStringValue()214 StringRef getStringValue() const { 215 return StringRef(getTrailingObjects<char>() + KindSize + 1, ValSize); 216 } 217 totalSizeToAlloc(StringRef Kind,StringRef Val)218 static size_t totalSizeToAlloc(StringRef Kind, StringRef Val) { 219 return TrailingObjects::totalSizeToAlloc<char>(Kind.size() + 1 + 220 Val.size() + 1); 221 } 222 }; 223 224 class TypeAttributeImpl : public EnumAttributeImpl { 225 Type *Ty; 226 227 public: TypeAttributeImpl(Attribute::AttrKind Kind,Type * Ty)228 TypeAttributeImpl(Attribute::AttrKind Kind, Type *Ty) 229 : EnumAttributeImpl(TypeAttrEntry, Kind), Ty(Ty) {} 230 getTypeValue()231 Type *getTypeValue() const { return Ty; } 232 }; 233 234 class ConstantRangeAttributeImpl : public EnumAttributeImpl { 235 ConstantRange CR; 236 237 public: ConstantRangeAttributeImpl(Attribute::AttrKind Kind,const ConstantRange & CR)238 ConstantRangeAttributeImpl(Attribute::AttrKind Kind, const ConstantRange &CR) 239 : EnumAttributeImpl(ConstantRangeAttrEntry, Kind), CR(CR) {} 240 getConstantRangeValue()241 const ConstantRange &getConstantRangeValue() const { return CR; } 242 }; 243 244 class ConstantRangeListAttributeImpl final 245 : public EnumAttributeImpl, 246 private TrailingObjects<ConstantRangeListAttributeImpl, ConstantRange> { 247 friend TrailingObjects; 248 249 unsigned Size; numTrailingObjects(OverloadToken<ConstantRange>)250 size_t numTrailingObjects(OverloadToken<ConstantRange>) const { return Size; } 251 252 public: ConstantRangeListAttributeImpl(Attribute::AttrKind Kind,ArrayRef<ConstantRange> Val)253 ConstantRangeListAttributeImpl(Attribute::AttrKind Kind, 254 ArrayRef<ConstantRange> Val) 255 : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), Size(Val.size()) { 256 assert(Size > 0); 257 ConstantRange *TrailingCR = getTrailingObjects<ConstantRange>(); 258 std::uninitialized_copy(Val.begin(), Val.end(), TrailingCR); 259 } 260 ~ConstantRangeListAttributeImpl()261 ~ConstantRangeListAttributeImpl() { 262 ConstantRange *TrailingCR = getTrailingObjects<ConstantRange>(); 263 for (unsigned I = 0; I != Size; ++I) 264 TrailingCR[I].~ConstantRange(); 265 } 266 getConstantRangeListValue()267 ArrayRef<ConstantRange> getConstantRangeListValue() const { 268 return ArrayRef(getTrailingObjects<ConstantRange>(), Size); 269 } 270 totalSizeToAlloc(ArrayRef<ConstantRange> Val)271 static size_t totalSizeToAlloc(ArrayRef<ConstantRange> Val) { 272 return TrailingObjects::totalSizeToAlloc<ConstantRange>(Val.size()); 273 } 274 }; 275 276 class AttributeBitSet { 277 /// Bitset with a bit for each available attribute Attribute::AttrKind. 278 uint8_t AvailableAttrs[12] = {}; 279 static_assert(Attribute::EndAttrKinds <= sizeof(AvailableAttrs) * CHAR_BIT, 280 "Too many attributes"); 281 282 public: hasAttribute(Attribute::AttrKind Kind)283 bool hasAttribute(Attribute::AttrKind Kind) const { 284 return AvailableAttrs[Kind / 8] & (1 << (Kind % 8)); 285 } 286 addAttribute(Attribute::AttrKind Kind)287 void addAttribute(Attribute::AttrKind Kind) { 288 AvailableAttrs[Kind / 8] |= 1 << (Kind % 8); 289 } 290 }; 291 292 //===----------------------------------------------------------------------===// 293 /// \class 294 /// This class represents a group of attributes that apply to one 295 /// element: function, return type, or parameter. 296 class AttributeSetNode final 297 : public FoldingSetNode, 298 private TrailingObjects<AttributeSetNode, Attribute> { 299 friend TrailingObjects; 300 301 unsigned NumAttrs; ///< Number of attributes in this node. 302 AttributeBitSet AvailableAttrs; ///< Available enum attributes. 303 304 DenseMap<StringRef, Attribute> StringAttrs; 305 306 AttributeSetNode(ArrayRef<Attribute> Attrs); 307 308 static AttributeSetNode *getSorted(LLVMContext &C, 309 ArrayRef<Attribute> SortedAttrs); 310 std::optional<Attribute> findEnumAttribute(Attribute::AttrKind Kind) const; 311 312 public: 313 // AttributesSetNode is uniqued, these should not be available. 314 AttributeSetNode(const AttributeSetNode &) = delete; 315 AttributeSetNode &operator=(const AttributeSetNode &) = delete; 316 delete(void * p)317 void operator delete(void *p) { ::operator delete(p); } 318 319 static AttributeSetNode *get(LLVMContext &C, const AttrBuilder &B); 320 321 static AttributeSetNode *get(LLVMContext &C, ArrayRef<Attribute> Attrs); 322 323 /// Return the number of attributes this AttributeList contains. getNumAttributes()324 unsigned getNumAttributes() const { return NumAttrs; } 325 hasAttribute(Attribute::AttrKind Kind)326 bool hasAttribute(Attribute::AttrKind Kind) const { 327 return AvailableAttrs.hasAttribute(Kind); 328 } 329 bool hasAttribute(StringRef Kind) const; hasAttributes()330 bool hasAttributes() const { return NumAttrs != 0; } 331 332 Attribute getAttribute(Attribute::AttrKind Kind) const; 333 Attribute getAttribute(StringRef Kind) const; 334 335 MaybeAlign getAlignment() const; 336 MaybeAlign getStackAlignment() const; 337 uint64_t getDereferenceableBytes() const; 338 uint64_t getDereferenceableOrNullBytes() const; 339 std::optional<std::pair<unsigned, std::optional<unsigned>>> getAllocSizeArgs() 340 const; 341 unsigned getVScaleRangeMin() const; 342 std::optional<unsigned> getVScaleRangeMax() const; 343 UWTableKind getUWTableKind() const; 344 AllocFnKind getAllocKind() const; 345 MemoryEffects getMemoryEffects() const; 346 FPClassTest getNoFPClass() const; 347 std::string getAsString(bool InAttrGrp) const; 348 Type *getAttributeType(Attribute::AttrKind Kind) const; 349 350 using iterator = const Attribute *; 351 begin()352 iterator begin() const { return getTrailingObjects<Attribute>(); } end()353 iterator end() const { return begin() + NumAttrs; } 354 Profile(FoldingSetNodeID & ID)355 void Profile(FoldingSetNodeID &ID) const { 356 Profile(ID, ArrayRef(begin(), end())); 357 } 358 Profile(FoldingSetNodeID & ID,ArrayRef<Attribute> AttrList)359 static void Profile(FoldingSetNodeID &ID, ArrayRef<Attribute> AttrList) { 360 for (const auto &Attr : AttrList) 361 Attr.Profile(ID); 362 } 363 }; 364 365 //===----------------------------------------------------------------------===// 366 /// \class 367 /// This class represents a set of attributes that apply to the function, 368 /// return type, and parameters. 369 class AttributeListImpl final 370 : public FoldingSetNode, 371 private TrailingObjects<AttributeListImpl, AttributeSet> { 372 friend class AttributeList; 373 friend TrailingObjects; 374 375 private: 376 unsigned NumAttrSets; ///< Number of entries in this set. 377 /// Available enum function attributes. 378 AttributeBitSet AvailableFunctionAttrs; 379 /// Union of enum attributes available at any index. 380 AttributeBitSet AvailableSomewhereAttrs; 381 382 // Helper fn for TrailingObjects class. numTrailingObjects(OverloadToken<AttributeSet>)383 size_t numTrailingObjects(OverloadToken<AttributeSet>) { return NumAttrSets; } 384 385 public: 386 AttributeListImpl(ArrayRef<AttributeSet> Sets); 387 388 // AttributesSetImpt is uniqued, these should not be available. 389 AttributeListImpl(const AttributeListImpl &) = delete; 390 AttributeListImpl &operator=(const AttributeListImpl &) = delete; 391 392 /// Return true if the AttributeSet or the FunctionIndex has an 393 /// enum attribute of the given kind. hasFnAttribute(Attribute::AttrKind Kind)394 bool hasFnAttribute(Attribute::AttrKind Kind) const { 395 return AvailableFunctionAttrs.hasAttribute(Kind); 396 } 397 398 /// Return true if the specified attribute is set for at least one 399 /// parameter or for the return value. If Index is not nullptr, the index 400 /// of a parameter with the specified attribute is provided. 401 bool hasAttrSomewhere(Attribute::AttrKind Kind, 402 unsigned *Index = nullptr) const; 403 404 using iterator = const AttributeSet *; 405 begin()406 iterator begin() const { return getTrailingObjects<AttributeSet>(); } end()407 iterator end() const { return begin() + NumAttrSets; } 408 409 void Profile(FoldingSetNodeID &ID) const; 410 static void Profile(FoldingSetNodeID &ID, ArrayRef<AttributeSet> Nodes); 411 412 void dump() const; 413 }; 414 415 static_assert(std::is_trivially_destructible<AttributeListImpl>::value, 416 "AttributeListImpl should be trivially destructible"); 417 418 } // end namespace llvm 419 420 #endif // LLVM_LIB_IR_ATTRIBUTEIMPL_H 421