| 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 | /// Only the ConstantRange kinds are uniqued by profile; every other kind |
| 96 | /// has a pool with a typed key. |
| 97 | void Profile(FoldingSetNodeID &ID) const { |
| 98 | if (isConstantRangeAttribute()) |
| 99 | Profile(ID, Kind: getKindAsEnum(), CR: getValueAsConstantRange()); |
| 100 | else |
| 101 | Profile(ID, Kind: getKindAsEnum(), Val: getValueAsConstantRangeList()); |
| 102 | } |
| 103 | |
| 104 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, |
| 105 | const ConstantRange &CR) { |
| 106 | ID.AddInteger(I: Kind); |
| 107 | CR.getLower().Profile(id&: ID); |
| 108 | CR.getUpper().Profile(id&: ID); |
| 109 | } |
| 110 | |
| 111 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, |
| 112 | ArrayRef<ConstantRange> Val) { |
| 113 | ID.AddInteger(I: Kind); |
| 114 | ID.AddInteger(I: Val.size()); |
| 115 | for (auto &CR : Val) { |
| 116 | CR.getLower().Profile(id&: ID); |
| 117 | CR.getUpper().Profile(id&: ID); |
| 118 | } |
| 119 | } |
| 120 | }; |
| 121 | |
| 122 | static_assert(std::is_trivially_destructible<AttributeImpl>::value, |
| 123 | "AttributeImpl should be trivially destructible" ); |
| 124 | |
| 125 | //===----------------------------------------------------------------------===// |
| 126 | /// \class |
| 127 | /// A set of classes that contain the value of the |
| 128 | /// attribute object. There are three main categories: enum attribute entries, |
| 129 | /// represented by Attribute::AttrKind; alignment attribute entries; and string |
| 130 | /// attribute enties, which are for target-dependent attributes. |
| 131 | |
| 132 | class EnumAttributeImpl : public AttributeImpl { |
| 133 | Attribute::AttrKind Kind; |
| 134 | |
| 135 | protected: |
| 136 | EnumAttributeImpl(AttrEntryKind ID, Attribute::AttrKind Kind) |
| 137 | : AttributeImpl(ID), Kind(Kind) {} |
| 138 | |
| 139 | public: |
| 140 | EnumAttributeImpl(Attribute::AttrKind Kind) |
| 141 | : AttributeImpl(EnumAttrEntry), Kind(Kind) { |
| 142 | assert(Kind != Attribute::AttrKind::None && |
| 143 | "Can't create a None attribute!" ); |
| 144 | } |
| 145 | |
| 146 | Attribute::AttrKind getEnumKind() const { return Kind; } |
| 147 | }; |
| 148 | |
| 149 | class IntAttributeImpl : public EnumAttributeImpl { |
| 150 | uint64_t Val; |
| 151 | |
| 152 | public: |
| 153 | IntAttributeImpl(Attribute::AttrKind Kind, uint64_t Val) |
| 154 | : EnumAttributeImpl(IntAttrEntry, Kind), Val(Val) { |
| 155 | assert(Attribute::isIntAttrKind(Kind) && |
| 156 | "Wrong kind for int attribute!" ); |
| 157 | } |
| 158 | |
| 159 | uint64_t getValue() const { return Val; } |
| 160 | |
| 161 | std::pair<unsigned, uint64_t> getKey() const { return {getEnumKind(), Val}; } |
| 162 | }; |
| 163 | |
| 164 | class StringAttributeImpl final |
| 165 | : public AttributeImpl, |
| 166 | private TrailingObjects<StringAttributeImpl, char> { |
| 167 | friend TrailingObjects; |
| 168 | |
| 169 | unsigned KindSize; |
| 170 | unsigned ValSize; |
| 171 | |
| 172 | public: |
| 173 | StringAttributeImpl(StringRef Kind, StringRef Val = StringRef()) |
| 174 | : AttributeImpl(StringAttrEntry), KindSize(Kind.size()), |
| 175 | ValSize(Val.size()) { |
| 176 | char *TrailingString = getTrailingObjects(); |
| 177 | // Some users rely on zero-termination. |
| 178 | llvm::copy(Range&: Kind, Out: TrailingString); |
| 179 | TrailingString[KindSize] = '\0'; |
| 180 | llvm::copy(Range&: Val, Out: &TrailingString[KindSize + 1]); |
| 181 | TrailingString[KindSize + 1 + ValSize] = '\0'; |
| 182 | } |
| 183 | |
| 184 | StringRef getStringKind() const { |
| 185 | return StringRef(getTrailingObjects(), KindSize); |
| 186 | } |
| 187 | StringRef getStringValue() const { |
| 188 | return StringRef(getTrailingObjects() + KindSize + 1, ValSize); |
| 189 | } |
| 190 | |
| 191 | std::pair<StringRef, StringRef> getKey() const { |
| 192 | return {getStringKind(), getStringValue()}; |
| 193 | } |
| 194 | |
| 195 | static size_t totalSizeToAlloc(StringRef Kind, StringRef Val) { |
| 196 | return TrailingObjects::totalSizeToAlloc<char>(Counts: Kind.size() + 1 + |
| 197 | Val.size() + 1); |
| 198 | } |
| 199 | }; |
| 200 | |
| 201 | class TypeAttributeImpl : public EnumAttributeImpl { |
| 202 | Type *Ty; |
| 203 | |
| 204 | public: |
| 205 | TypeAttributeImpl(Attribute::AttrKind Kind, Type *Ty) |
| 206 | : EnumAttributeImpl(TypeAttrEntry, Kind), Ty(Ty) {} |
| 207 | |
| 208 | Type *getTypeValue() const { return Ty; } |
| 209 | |
| 210 | std::pair<unsigned, Type *> getKey() const { return {getEnumKind(), Ty}; } |
| 211 | }; |
| 212 | |
| 213 | class ConstantRangeAttributeImpl : public EnumAttributeImpl { |
| 214 | ConstantRange CR; |
| 215 | |
| 216 | public: |
| 217 | ConstantRangeAttributeImpl(Attribute::AttrKind Kind, const ConstantRange &CR) |
| 218 | : EnumAttributeImpl(ConstantRangeAttrEntry, Kind), CR(CR) {} |
| 219 | |
| 220 | const ConstantRange &getConstantRangeValue() const { return CR; } |
| 221 | }; |
| 222 | |
| 223 | class ConstantRangeListAttributeImpl final |
| 224 | : public EnumAttributeImpl, |
| 225 | private TrailingObjects<ConstantRangeListAttributeImpl, ConstantRange> { |
| 226 | friend TrailingObjects; |
| 227 | |
| 228 | unsigned Size; |
| 229 | |
| 230 | public: |
| 231 | ConstantRangeListAttributeImpl(Attribute::AttrKind Kind, |
| 232 | ArrayRef<ConstantRange> Val) |
| 233 | : EnumAttributeImpl(ConstantRangeListAttrEntry, Kind), Size(Val.size()) { |
| 234 | assert(Size > 0); |
| 235 | llvm::uninitialized_copy(Src&: Val, Dst: getTrailingObjects()); |
| 236 | } |
| 237 | |
| 238 | ~ConstantRangeListAttributeImpl() { |
| 239 | for (ConstantRange &CR : getTrailingObjects(N: Size)) |
| 240 | CR.~ConstantRange(); |
| 241 | } |
| 242 | |
| 243 | ArrayRef<ConstantRange> getConstantRangeListValue() const { |
| 244 | return getTrailingObjects(N: Size); |
| 245 | } |
| 246 | |
| 247 | static size_t totalSizeToAlloc(ArrayRef<ConstantRange> Val) { |
| 248 | return TrailingObjects::totalSizeToAlloc<ConstantRange>(Counts: Val.size()); |
| 249 | } |
| 250 | }; |
| 251 | |
| 252 | class AttributeBitSet { |
| 253 | /// Bitset with a bit for each available attribute Attribute::AttrKind. |
| 254 | uint8_t AvailableAttrs[16] = {}; |
| 255 | static_assert(Attribute::EndAttrKinds <= sizeof(AvailableAttrs) * CHAR_BIT, |
| 256 | "Too many attributes" ); |
| 257 | |
| 258 | public: |
| 259 | bool hasAttribute(Attribute::AttrKind Kind) const { |
| 260 | return AvailableAttrs[Kind / 8] & (1 << (Kind % 8)); |
| 261 | } |
| 262 | |
| 263 | void addAttribute(Attribute::AttrKind Kind) { |
| 264 | AvailableAttrs[Kind / 8] |= 1 << (Kind % 8); |
| 265 | } |
| 266 | }; |
| 267 | |
| 268 | //===----------------------------------------------------------------------===// |
| 269 | /// \class |
| 270 | /// This class represents a group of attributes that apply to one |
| 271 | /// element: function, return type, or parameter. |
| 272 | class AttributeSetNode final |
| 273 | : public FoldingSetNode, |
| 274 | private TrailingObjects<AttributeSetNode, Attribute> { |
| 275 | friend TrailingObjects; |
| 276 | |
| 277 | unsigned NumAttrs; ///< Number of attributes in this node. |
| 278 | AttributeBitSet AvailableAttrs; ///< Available enum attributes. |
| 279 | |
| 280 | DenseMap<StringRef, Attribute> StringAttrs; |
| 281 | |
| 282 | AttributeSetNode(ArrayRef<Attribute> Attrs); |
| 283 | |
| 284 | static AttributeSetNode *getSorted(LLVMContext &C, |
| 285 | ArrayRef<Attribute> SortedAttrs); |
| 286 | std::optional<Attribute> findEnumAttribute(Attribute::AttrKind Kind) const; |
| 287 | |
| 288 | public: |
| 289 | // AttributesSetNode is uniqued, these should not be available. |
| 290 | AttributeSetNode(const AttributeSetNode &) = delete; |
| 291 | AttributeSetNode &operator=(const AttributeSetNode &) = delete; |
| 292 | |
| 293 | void operator delete(void *p) { ::operator delete(p); } |
| 294 | |
| 295 | static AttributeSetNode *get(LLVMContext &C, const AttrBuilder &B); |
| 296 | |
| 297 | static AttributeSetNode *get(LLVMContext &C, ArrayRef<Attribute> Attrs); |
| 298 | |
| 299 | /// Return the number of attributes this AttributeList contains. |
| 300 | unsigned getNumAttributes() const { return NumAttrs; } |
| 301 | |
| 302 | bool hasAttribute(Attribute::AttrKind Kind) const { |
| 303 | return AvailableAttrs.hasAttribute(Kind); |
| 304 | } |
| 305 | bool hasAttribute(StringRef Kind) const; |
| 306 | bool hasAttributes() const { return NumAttrs != 0; } |
| 307 | |
| 308 | Attribute getAttribute(Attribute::AttrKind Kind) const; |
| 309 | Attribute getAttribute(StringRef Kind) const; |
| 310 | |
| 311 | MaybeAlign getAlignment() const; |
| 312 | MaybeAlign getStackAlignment() const; |
| 313 | uint64_t getDereferenceableBytes() const; |
| 314 | DeadOnReturnInfo getDeadOnReturnInfo() const; |
| 315 | uint64_t getDereferenceableOrNullBytes() const; |
| 316 | std::optional<std::pair<unsigned, std::optional<unsigned>>> getAllocSizeArgs() |
| 317 | const; |
| 318 | unsigned getVScaleRangeMin() const; |
| 319 | std::optional<unsigned> getVScaleRangeMax() const; |
| 320 | UWTableKind getUWTableKind() const; |
| 321 | AllocFnKind getAllocKind() const; |
| 322 | MemoryEffects getMemoryEffects() const; |
| 323 | CaptureInfo getCaptureInfo() const; |
| 324 | FPClassTest getNoFPClass() const; |
| 325 | std::string getAsString(bool InAttrGrp) const; |
| 326 | Type *getAttributeType(Attribute::AttrKind Kind) const; |
| 327 | |
| 328 | using iterator = const Attribute *; |
| 329 | |
| 330 | iterator begin() const { return getTrailingObjects(); } |
| 331 | iterator end() const { return begin() + NumAttrs; } |
| 332 | |
| 333 | ArrayRef<Attribute> getKey() const { return getTrailingObjects(N: NumAttrs); } |
| 334 | }; |
| 335 | |
| 336 | //===----------------------------------------------------------------------===// |
| 337 | /// \class |
| 338 | /// This class represents a set of attributes that apply to the function, |
| 339 | /// return type, and parameters. |
| 340 | class AttributeListImpl final |
| 341 | : public FoldingSetNode, |
| 342 | private TrailingObjects<AttributeListImpl, AttributeSet> { |
| 343 | friend class AttributeList; |
| 344 | friend TrailingObjects; |
| 345 | |
| 346 | private: |
| 347 | unsigned NumAttrSets; ///< Number of entries in this set. |
| 348 | /// Available enum function attributes. |
| 349 | AttributeBitSet AvailableFunctionAttrs; |
| 350 | /// Union of enum attributes available at any index. |
| 351 | AttributeBitSet AvailableSomewhereAttrs; |
| 352 | |
| 353 | public: |
| 354 | AttributeListImpl(ArrayRef<AttributeSet> Sets); |
| 355 | |
| 356 | // AttributesSetImpt is uniqued, these should not be available. |
| 357 | AttributeListImpl(const AttributeListImpl &) = delete; |
| 358 | AttributeListImpl &operator=(const AttributeListImpl &) = delete; |
| 359 | |
| 360 | /// Return true if the AttributeSet or the FunctionIndex has an |
| 361 | /// enum attribute of the given kind. |
| 362 | bool hasFnAttribute(Attribute::AttrKind Kind) const { |
| 363 | return AvailableFunctionAttrs.hasAttribute(Kind); |
| 364 | } |
| 365 | |
| 366 | /// Return true if the specified attribute is set for at least one |
| 367 | /// parameter or for the return value. If Index is not nullptr, the index |
| 368 | /// of a parameter with the specified attribute is provided. |
| 369 | bool hasAttrSomewhere(Attribute::AttrKind Kind, |
| 370 | unsigned *Index = nullptr) const; |
| 371 | |
| 372 | using iterator = const AttributeSet *; |
| 373 | |
| 374 | iterator begin() const { return getTrailingObjects(); } |
| 375 | iterator end() const { return begin() + NumAttrSets; } |
| 376 | |
| 377 | ArrayRef<AttributeSet> getKey() const { |
| 378 | return getTrailingObjects(N: NumAttrSets); |
| 379 | } |
| 380 | |
| 381 | void dump() const; |
| 382 | }; |
| 383 | |
| 384 | static_assert(std::is_trivially_destructible<AttributeListImpl>::value, |
| 385 | "AttributeListImpl should be trivially destructible" ); |
| 386 | |
| 387 | } // end namespace llvm |
| 388 | |
| 389 | #endif // LLVM_LIB_IR_ATTRIBUTEIMPL_H |
| 390 | |