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 when sorting the attributes. |
90 | bool operator<(const AttributeImpl &AI) const; |
91 | |
92 | void Profile(FoldingSetNodeID &ID) const { |
93 | if (isEnumAttribute()) |
94 | Profile(ID, Kind: getKindAsEnum()); |
95 | else if (isIntAttribute()) |
96 | Profile(ID, Kind: getKindAsEnum(), Val: getValueAsInt()); |
97 | else if (isStringAttribute()) |
98 | Profile(ID, Kind: getKindAsString(), Values: getValueAsString()); |
99 | else if (isTypeAttribute()) |
100 | Profile(ID, Kind: getKindAsEnum(), Ty: getValueAsType()); |
101 | else if (isConstantRangeAttribute()) |
102 | Profile(ID, Kind: getKindAsEnum(), CR: getValueAsConstantRange()); |
103 | else |
104 | Profile(ID, Kind: getKindAsEnum(), Val: getValueAsConstantRangeList()); |
105 | } |
106 | |
107 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind) { |
108 | assert(Attribute::isEnumAttrKind(Kind) && "Expected enum attribute" ); |
109 | ID.AddInteger(I: Kind); |
110 | } |
111 | |
112 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, |
113 | uint64_t Val) { |
114 | assert(Attribute::isIntAttrKind(Kind) && "Expected int attribute" ); |
115 | ID.AddInteger(I: Kind); |
116 | ID.AddInteger(I: Val); |
117 | } |
118 | |
119 | static void Profile(FoldingSetNodeID &ID, StringRef Kind, StringRef Values) { |
120 | ID.AddString(String: Kind); |
121 | if (!Values.empty()) ID.AddString(String: Values); |
122 | } |
123 | |
124 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, |
125 | Type *Ty) { |
126 | ID.AddInteger(I: Kind); |
127 | ID.AddPointer(Ptr: Ty); |
128 | } |
129 | |
130 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, |
131 | const ConstantRange &CR) { |
132 | ID.AddInteger(I: Kind); |
133 | CR.getLower().Profile(id&: ID); |
134 | CR.getUpper().Profile(id&: ID); |
135 | } |
136 | |
137 | static void Profile(FoldingSetNodeID &ID, Attribute::AttrKind Kind, |
138 | ArrayRef<ConstantRange> Val) { |
139 | ID.AddInteger(I: Kind); |
140 | ID.AddInteger(I: Val.size()); |
141 | for (auto &CR : Val) { |
142 | CR.getLower().Profile(id&: ID); |
143 | CR.getUpper().Profile(id&: 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: |
162 | EnumAttributeImpl(AttrEntryKind ID, Attribute::AttrKind Kind) |
163 | : AttributeImpl(ID), Kind(Kind) {} |
164 | |
165 | public: |
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 | |
172 | Attribute::AttrKind getEnumKind() const { return Kind; } |
173 | }; |
174 | |
175 | class IntAttributeImpl : public EnumAttributeImpl { |
176 | uint64_t Val; |
177 | |
178 | public: |
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 | |
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; |
195 | size_t numTrailingObjects(OverloadToken<char>) const { |
196 | return KindSize + 1 + ValSize + 1; |
197 | } |
198 | |
199 | public: |
200 | StringAttributeImpl(StringRef Kind, StringRef Val = StringRef()) |
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(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<char>(), KindSize); |
213 | } |
214 | StringRef getStringValue() const { |
215 | return StringRef(getTrailingObjects<char>() + 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 | size_t numTrailingObjects(OverloadToken<ConstantRange>) const { return Size; } |
251 | |
252 | public: |
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(first: Val.begin(), last: Val.end(), result: TrailingCR); |
259 | } |
260 | |
261 | ~ConstantRangeListAttributeImpl() { |
262 | ConstantRange *TrailingCR = getTrailingObjects<ConstantRange>(); |
263 | for (unsigned I = 0; I != Size; ++I) |
264 | TrailingCR[I].~ConstantRange(); |
265 | } |
266 | |
267 | ArrayRef<ConstantRange> getConstantRangeListValue() const { |
268 | return ArrayRef(getTrailingObjects<ConstantRange>(), Size); |
269 | } |
270 | |
271 | static size_t totalSizeToAlloc(ArrayRef<ConstantRange> Val) { |
272 | return TrailingObjects::totalSizeToAlloc<ConstantRange>(Counts: 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: |
283 | bool hasAttribute(Attribute::AttrKind Kind) const { |
284 | return AvailableAttrs[Kind / 8] & (1 << (Kind % 8)); |
285 | } |
286 | |
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 | |
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. |
324 | unsigned getNumAttributes() const { return NumAttrs; } |
325 | |
326 | bool hasAttribute(Attribute::AttrKind Kind) const { |
327 | return AvailableAttrs.hasAttribute(Kind); |
328 | } |
329 | bool hasAttribute(StringRef Kind) const; |
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 | |
352 | iterator begin() const { return getTrailingObjects<Attribute>(); } |
353 | iterator end() const { return begin() + NumAttrs; } |
354 | |
355 | void Profile(FoldingSetNodeID &ID) const { |
356 | Profile(ID, AttrList: ArrayRef(begin(), end())); |
357 | } |
358 | |
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. |
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. |
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 | |
406 | iterator begin() const { return getTrailingObjects<AttributeSet>(); } |
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 | |