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 to sort attributes. KindOnly controls if the sort includes the 90 /// attributes' values or just the kind. 91 int cmp(const AttributeImpl &AI, bool KindOnly) const; 92 /// Used when sorting the attributes. 93 bool operator<(const AttributeImpl &AI) const; 94 Profile(FoldingSetNodeID & ID)95 void Profile(FoldingSetNodeID &ID) const { 96 if (isEnumAttribute()) 97 Profile(ID, getKindAsEnum()); 98 else if (isIntAttribute()) 99 Profile(ID, getKindAsEnum(), getValueAsInt()); 100 else if (isStringAttribute()) 101 Profile(ID, getKindAsString(), getValueAsString()); 102 else if (isTypeAttribute()) 103 Profile(ID, getKindAsEnum(), getValueAsType()); 104 else if (isConstantRangeAttribute()) 105 Profile(ID, getKindAsEnum(), getValueAsConstantRange()); 106 else 107 Profile(ID, getKindAsEnum(), getValueAsConstantRangeList()); 108 } 109 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind)110 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind) { 111 assert(Attribute::isEnumAttrKind(Kind) && "Expected enum attribute"); 112 ID.AddInteger(Kind); 113 } 114 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind,uint64_t Val)115 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, 116 uint64_t Val) { 117 assert(Attribute::isIntAttrKind(Kind) && "Expected int attribute"); 118 ID.AddInteger(Kind); 119 ID.AddInteger(Val); 120 } 121 Profile(FoldingSetNodeID & ID,StringRef Kind,StringRef Values)122 static void Profile(FoldingSetNodeID &ID, StringRef Kind, StringRef Values) { 123 ID.AddString(Kind); 124 if (!Values.empty()) ID.AddString(Values); 125 } 126 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind,Type * Ty)127 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, 128 Type *Ty) { 129 ID.AddInteger(Kind); 130 ID.AddPointer(Ty); 131 } 132 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind,const ConstantRange & CR)133 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, 134 const ConstantRange &CR) { 135 ID.AddInteger(Kind); 136 CR.getLower().Profile(ID); 137 CR.getUpper().Profile(ID); 138 } 139 Profile(FoldingSetNodeID & ID,Attribute::AttrKind Kind,ArrayRef<ConstantRange> Val)140 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, 141 ArrayRef<ConstantRange> Val) { 142 ID.AddInteger(Kind); 143 ID.AddInteger(Val.size()); 144 for (auto &CR : Val) { 145 CR.getLower().Profile(ID); 146 CR.getUpper().Profile(ID); 147 } 148 } 149 }; 150 151 static_assert(std::is_trivially_destructible<AttributeImpl>::value, 152 "AttributeImpl should be trivially destructible"); 153 154 //===----------------------------------------------------------------------===// 155 /// \class 156 /// A set of classes that contain the value of the 157 /// attribute object. There are three main categories: enum attribute entries, 158 /// represented by Attribute::AttrKind; alignment attribute entries; and string 159 /// attribute enties, which are for target-dependent attributes. 160 161 class EnumAttributeImpl : public AttributeImpl { 162 Attribute::AttrKind Kind; 163 164 protected: EnumAttributeImpl(AttrEntryKind ID,Attribute::AttrKind Kind)165 EnumAttributeImpl(AttrEntryKind ID, Attribute::AttrKind Kind) 166 : AttributeImpl(ID), Kind(Kind) {} 167 168 public: EnumAttributeImpl(Attribute::AttrKind Kind)169 EnumAttributeImpl(Attribute::AttrKind Kind) 170 : AttributeImpl(EnumAttrEntry), Kind(Kind) { 171 assert(Kind != Attribute::AttrKind::None && 172 "Can't create a None attribute!"); 173 } 174 getEnumKind()175 Attribute::AttrKind getEnumKind() const { return Kind; } 176 }; 177 178 class IntAttributeImpl : public EnumAttributeImpl { 179 uint64_t Val; 180 181 public: IntAttributeImpl(Attribute::AttrKind Kind,uint64_t Val)182 IntAttributeImpl(Attribute::AttrKind Kind, uint64_t Val) 183 : EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) { 184 assert(Attribute::isIntAttrKind(Kind) && 185 "Wrong kind for int attribute!"); 186 } 187 getValue()188 uint64_t getValue() const { return Val; } 189 }; 190 191 class StringAttributeImpl final 192 : public AttributeImpl, 193 private TrailingObjects<StringAttributeImpl, char> { 194 friend TrailingObjects; 195 196 unsigned KindSize; 197 unsigned ValSize; 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(); 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(), KindSize); 213 } getStringValue()214 StringRef getStringValue() const { 215 return StringRef(getTrailingObjects() + 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; 250 251 public: ConstantRangeListAttributeImpl(Attribute::AttrKind Kind,ArrayRef<ConstantRange> Val)252 ConstantRangeListAttributeImpl(Attribute::AttrKind Kind, 253 ArrayRef<ConstantRange> Val) 254 : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), Size(Val.size()) { 255 assert(Size > 0); 256 llvm::uninitialized_copy(Val, getTrailingObjects()); 257 } 258 ~ConstantRangeListAttributeImpl()259 ~ConstantRangeListAttributeImpl() { 260 for (ConstantRange &CR : getTrailingObjects(Size)) 261 CR.~ConstantRange(); 262 } 263 getConstantRangeListValue()264 ArrayRef<ConstantRange> getConstantRangeListValue() const { 265 return getTrailingObjects(Size); 266 } 267 totalSizeToAlloc(ArrayRef<ConstantRange> Val)268 static size_t totalSizeToAlloc(ArrayRef<ConstantRange> Val) { 269 return TrailingObjects::totalSizeToAlloc<ConstantRange>(Val.size()); 270 } 271 }; 272 273 class AttributeBitSet { 274 /// Bitset with a bit for each available attribute Attribute::AttrKind. 275 uint8_t AvailableAttrs[16] = {}; 276 static_assert(Attribute::EndAttrKinds <= sizeof(AvailableAttrs) * CHAR_BIT, 277 "Too many attributes"); 278 279 public: hasAttribute(Attribute::AttrKind Kind)280 bool hasAttribute(Attribute::AttrKind Kind) const { 281 return AvailableAttrs[Kind / 8] & (1 << (Kind % 8)); 282 } 283 addAttribute(Attribute::AttrKind Kind)284 void addAttribute(Attribute::AttrKind Kind) { 285 AvailableAttrs[Kind / 8] |= 1 << (Kind % 8); 286 } 287 }; 288 289 //===----------------------------------------------------------------------===// 290 /// \class 291 /// This class represents a group of attributes that apply to one 292 /// element: function, return type, or parameter. 293 class AttributeSetNode final 294 : public FoldingSetNode, 295 private TrailingObjects<AttributeSetNode, Attribute> { 296 friend TrailingObjects; 297 298 unsigned NumAttrs; ///< Number of attributes in this node. 299 AttributeBitSet AvailableAttrs; ///< Available enum attributes. 300 301 DenseMap<StringRef, Attribute> StringAttrs; 302 303 AttributeSetNode(ArrayRef<Attribute> Attrs); 304 305 static AttributeSetNode *getSorted(LLVMContext &C, 306 ArrayRef<Attribute> SortedAttrs); 307 std::optional<Attribute> findEnumAttribute(Attribute::AttrKind Kind) const; 308 309 public: 310 // AttributesSetNode is uniqued, these should not be available. 311 AttributeSetNode(const AttributeSetNode &) = delete; 312 AttributeSetNode &operator=(const AttributeSetNode &) = delete; 313 delete(void * p)314 void operator delete(void *p) { ::operator delete(p); } 315 316 static AttributeSetNode *get(LLVMContext &C, const AttrBuilder &B); 317 318 static AttributeSetNode *get(LLVMContext &C, ArrayRef<Attribute> Attrs); 319 320 /// Return the number of attributes this AttributeList contains. getNumAttributes()321 unsigned getNumAttributes() const { return NumAttrs; } 322 hasAttribute(Attribute::AttrKind Kind)323 bool hasAttribute(Attribute::AttrKind Kind) const { 324 return AvailableAttrs.hasAttribute(Kind); 325 } 326 bool hasAttribute(StringRef Kind) const; hasAttributes()327 bool hasAttributes() const { return NumAttrs != 0; } 328 329 Attribute getAttribute(Attribute::AttrKind Kind) const; 330 Attribute getAttribute(StringRef Kind) const; 331 332 MaybeAlign getAlignment() const; 333 MaybeAlign getStackAlignment() const; 334 uint64_t getDereferenceableBytes() const; 335 uint64_t getDereferenceableOrNullBytes() const; 336 std::optional<std::pair<unsigned, std::optional<unsigned>>> getAllocSizeArgs() 337 const; 338 unsigned getVScaleRangeMin() const; 339 std::optional<unsigned> getVScaleRangeMax() const; 340 UWTableKind getUWTableKind() const; 341 AllocFnKind getAllocKind() const; 342 MemoryEffects getMemoryEffects() const; 343 CaptureInfo getCaptureInfo() const; 344 FPClassTest getNoFPClass() const; 345 std::string getAsString(bool InAttrGrp) const; 346 Type *getAttributeType(Attribute::AttrKind Kind) const; 347 348 using iterator = const Attribute *; 349 begin()350 iterator begin() const { return getTrailingObjects(); } end()351 iterator end() const { return begin() + NumAttrs; } 352 Profile(FoldingSetNodeID & ID)353 void Profile(FoldingSetNodeID &ID) const { 354 Profile(ID, ArrayRef(begin(), end())); 355 } 356 Profile(FoldingSetNodeID & ID,ArrayRef<Attribute> AttrList)357 static void Profile(FoldingSetNodeID &ID, ArrayRef<Attribute> AttrList) { 358 for (const auto &Attr : AttrList) 359 Attr.Profile(ID); 360 } 361 }; 362 363 //===----------------------------------------------------------------------===// 364 /// \class 365 /// This class represents a set of attributes that apply to the function, 366 /// return type, and parameters. 367 class AttributeListImpl final 368 : public FoldingSetNode, 369 private TrailingObjects<AttributeListImpl, AttributeSet> { 370 friend class AttributeList; 371 friend TrailingObjects; 372 373 private: 374 unsigned NumAttrSets; ///< Number of entries in this set. 375 /// Available enum function attributes. 376 AttributeBitSet AvailableFunctionAttrs; 377 /// Union of enum attributes available at any index. 378 AttributeBitSet AvailableSomewhereAttrs; 379 380 public: 381 AttributeListImpl(ArrayRef<AttributeSet> Sets); 382 383 // AttributesSetImpt is uniqued, these should not be available. 384 AttributeListImpl(const AttributeListImpl &) = delete; 385 AttributeListImpl &operator=(const AttributeListImpl &) = delete; 386 387 /// Return true if the AttributeSet or the FunctionIndex has an 388 /// enum attribute of the given kind. hasFnAttribute(Attribute::AttrKind Kind)389 bool hasFnAttribute(Attribute::AttrKind Kind) const { 390 return AvailableFunctionAttrs.hasAttribute(Kind); 391 } 392 393 /// Return true if the specified attribute is set for at least one 394 /// parameter or for the return value. If Index is not nullptr, the index 395 /// of a parameter with the specified attribute is provided. 396 bool hasAttrSomewhere(Attribute::AttrKind Kind, 397 unsigned *Index = nullptr) const; 398 399 using iterator = const AttributeSet *; 400 begin()401 iterator begin() const { return getTrailingObjects(); } end()402 iterator end() const { return begin() + NumAttrSets; } 403 404 void Profile(FoldingSetNodeID &ID) const; 405 static void Profile(FoldingSetNodeID &ID, ArrayRef<AttributeSet> Nodes); 406 407 void dump() const; 408 }; 409 410 static_assert(std::is_trivially_destructible<AttributeListImpl>::value, 411 "AttributeListImpl should be trivially destructible"); 412 413 } // end namespace llvm 414 415 #endif // LLVM_LIB_IR_ATTRIBUTEIMPL_H 416