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 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 62 bool isEnumAttribute() const { return KindID == EnumAttrEntry; } 63 bool isIntAttribute() const { return KindID == IntAttrEntry; } 64 bool isStringAttribute() const { return KindID == StringAttrEntry; } 65 bool isTypeAttribute() const { return KindID == TypeAttrEntry; } 66 bool isConstantRangeAttribute() const { 67 return KindID == ConstantRangeAttrEntry; 68 } 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 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 110 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind) { 111 assert(Attribute::isEnumAttrKind(Kind) && "Expected enum attribute"); 112 ID.AddInteger(Kind); 113 } 114 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 122 static void Profile(FoldingSetNodeID &ID, StringRef Kind, StringRef Values) { 123 ID.AddString(Kind); 124 if (!Values.empty()) ID.AddString(Values); 125 } 126 127 static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, 128 Type *Ty) { 129 ID.AddInteger(Kind); 130 ID.AddPointer(Ty); 131 } 132 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 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: 165 EnumAttributeImpl(AttrEntryKind ID, Attribute::AttrKind Kind) 166 : AttributeImpl(ID), Kind(Kind) {} 167 168 public: 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 175 Attribute::AttrKind getEnumKind() const { return Kind; } 176 }; 177 178 class IntAttributeImpl : public EnumAttributeImpl { 179 uint64_t Val; 180 181 public: 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 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 size_t numTrailingObjects(OverloadToken<char>) const { 199 return KindSize + 1 + ValSize + 1; 200 } 201 202 public: 203 StringAttributeImpl(StringRef Kind, StringRef Val = StringRef()) 204 : AttributeImpl(StringAttrEntry), KindSize(Kind.size()), 205 ValSize(Val.size()) { 206 char *TrailingString = getTrailingObjects<char>(); 207 // Some users rely on zero-termination. 208 llvm::copy(Kind, TrailingString); 209 TrailingString[KindSize] = '\0'; 210 llvm::copy(Val, &TrailingString[KindSize + 1]); 211 TrailingString[KindSize + 1 + ValSize] = '\0'; 212 } 213 214 StringRef getStringKind() const { 215 return StringRef(getTrailingObjects<char>(), KindSize); 216 } 217 StringRef getStringValue() const { 218 return StringRef(getTrailingObjects<char>() + KindSize + 1, ValSize); 219 } 220 221 static size_t totalSizeToAlloc(StringRef Kind, StringRef Val) { 222 return TrailingObjects::totalSizeToAlloc<char>(Kind.size() + 1 + 223 Val.size() + 1); 224 } 225 }; 226 227 class TypeAttributeImpl : public EnumAttributeImpl { 228 Type *Ty; 229 230 public: 231 TypeAttributeImpl(Attribute::AttrKind Kind, Type *Ty) 232 : EnumAttributeImpl(TypeAttrEntry, Kind), Ty(Ty) {} 233 234 Type *getTypeValue() const { return Ty; } 235 }; 236 237 class ConstantRangeAttributeImpl : public EnumAttributeImpl { 238 ConstantRange CR; 239 240 public: 241 ConstantRangeAttributeImpl(Attribute::AttrKind Kind, const ConstantRange &CR) 242 : EnumAttributeImpl(ConstantRangeAttrEntry, Kind), CR(CR) {} 243 244 const ConstantRange &getConstantRangeValue() const { return CR; } 245 }; 246 247 class ConstantRangeListAttributeImpl final 248 : public EnumAttributeImpl, 249 private TrailingObjects<ConstantRangeListAttributeImpl, ConstantRange> { 250 friend TrailingObjects; 251 252 unsigned Size; 253 size_t numTrailingObjects(OverloadToken<ConstantRange>) const { return Size; } 254 255 public: 256 ConstantRangeListAttributeImpl(Attribute::AttrKind Kind, 257 ArrayRef<ConstantRange> Val) 258 : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), Size(Val.size()) { 259 assert(Size > 0); 260 ConstantRange *TrailingCR = getTrailingObjects<ConstantRange>(); 261 std::uninitialized_copy(Val.begin(), Val.end(), TrailingCR); 262 } 263 264 ~ConstantRangeListAttributeImpl() { 265 ConstantRange *TrailingCR = getTrailingObjects<ConstantRange>(); 266 for (unsigned I = 0; I != Size; ++I) 267 TrailingCR[I].~ConstantRange(); 268 } 269 270 ArrayRef<ConstantRange> getConstantRangeListValue() const { 271 return ArrayRef(getTrailingObjects<ConstantRange>(), Size); 272 } 273 274 static size_t totalSizeToAlloc(ArrayRef<ConstantRange> Val) { 275 return TrailingObjects::totalSizeToAlloc<ConstantRange>(Val.size()); 276 } 277 }; 278 279 class AttributeBitSet { 280 /// Bitset with a bit for each available attribute Attribute::AttrKind. 281 uint8_t AvailableAttrs[16] = {}; 282 static_assert(Attribute::EndAttrKinds <= sizeof(AvailableAttrs) * CHAR_BIT, 283 "Too many attributes"); 284 285 public: 286 bool hasAttribute(Attribute::AttrKind Kind) const { 287 return AvailableAttrs[Kind / 8] & (1 << (Kind % 8)); 288 } 289 290 void addAttribute(Attribute::AttrKind Kind) { 291 AvailableAttrs[Kind / 8] |= 1 << (Kind % 8); 292 } 293 }; 294 295 //===----------------------------------------------------------------------===// 296 /// \class 297 /// This class represents a group of attributes that apply to one 298 /// element: function, return type, or parameter. 299 class AttributeSetNode final 300 : public FoldingSetNode, 301 private TrailingObjects<AttributeSetNode, Attribute> { 302 friend TrailingObjects; 303 304 unsigned NumAttrs; ///< Number of attributes in this node. 305 AttributeBitSet AvailableAttrs; ///< Available enum attributes. 306 307 DenseMap<StringRef, Attribute> StringAttrs; 308 309 AttributeSetNode(ArrayRef<Attribute> Attrs); 310 311 static AttributeSetNode *getSorted(LLVMContext &C, 312 ArrayRef<Attribute> SortedAttrs); 313 std::optional<Attribute> findEnumAttribute(Attribute::AttrKind Kind) const; 314 315 public: 316 // AttributesSetNode is uniqued, these should not be available. 317 AttributeSetNode(const AttributeSetNode &) = delete; 318 AttributeSetNode &operator=(const AttributeSetNode &) = delete; 319 320 void operator delete(void *p) { ::operator delete(p); } 321 322 static AttributeSetNode *get(LLVMContext &C, const AttrBuilder &B); 323 324 static AttributeSetNode *get(LLVMContext &C, ArrayRef<Attribute> Attrs); 325 326 /// Return the number of attributes this AttributeList contains. 327 unsigned getNumAttributes() const { return NumAttrs; } 328 329 bool hasAttribute(Attribute::AttrKind Kind) const { 330 return AvailableAttrs.hasAttribute(Kind); 331 } 332 bool hasAttribute(StringRef Kind) const; 333 bool hasAttributes() const { return NumAttrs != 0; } 334 335 Attribute getAttribute(Attribute::AttrKind Kind) const; 336 Attribute getAttribute(StringRef Kind) const; 337 338 MaybeAlign getAlignment() const; 339 MaybeAlign getStackAlignment() const; 340 uint64_t getDereferenceableBytes() const; 341 uint64_t getDereferenceableOrNullBytes() const; 342 std::optional<std::pair<unsigned, std::optional<unsigned>>> getAllocSizeArgs() 343 const; 344 unsigned getVScaleRangeMin() const; 345 std::optional<unsigned> getVScaleRangeMax() const; 346 UWTableKind getUWTableKind() const; 347 AllocFnKind getAllocKind() const; 348 MemoryEffects getMemoryEffects() const; 349 CaptureInfo getCaptureInfo() const; 350 FPClassTest getNoFPClass() const; 351 std::string getAsString(bool InAttrGrp) const; 352 Type *getAttributeType(Attribute::AttrKind Kind) const; 353 354 using iterator = const Attribute *; 355 356 iterator begin() const { return getTrailingObjects<Attribute>(); } 357 iterator end() const { return begin() + NumAttrs; } 358 359 void Profile(FoldingSetNodeID &ID) const { 360 Profile(ID, ArrayRef(begin(), end())); 361 } 362 363 static void Profile(FoldingSetNodeID &ID, ArrayRef<Attribute> AttrList) { 364 for (const auto &Attr : AttrList) 365 Attr.Profile(ID); 366 } 367 }; 368 369 //===----------------------------------------------------------------------===// 370 /// \class 371 /// This class represents a set of attributes that apply to the function, 372 /// return type, and parameters. 373 class AttributeListImpl final 374 : public FoldingSetNode, 375 private TrailingObjects<AttributeListImpl, AttributeSet> { 376 friend class AttributeList; 377 friend TrailingObjects; 378 379 private: 380 unsigned NumAttrSets; ///< Number of entries in this set. 381 /// Available enum function attributes. 382 AttributeBitSet AvailableFunctionAttrs; 383 /// Union of enum attributes available at any index. 384 AttributeBitSet AvailableSomewhereAttrs; 385 386 // Helper fn for TrailingObjects class. 387 size_t numTrailingObjects(OverloadToken<AttributeSet>) { return NumAttrSets; } 388 389 public: 390 AttributeListImpl(ArrayRef<AttributeSet> Sets); 391 392 // AttributesSetImpt is uniqued, these should not be available. 393 AttributeListImpl(const AttributeListImpl &) = delete; 394 AttributeListImpl &operator=(const AttributeListImpl &) = delete; 395 396 /// Return true if the AttributeSet or the FunctionIndex has an 397 /// enum attribute of the given kind. 398 bool hasFnAttribute(Attribute::AttrKind Kind) const { 399 return AvailableFunctionAttrs.hasAttribute(Kind); 400 } 401 402 /// Return true if the specified attribute is set for at least one 403 /// parameter or for the return value. If Index is not nullptr, the index 404 /// of a parameter with the specified attribute is provided. 405 bool hasAttrSomewhere(Attribute::AttrKind Kind, 406 unsigned *Index = nullptr) const; 407 408 using iterator = const AttributeSet *; 409 410 iterator begin() const { return getTrailingObjects<AttributeSet>(); } 411 iterator end() const { return begin() + NumAttrSets; } 412 413 void Profile(FoldingSetNodeID &ID) const; 414 static void Profile(FoldingSetNodeID &ID, ArrayRef<AttributeSet> Nodes); 415 416 void dump() const; 417 }; 418 419 static_assert(std::is_trivially_destructible<AttributeListImpl>::value, 420 "AttributeListImpl should be trivially destructible"); 421 422 } // end namespace llvm 423 424 #endif // LLVM_LIB_IR_ATTRIBUTEIMPL_H 425