| 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, Kind: getKindAsEnum()); |
| 98 | else if (isIntAttribute()) |
| 99 | Profile(ID, Kind: getKindAsEnum(), Val: getValueAsInt()); |
| 100 | else if (isStringAttribute()) |
| 101 | Profile(ID, Kind: getKindAsString(), Values: getValueAsString()); |
| 102 | else if (isTypeAttribute()) |
| 103 | Profile(ID, Kind: getKindAsEnum(), Ty: getValueAsType()); |
| 104 | else if (isConstantRangeAttribute()) |
| 105 | Profile(ID, Kind: getKindAsEnum(), CR: getValueAsConstantRange()); |
| 106 | else |
| 107 | Profile(ID, Kind: getKindAsEnum(), Val: getValueAsConstantRangeList()); |
| 108 | } |
| 109 | |
| 110 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind) { |
| 111 | assert(Attribute::isEnumAttrKind(Kind) && "Expected enum attribute" ); |
| 112 | ID.AddInteger(I: 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(I: Kind); |
| 119 | ID.AddInteger(I: Val); |
| 120 | } |
| 121 | |
| 122 | static void Profile(FoldingSetNodeID &ID, StringRef Kind, StringRef Values) { |
| 123 | ID.AddString(String: Kind); |
| 124 | if (!Values.empty()) ID.AddString(String: Values); |
| 125 | } |
| 126 | |
| 127 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, |
| 128 | Type *Ty) { |
| 129 | ID.AddInteger(I: Kind); |
| 130 | ID.AddPointer(Ptr: Ty); |
| 131 | } |
| 132 | |
| 133 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, |
| 134 | const ConstantRange &CR) { |
| 135 | ID.AddInteger(I: Kind); |
| 136 | CR.getLower().Profile(id&: ID); |
| 137 | CR.getUpper().Profile(id&: ID); |
| 138 | } |
| 139 | |
| 140 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, |
| 141 | ArrayRef<ConstantRange> Val) { |
| 142 | ID.AddInteger(I: Kind); |
| 143 | ID.AddInteger(I: Val.size()); |
| 144 | for (auto &CR : Val) { |
| 145 | CR.getLower().Profile(id&: ID); |
| 146 | CR.getUpper().Profile(id&: 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 | |
| 199 | public: |
| 200 | StringAttributeImpl(StringRef Kind, StringRef Val = StringRef()) |
| 201 | : AttributeImpl(StringAttrEntry), KindSize(Kind.size()), |
| 202 | ValSize(Val.size()) { |
| 203 | char *TrailingString = getTrailingObjects(); |
| 204 | // Some users rely on zero-termination. |
| 205 | llvm::copy(Range&: Kind, Out: TrailingString); |
| 206 | TrailingString[KindSize] = '\0'; |
| 207 | llvm::copy(Range&: Val, Out: &TrailingString[KindSize + 1]); |
| 208 | TrailingString[KindSize + 1 + ValSize] = '\0'; |
| 209 | } |
| 210 | |
| 211 | StringRef getStringKind() const { |
| 212 | return StringRef(getTrailingObjects(), KindSize); |
| 213 | } |
| 214 | StringRef getStringValue() const { |
| 215 | return StringRef(getTrailingObjects() + KindSize + 1, ValSize); |
| 216 | } |
| 217 | |
| 218 | static size_t totalSizeToAlloc(StringRef Kind, StringRef Val) { |
| 219 | return TrailingObjects::totalSizeToAlloc<char>(Counts: Kind.size() + 1 + |
| 220 | Val.size() + 1); |
| 221 | } |
| 222 | }; |
| 223 | |
| 224 | class TypeAttributeImpl : public EnumAttributeImpl { |
| 225 | Type *Ty; |
| 226 | |
| 227 | public: |
| 228 | TypeAttributeImpl(Attribute::AttrKind Kind, Type *Ty) |
| 229 | : EnumAttributeImpl(TypeAttrEntry, Kind), Ty(Ty) {} |
| 230 | |
| 231 | Type *getTypeValue() const { return Ty; } |
| 232 | }; |
| 233 | |
| 234 | class ConstantRangeAttributeImpl : public EnumAttributeImpl { |
| 235 | ConstantRange CR; |
| 236 | |
| 237 | public: |
| 238 | ConstantRangeAttributeImpl(Attribute::AttrKind Kind, const ConstantRange &CR) |
| 239 | : EnumAttributeImpl(ConstantRangeAttrEntry, Kind), CR(CR) {} |
| 240 | |
| 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: |
| 252 | ConstantRangeListAttributeImpl(Attribute::AttrKind Kind, |
| 253 | ArrayRef<ConstantRange> Val) |
| 254 | : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), Size(Val.size()) { |
| 255 | assert(Size > 0); |
| 256 | llvm::uninitialized_copy(Src&: Val, Dst: getTrailingObjects()); |
| 257 | } |
| 258 | |
| 259 | ~ConstantRangeListAttributeImpl() { |
| 260 | for (ConstantRange &CR : getTrailingObjects(N: Size)) |
| 261 | CR.~ConstantRange(); |
| 262 | } |
| 263 | |
| 264 | ArrayRef<ConstantRange> getConstantRangeListValue() const { |
| 265 | return getTrailingObjects(N: Size); |
| 266 | } |
| 267 | |
| 268 | static size_t totalSizeToAlloc(ArrayRef<ConstantRange> Val) { |
| 269 | return TrailingObjects::totalSizeToAlloc<ConstantRange>(Counts: 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: |
| 280 | bool hasAttribute(Attribute::AttrKind Kind) const { |
| 281 | return AvailableAttrs[Kind / 8] & (1 << (Kind % 8)); |
| 282 | } |
| 283 | |
| 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 | |
| 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. |
| 321 | unsigned getNumAttributes() const { return NumAttrs; } |
| 322 | |
| 323 | bool hasAttribute(Attribute::AttrKind Kind) const { |
| 324 | return AvailableAttrs.hasAttribute(Kind); |
| 325 | } |
| 326 | bool hasAttribute(StringRef Kind) const; |
| 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 | |
| 350 | iterator begin() const { return getTrailingObjects(); } |
| 351 | iterator end() const { return begin() + NumAttrs; } |
| 352 | |
| 353 | void Profile(FoldingSetNodeID &ID) const { |
| 354 | Profile(ID, AttrList: ArrayRef(begin(), end())); |
| 355 | } |
| 356 | |
| 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. |
| 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 | |
| 401 | iterator begin() const { return getTrailingObjects(); } |
| 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 | |