/src/llvm-project/llvm/lib/IR/Attributes.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- Attributes.cpp - Implement AttributesList --------------------------===// |
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 implements the Attribute, AttributeImpl, AttrBuilder, |
11 | | // AttributeListImpl, and AttributeList classes. |
12 | | // |
13 | | //===----------------------------------------------------------------------===// |
14 | | |
15 | | #include "llvm/IR/Attributes.h" |
16 | | #include "AttributeImpl.h" |
17 | | #include "LLVMContextImpl.h" |
18 | | #include "llvm/ADT/ArrayRef.h" |
19 | | #include "llvm/ADT/FoldingSet.h" |
20 | | #include "llvm/ADT/STLExtras.h" |
21 | | #include "llvm/ADT/SmallVector.h" |
22 | | #include "llvm/ADT/StringExtras.h" |
23 | | #include "llvm/ADT/StringRef.h" |
24 | | #include "llvm/ADT/StringSwitch.h" |
25 | | #include "llvm/Config/llvm-config.h" |
26 | | #include "llvm/IR/AttributeMask.h" |
27 | | #include "llvm/IR/Function.h" |
28 | | #include "llvm/IR/LLVMContext.h" |
29 | | #include "llvm/IR/Type.h" |
30 | | #include "llvm/Support/Compiler.h" |
31 | | #include "llvm/Support/ErrorHandling.h" |
32 | | #include "llvm/Support/ModRef.h" |
33 | | #include "llvm/Support/raw_ostream.h" |
34 | | #include <algorithm> |
35 | | #include <cassert> |
36 | | #include <cstddef> |
37 | | #include <cstdint> |
38 | | #include <limits> |
39 | | #include <optional> |
40 | | #include <string> |
41 | | #include <tuple> |
42 | | #include <utility> |
43 | | |
44 | | using namespace llvm; |
45 | | |
46 | | //===----------------------------------------------------------------------===// |
47 | | // Attribute Construction Methods |
48 | | //===----------------------------------------------------------------------===// |
49 | | |
50 | | // allocsize has two integer arguments, but because they're both 32 bits, we can |
51 | | // pack them into one 64-bit value, at the cost of making said value |
52 | | // nonsensical. |
53 | | // |
54 | | // In order to do this, we need to reserve one value of the second (optional) |
55 | | // allocsize argument to signify "not present." |
56 | | static const unsigned AllocSizeNumElemsNotPresent = -1; |
57 | | |
58 | | static uint64_t packAllocSizeArgs(unsigned ElemSizeArg, |
59 | 6 | const std::optional<unsigned> &NumElemsArg) { |
60 | 6 | assert((!NumElemsArg || *NumElemsArg != AllocSizeNumElemsNotPresent) && |
61 | 6 | "Attempting to pack a reserved value"); |
62 | | |
63 | 0 | return uint64_t(ElemSizeArg) << 32 | |
64 | 6 | NumElemsArg.value_or(AllocSizeNumElemsNotPresent); |
65 | 6 | } |
66 | | |
67 | | static std::pair<unsigned, std::optional<unsigned>> |
68 | 2.33k | unpackAllocSizeArgs(uint64_t Num) { |
69 | 2.33k | unsigned NumElems = Num & std::numeric_limits<unsigned>::max(); |
70 | 2.33k | unsigned ElemSizeArg = Num >> 32; |
71 | | |
72 | 2.33k | std::optional<unsigned> NumElemsArg; |
73 | 2.33k | if (NumElems != AllocSizeNumElemsNotPresent) |
74 | 877 | NumElemsArg = NumElems; |
75 | 2.33k | return std::make_pair(ElemSizeArg, NumElemsArg); |
76 | 2.33k | } |
77 | | |
78 | | static uint64_t packVScaleRangeArgs(unsigned MinValue, |
79 | 0 | std::optional<unsigned> MaxValue) { |
80 | 0 | return uint64_t(MinValue) << 32 | MaxValue.value_or(0); |
81 | 0 | } |
82 | | |
83 | | static std::pair<unsigned, std::optional<unsigned>> |
84 | 0 | unpackVScaleRangeArgs(uint64_t Value) { |
85 | 0 | unsigned MaxValue = Value & std::numeric_limits<unsigned>::max(); |
86 | 0 | unsigned MinValue = Value >> 32; |
87 | |
|
88 | 0 | return std::make_pair(MinValue, |
89 | 0 | MaxValue > 0 ? MaxValue : std::optional<unsigned>()); |
90 | 0 | } |
91 | | |
92 | | Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, |
93 | 4.22M | uint64_t Val) { |
94 | 4.22M | bool IsIntAttr = Attribute::isIntAttrKind(Kind); |
95 | 4.22M | assert((IsIntAttr || Attribute::isEnumAttrKind(Kind)) && |
96 | 4.22M | "Not an enum or int attribute"); |
97 | | |
98 | 0 | LLVMContextImpl *pImpl = Context.pImpl; |
99 | 4.22M | FoldingSetNodeID ID; |
100 | 4.22M | ID.AddInteger(Kind); |
101 | 4.22M | if (IsIntAttr) |
102 | 557k | ID.AddInteger(Val); |
103 | 3.66M | else |
104 | 3.66M | assert(Val == 0 && "Value must be zero for enum attributes"); |
105 | | |
106 | 0 | void *InsertPoint; |
107 | 4.22M | AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); |
108 | | |
109 | 4.22M | if (!PA) { |
110 | | // If we didn't find any existing attributes of the same shape then create a |
111 | | // new one and insert it. |
112 | 290k | if (!IsIntAttr) |
113 | 245k | PA = new (pImpl->Alloc) EnumAttributeImpl(Kind); |
114 | 45.2k | else |
115 | 45.2k | PA = new (pImpl->Alloc) IntAttributeImpl(Kind, Val); |
116 | 290k | pImpl->AttrsSet.InsertNode(PA, InsertPoint); |
117 | 290k | } |
118 | | |
119 | | // Return the Attribute that we found or created. |
120 | 4.22M | return Attribute(PA); |
121 | 4.22M | } |
122 | | |
123 | 396k | Attribute Attribute::get(LLVMContext &Context, StringRef Kind, StringRef Val) { |
124 | 396k | LLVMContextImpl *pImpl = Context.pImpl; |
125 | 396k | FoldingSetNodeID ID; |
126 | 396k | ID.AddString(Kind); |
127 | 396k | if (!Val.empty()) ID.AddString(Val); |
128 | | |
129 | 396k | void *InsertPoint; |
130 | 396k | AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); |
131 | | |
132 | 396k | if (!PA) { |
133 | | // If we didn't find any existing attributes of the same shape then create a |
134 | | // new one and insert it. |
135 | 39.4k | void *Mem = |
136 | 39.4k | pImpl->Alloc.Allocate(StringAttributeImpl::totalSizeToAlloc(Kind, Val), |
137 | 39.4k | alignof(StringAttributeImpl)); |
138 | 39.4k | PA = new (Mem) StringAttributeImpl(Kind, Val); |
139 | 39.4k | pImpl->AttrsSet.InsertNode(PA, InsertPoint); |
140 | 39.4k | } |
141 | | |
142 | | // Return the Attribute that we found or created. |
143 | 396k | return Attribute(PA); |
144 | 396k | } |
145 | | |
146 | | Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, |
147 | 1.86k | Type *Ty) { |
148 | 1.86k | assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute"); |
149 | 0 | LLVMContextImpl *pImpl = Context.pImpl; |
150 | 1.86k | FoldingSetNodeID ID; |
151 | 1.86k | ID.AddInteger(Kind); |
152 | 1.86k | ID.AddPointer(Ty); |
153 | | |
154 | 1.86k | void *InsertPoint; |
155 | 1.86k | AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); |
156 | | |
157 | 1.86k | if (!PA) { |
158 | | // If we didn't find any existing attributes of the same shape then create a |
159 | | // new one and insert it. |
160 | 1.24k | PA = new (pImpl->Alloc) TypeAttributeImpl(Kind, Ty); |
161 | 1.24k | pImpl->AttrsSet.InsertNode(PA, InsertPoint); |
162 | 1.24k | } |
163 | | |
164 | | // Return the Attribute that we found or created. |
165 | 1.86k | return Attribute(PA); |
166 | 1.86k | } |
167 | | |
168 | 2.14k | Attribute Attribute::getWithAlignment(LLVMContext &Context, Align A) { |
169 | 2.14k | assert(A <= llvm::Value::MaximumAlignment && "Alignment too large."); |
170 | 0 | return get(Context, Alignment, A.value()); |
171 | 2.14k | } |
172 | | |
173 | 0 | Attribute Attribute::getWithStackAlignment(LLVMContext &Context, Align A) { |
174 | 0 | assert(A <= 0x100 && "Alignment too large."); |
175 | 0 | return get(Context, StackAlignment, A.value()); |
176 | 0 | } |
177 | | |
178 | | Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context, |
179 | 3.79k | uint64_t Bytes) { |
180 | 3.79k | assert(Bytes && "Bytes must be non-zero."); |
181 | 0 | return get(Context, Dereferenceable, Bytes); |
182 | 3.79k | } |
183 | | |
184 | | Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context, |
185 | 738 | uint64_t Bytes) { |
186 | 738 | assert(Bytes && "Bytes must be non-zero."); |
187 | 0 | return get(Context, DereferenceableOrNull, Bytes); |
188 | 738 | } |
189 | | |
190 | 60 | Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) { |
191 | 60 | return get(Context, ByVal, Ty); |
192 | 60 | } |
193 | | |
194 | 90 | Attribute Attribute::getWithStructRetType(LLVMContext &Context, Type *Ty) { |
195 | 90 | return get(Context, StructRet, Ty); |
196 | 90 | } |
197 | | |
198 | 0 | Attribute Attribute::getWithByRefType(LLVMContext &Context, Type *Ty) { |
199 | 0 | return get(Context, ByRef, Ty); |
200 | 0 | } |
201 | | |
202 | 0 | Attribute Attribute::getWithPreallocatedType(LLVMContext &Context, Type *Ty) { |
203 | 0 | return get(Context, Preallocated, Ty); |
204 | 0 | } |
205 | | |
206 | 34 | Attribute Attribute::getWithInAllocaType(LLVMContext &Context, Type *Ty) { |
207 | 34 | return get(Context, InAlloca, Ty); |
208 | 34 | } |
209 | | |
210 | | Attribute Attribute::getWithUWTableKind(LLVMContext &Context, |
211 | 0 | UWTableKind Kind) { |
212 | 0 | return get(Context, UWTable, uint64_t(Kind)); |
213 | 0 | } |
214 | | |
215 | | Attribute Attribute::getWithMemoryEffects(LLVMContext &Context, |
216 | 511k | MemoryEffects ME) { |
217 | 511k | return get(Context, Memory, ME.toIntValue()); |
218 | 511k | } |
219 | | |
220 | | Attribute Attribute::getWithNoFPClass(LLVMContext &Context, |
221 | 0 | FPClassTest ClassMask) { |
222 | 0 | return get(Context, NoFPClass, ClassMask); |
223 | 0 | } |
224 | | |
225 | | Attribute |
226 | | Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg, |
227 | 6 | const std::optional<unsigned> &NumElemsArg) { |
228 | 6 | assert(!(ElemSizeArg == 0 && NumElemsArg && *NumElemsArg == 0) && |
229 | 6 | "Invalid allocsize arguments -- given allocsize(0, 0)"); |
230 | 0 | return get(Context, AllocSize, packAllocSizeArgs(ElemSizeArg, NumElemsArg)); |
231 | 6 | } |
232 | | |
233 | | Attribute Attribute::getWithVScaleRangeArgs(LLVMContext &Context, |
234 | | unsigned MinValue, |
235 | 0 | unsigned MaxValue) { |
236 | 0 | return get(Context, VScaleRange, packVScaleRangeArgs(MinValue, MaxValue)); |
237 | 0 | } |
238 | | |
239 | 707 | Attribute::AttrKind Attribute::getAttrKindFromName(StringRef AttrName) { |
240 | 707 | return StringSwitch<Attribute::AttrKind>(AttrName) |
241 | 707 | #define GET_ATTR_NAMES |
242 | 707 | #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \ |
243 | 62.2k | .Case(#DISPLAY_NAME, Attribute::ENUM_NAME) |
244 | 707 | #include "llvm/IR/Attributes.inc" |
245 | 707 | .Default(Attribute::None); |
246 | 707 | } |
247 | | |
248 | 187 | StringRef Attribute::getNameFromAttrKind(Attribute::AttrKind AttrKind) { |
249 | 187 | switch (AttrKind) { |
250 | 0 | #define GET_ATTR_NAMES |
251 | 0 | #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \ |
252 | 187 | case Attribute::ENUM_NAME: \ |
253 | 187 | return #DISPLAY_NAME; |
254 | 0 | #include "llvm/IR/Attributes.inc" |
255 | 0 | case Attribute::None: |
256 | 0 | return "none"; |
257 | 0 | default: |
258 | 0 | llvm_unreachable("invalid Kind"); |
259 | 187 | } |
260 | 187 | } |
261 | | |
262 | 586 | bool Attribute::isExistingAttribute(StringRef Name) { |
263 | 586 | return StringSwitch<bool>(Name) |
264 | 586 | #define GET_ATTR_NAMES |
265 | 58.6k | #define ATTRIBUTE_ALL(ENUM_NAME, DISPLAY_NAME) .Case(#DISPLAY_NAME, true) |
266 | 586 | #include "llvm/IR/Attributes.inc" |
267 | 586 | .Default(false); |
268 | 586 | } |
269 | | |
270 | | //===----------------------------------------------------------------------===// |
271 | | // Attribute Accessor Methods |
272 | | //===----------------------------------------------------------------------===// |
273 | | |
274 | 9.16M | bool Attribute::isEnumAttribute() const { |
275 | 9.16M | return pImpl && pImpl->isEnumAttribute(); |
276 | 9.16M | } |
277 | | |
278 | 3.61M | bool Attribute::isIntAttribute() const { |
279 | 3.61M | return pImpl && pImpl->isIntAttribute(); |
280 | 3.61M | } |
281 | | |
282 | 16.3M | bool Attribute::isStringAttribute() const { |
283 | 16.3M | return pImpl && pImpl->isStringAttribute(); |
284 | 16.3M | } |
285 | | |
286 | 34.6k | bool Attribute::isTypeAttribute() const { |
287 | 34.6k | return pImpl && pImpl->isTypeAttribute(); |
288 | 34.6k | } |
289 | | |
290 | 9.16M | Attribute::AttrKind Attribute::getKindAsEnum() const { |
291 | 9.16M | if (!pImpl) return None; |
292 | 9.16M | assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute()) && |
293 | 9.16M | "Invalid attribute type to get the kind as an enum!"); |
294 | 0 | return pImpl->getKindAsEnum(); |
295 | 9.16M | } |
296 | | |
297 | 110 | uint64_t Attribute::getValueAsInt() const { |
298 | 110 | if (!pImpl) return 0; |
299 | 110 | assert(isIntAttribute() && |
300 | 110 | "Expected the attribute to be an integer attribute!"); |
301 | 0 | return pImpl->getValueAsInt(); |
302 | 110 | } |
303 | | |
304 | 3.65M | bool Attribute::getValueAsBool() const { |
305 | 3.65M | if (!pImpl) return false; |
306 | 18.1k | assert(isStringAttribute() && |
307 | 18.1k | "Expected the attribute to be a string attribute!"); |
308 | 0 | return pImpl->getValueAsBool(); |
309 | 3.65M | } |
310 | | |
311 | 3.16M | StringRef Attribute::getKindAsString() const { |
312 | 3.16M | if (!pImpl) return {}; |
313 | 3.16M | assert(isStringAttribute() && |
314 | 3.16M | "Invalid attribute type to get the kind as a string!"); |
315 | 0 | return pImpl->getKindAsString(); |
316 | 3.16M | } |
317 | | |
318 | 1.15M | StringRef Attribute::getValueAsString() const { |
319 | 1.15M | if (!pImpl) return {}; |
320 | 243k | assert(isStringAttribute() && |
321 | 243k | "Invalid attribute type to get the value as a string!"); |
322 | 0 | return pImpl->getValueAsString(); |
323 | 1.15M | } |
324 | | |
325 | 8.22k | Type *Attribute::getValueAsType() const { |
326 | 8.22k | if (!pImpl) return {}; |
327 | 8.22k | assert(isTypeAttribute() && |
328 | 8.22k | "Invalid attribute type to get the value as a type!"); |
329 | 0 | return pImpl->getValueAsType(); |
330 | 8.22k | } |
331 | | |
332 | | |
333 | 593k | bool Attribute::hasAttribute(AttrKind Kind) const { |
334 | 593k | return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None); |
335 | 593k | } |
336 | | |
337 | 339k | bool Attribute::hasAttribute(StringRef Kind) const { |
338 | 339k | if (!isStringAttribute()) return false; |
339 | 339k | return pImpl && pImpl->hasAttribute(Kind); |
340 | 339k | } |
341 | | |
342 | 28.8k | MaybeAlign Attribute::getAlignment() const { |
343 | 28.8k | assert(hasAttribute(Attribute::Alignment) && |
344 | 28.8k | "Trying to get alignment from non-alignment attribute!"); |
345 | 0 | return MaybeAlign(pImpl->getValueAsInt()); |
346 | 28.8k | } |
347 | | |
348 | 0 | MaybeAlign Attribute::getStackAlignment() const { |
349 | 0 | assert(hasAttribute(Attribute::StackAlignment) && |
350 | 0 | "Trying to get alignment from non-alignment attribute!"); |
351 | 0 | return MaybeAlign(pImpl->getValueAsInt()); |
352 | 0 | } |
353 | | |
354 | 9.57k | uint64_t Attribute::getDereferenceableBytes() const { |
355 | 9.57k | assert(hasAttribute(Attribute::Dereferenceable) && |
356 | 9.57k | "Trying to get dereferenceable bytes from " |
357 | 9.57k | "non-dereferenceable attribute!"); |
358 | 0 | return pImpl->getValueAsInt(); |
359 | 9.57k | } |
360 | | |
361 | 688 | uint64_t Attribute::getDereferenceableOrNullBytes() const { |
362 | 688 | assert(hasAttribute(Attribute::DereferenceableOrNull) && |
363 | 688 | "Trying to get dereferenceable bytes from " |
364 | 688 | "non-dereferenceable attribute!"); |
365 | 0 | return pImpl->getValueAsInt(); |
366 | 688 | } |
367 | | |
368 | | std::pair<unsigned, std::optional<unsigned>> |
369 | 2.33k | Attribute::getAllocSizeArgs() const { |
370 | 2.33k | assert(hasAttribute(Attribute::AllocSize) && |
371 | 2.33k | "Trying to get allocsize args from non-allocsize attribute"); |
372 | 0 | return unpackAllocSizeArgs(pImpl->getValueAsInt()); |
373 | 2.33k | } |
374 | | |
375 | 0 | unsigned Attribute::getVScaleRangeMin() const { |
376 | 0 | assert(hasAttribute(Attribute::VScaleRange) && |
377 | 0 | "Trying to get vscale args from non-vscale attribute"); |
378 | 0 | return unpackVScaleRangeArgs(pImpl->getValueAsInt()).first; |
379 | 0 | } |
380 | | |
381 | 0 | std::optional<unsigned> Attribute::getVScaleRangeMax() const { |
382 | 0 | assert(hasAttribute(Attribute::VScaleRange) && |
383 | 0 | "Trying to get vscale args from non-vscale attribute"); |
384 | 0 | return unpackVScaleRangeArgs(pImpl->getValueAsInt()).second; |
385 | 0 | } |
386 | | |
387 | 31.6k | UWTableKind Attribute::getUWTableKind() const { |
388 | 31.6k | assert(hasAttribute(Attribute::UWTable) && |
389 | 31.6k | "Trying to get unwind table kind from non-uwtable attribute"); |
390 | 0 | return UWTableKind(pImpl->getValueAsInt()); |
391 | 31.6k | } |
392 | | |
393 | 31 | AllocFnKind Attribute::getAllocKind() const { |
394 | 31 | assert(hasAttribute(Attribute::AllocKind) && |
395 | 31 | "Trying to get allockind value from non-allockind attribute"); |
396 | 0 | return AllocFnKind(pImpl->getValueAsInt()); |
397 | 31 | } |
398 | | |
399 | 205k | MemoryEffects Attribute::getMemoryEffects() const { |
400 | 205k | assert(hasAttribute(Attribute::Memory) && |
401 | 205k | "Can only call getMemoryEffects() on memory attribute"); |
402 | 0 | return MemoryEffects::createFromIntValue(pImpl->getValueAsInt()); |
403 | 205k | } |
404 | | |
405 | 0 | FPClassTest Attribute::getNoFPClass() const { |
406 | 0 | assert(hasAttribute(Attribute::NoFPClass) && |
407 | 0 | "Can only call getNoFPClass() on nofpclass attribute"); |
408 | 0 | return static_cast<FPClassTest>(pImpl->getValueAsInt()); |
409 | 0 | } |
410 | | |
411 | 0 | static const char *getModRefStr(ModRefInfo MR) { |
412 | 0 | switch (MR) { |
413 | 0 | case ModRefInfo::NoModRef: |
414 | 0 | return "none"; |
415 | 0 | case ModRefInfo::Ref: |
416 | 0 | return "read"; |
417 | 0 | case ModRefInfo::Mod: |
418 | 0 | return "write"; |
419 | 0 | case ModRefInfo::ModRef: |
420 | 0 | return "readwrite"; |
421 | 0 | } |
422 | 0 | llvm_unreachable("Invalid ModRefInfo"); |
423 | 0 | } |
424 | | |
425 | 245 | std::string Attribute::getAsString(bool InAttrGrp) const { |
426 | 245 | if (!pImpl) return {}; |
427 | | |
428 | 245 | if (isEnumAttribute()) |
429 | 187 | return getNameFromAttrKind(getKindAsEnum()).str(); |
430 | | |
431 | 58 | if (isTypeAttribute()) { |
432 | 0 | std::string Result = getNameFromAttrKind(getKindAsEnum()).str(); |
433 | 0 | Result += '('; |
434 | 0 | raw_string_ostream OS(Result); |
435 | 0 | getValueAsType()->print(OS, false, true); |
436 | 0 | OS.flush(); |
437 | 0 | Result += ')'; |
438 | 0 | return Result; |
439 | 0 | } |
440 | | |
441 | | // FIXME: These should be output like this: |
442 | | // |
443 | | // align=4 |
444 | | // alignstack=8 |
445 | | // |
446 | 58 | if (hasAttribute(Attribute::Alignment)) |
447 | 58 | return (InAttrGrp ? "align=" + Twine(getValueAsInt()) |
448 | 58 | : "align " + Twine(getValueAsInt())) |
449 | 58 | .str(); |
450 | | |
451 | 0 | auto AttrWithBytesToString = [&](const char *Name) { |
452 | 0 | return (InAttrGrp ? Name + ("=" + Twine(getValueAsInt())) |
453 | 0 | : Name + ("(" + Twine(getValueAsInt())) + ")") |
454 | 0 | .str(); |
455 | 0 | }; |
456 | |
|
457 | 0 | if (hasAttribute(Attribute::StackAlignment)) |
458 | 0 | return AttrWithBytesToString("alignstack"); |
459 | | |
460 | 0 | if (hasAttribute(Attribute::Dereferenceable)) |
461 | 0 | return AttrWithBytesToString("dereferenceable"); |
462 | | |
463 | 0 | if (hasAttribute(Attribute::DereferenceableOrNull)) |
464 | 0 | return AttrWithBytesToString("dereferenceable_or_null"); |
465 | | |
466 | 0 | if (hasAttribute(Attribute::AllocSize)) { |
467 | 0 | unsigned ElemSize; |
468 | 0 | std::optional<unsigned> NumElems; |
469 | 0 | std::tie(ElemSize, NumElems) = getAllocSizeArgs(); |
470 | |
|
471 | 0 | return (NumElems |
472 | 0 | ? "allocsize(" + Twine(ElemSize) + "," + Twine(*NumElems) + ")" |
473 | 0 | : "allocsize(" + Twine(ElemSize) + ")") |
474 | 0 | .str(); |
475 | 0 | } |
476 | | |
477 | 0 | if (hasAttribute(Attribute::VScaleRange)) { |
478 | 0 | unsigned MinValue = getVScaleRangeMin(); |
479 | 0 | std::optional<unsigned> MaxValue = getVScaleRangeMax(); |
480 | 0 | return ("vscale_range(" + Twine(MinValue) + "," + |
481 | 0 | Twine(MaxValue.value_or(0)) + ")") |
482 | 0 | .str(); |
483 | 0 | } |
484 | | |
485 | 0 | if (hasAttribute(Attribute::UWTable)) { |
486 | 0 | UWTableKind Kind = getUWTableKind(); |
487 | 0 | if (Kind != UWTableKind::None) { |
488 | 0 | return Kind == UWTableKind::Default |
489 | 0 | ? "uwtable" |
490 | 0 | : ("uwtable(" + |
491 | 0 | Twine(Kind == UWTableKind::Sync ? "sync" : "async") + ")") |
492 | 0 | .str(); |
493 | 0 | } |
494 | 0 | } |
495 | | |
496 | 0 | if (hasAttribute(Attribute::AllocKind)) { |
497 | 0 | AllocFnKind Kind = getAllocKind(); |
498 | 0 | SmallVector<StringRef> parts; |
499 | 0 | if ((Kind & AllocFnKind::Alloc) != AllocFnKind::Unknown) |
500 | 0 | parts.push_back("alloc"); |
501 | 0 | if ((Kind & AllocFnKind::Realloc) != AllocFnKind::Unknown) |
502 | 0 | parts.push_back("realloc"); |
503 | 0 | if ((Kind & AllocFnKind::Free) != AllocFnKind::Unknown) |
504 | 0 | parts.push_back("free"); |
505 | 0 | if ((Kind & AllocFnKind::Uninitialized) != AllocFnKind::Unknown) |
506 | 0 | parts.push_back("uninitialized"); |
507 | 0 | if ((Kind & AllocFnKind::Zeroed) != AllocFnKind::Unknown) |
508 | 0 | parts.push_back("zeroed"); |
509 | 0 | if ((Kind & AllocFnKind::Aligned) != AllocFnKind::Unknown) |
510 | 0 | parts.push_back("aligned"); |
511 | 0 | return ("allockind(\"" + |
512 | 0 | Twine(llvm::join(parts.begin(), parts.end(), ",")) + "\")") |
513 | 0 | .str(); |
514 | 0 | } |
515 | | |
516 | 0 | if (hasAttribute(Attribute::Memory)) { |
517 | 0 | std::string Result; |
518 | 0 | raw_string_ostream OS(Result); |
519 | 0 | bool First = true; |
520 | 0 | OS << "memory("; |
521 | |
|
522 | 0 | MemoryEffects ME = getMemoryEffects(); |
523 | | |
524 | | // Print access kind for "other" as the default access kind. This way it |
525 | | // will apply to any new location kinds that get split out of "other". |
526 | 0 | ModRefInfo OtherMR = ME.getModRef(IRMemLocation::Other); |
527 | 0 | if (OtherMR != ModRefInfo::NoModRef || ME.getModRef() == OtherMR) { |
528 | 0 | First = false; |
529 | 0 | OS << getModRefStr(OtherMR); |
530 | 0 | } |
531 | |
|
532 | 0 | for (auto Loc : MemoryEffects::locations()) { |
533 | 0 | ModRefInfo MR = ME.getModRef(Loc); |
534 | 0 | if (MR == OtherMR) |
535 | 0 | continue; |
536 | | |
537 | 0 | if (!First) |
538 | 0 | OS << ", "; |
539 | 0 | First = false; |
540 | |
|
541 | 0 | switch (Loc) { |
542 | 0 | case IRMemLocation::ArgMem: |
543 | 0 | OS << "argmem: "; |
544 | 0 | break; |
545 | 0 | case IRMemLocation::InaccessibleMem: |
546 | 0 | OS << "inaccessiblemem: "; |
547 | 0 | break; |
548 | 0 | case IRMemLocation::Other: |
549 | 0 | llvm_unreachable("This is represented as the default access kind"); |
550 | 0 | } |
551 | 0 | OS << getModRefStr(MR); |
552 | 0 | } |
553 | 0 | OS << ")"; |
554 | 0 | OS.flush(); |
555 | 0 | return Result; |
556 | 0 | } |
557 | | |
558 | 0 | if (hasAttribute(Attribute::NoFPClass)) { |
559 | 0 | std::string Result = "nofpclass"; |
560 | 0 | raw_string_ostream OS(Result); |
561 | 0 | OS << getNoFPClass(); |
562 | 0 | return Result; |
563 | 0 | } |
564 | | |
565 | | // Convert target-dependent attributes to strings of the form: |
566 | | // |
567 | | // "kind" |
568 | | // "kind" = "value" |
569 | | // |
570 | 0 | if (isStringAttribute()) { |
571 | 0 | std::string Result; |
572 | 0 | { |
573 | 0 | raw_string_ostream OS(Result); |
574 | 0 | OS << '"' << getKindAsString() << '"'; |
575 | | |
576 | | // Since some attribute strings contain special characters that cannot be |
577 | | // printable, those have to be escaped to make the attribute value |
578 | | // printable as is. e.g. "\01__gnu_mcount_nc" |
579 | 0 | const auto &AttrVal = pImpl->getValueAsString(); |
580 | 0 | if (!AttrVal.empty()) { |
581 | 0 | OS << "=\""; |
582 | 0 | printEscapedString(AttrVal, OS); |
583 | 0 | OS << "\""; |
584 | 0 | } |
585 | 0 | } |
586 | 0 | return Result; |
587 | 0 | } |
588 | | |
589 | 0 | llvm_unreachable("Unknown attribute"); |
590 | 0 | } |
591 | | |
592 | 729k | bool Attribute::hasParentContext(LLVMContext &C) const { |
593 | 729k | assert(isValid() && "invalid Attribute doesn't refer to any context"); |
594 | 0 | FoldingSetNodeID ID; |
595 | 729k | pImpl->Profile(ID); |
596 | 729k | void *Unused; |
597 | 729k | return C.pImpl->AttrsSet.FindNodeOrInsertPos(ID, Unused) == pImpl; |
598 | 729k | } |
599 | | |
600 | 10.5M | bool Attribute::operator<(Attribute A) const { |
601 | 10.5M | if (!pImpl && !A.pImpl) return false; |
602 | 10.5M | if (!pImpl) return true; |
603 | 10.5M | if (!A.pImpl) return false; |
604 | 10.5M | return *pImpl < *A.pImpl; |
605 | 10.5M | } |
606 | | |
607 | 10.2M | void Attribute::Profile(FoldingSetNodeID &ID) const { |
608 | 10.2M | ID.AddPointer(pImpl); |
609 | 10.2M | } |
610 | | |
611 | | enum AttributeProperty { |
612 | | FnAttr = (1 << 0), |
613 | | ParamAttr = (1 << 1), |
614 | | RetAttr = (1 << 2), |
615 | | }; |
616 | | |
617 | | #define GET_ATTR_PROP_TABLE |
618 | | #include "llvm/IR/Attributes.inc" |
619 | | |
620 | | static bool hasAttributeProperty(Attribute::AttrKind Kind, |
621 | 2.29M | AttributeProperty Prop) { |
622 | 2.29M | unsigned Index = Kind - 1; |
623 | 2.29M | assert(Index < std::size(AttrPropTable) && "Invalid attribute kind"); |
624 | 0 | return AttrPropTable[Index] & Prop; |
625 | 2.29M | } |
626 | | |
627 | 1.68M | bool Attribute::canUseAsFnAttr(AttrKind Kind) { |
628 | 1.68M | return hasAttributeProperty(Kind, AttributeProperty::FnAttr); |
629 | 1.68M | } |
630 | | |
631 | 580k | bool Attribute::canUseAsParamAttr(AttrKind Kind) { |
632 | 580k | return hasAttributeProperty(Kind, AttributeProperty::ParamAttr); |
633 | 580k | } |
634 | | |
635 | 22.4k | bool Attribute::canUseAsRetAttr(AttrKind Kind) { |
636 | 22.4k | return hasAttributeProperty(Kind, AttributeProperty::RetAttr); |
637 | 22.4k | } |
638 | | |
639 | | //===----------------------------------------------------------------------===// |
640 | | // AttributeImpl Definition |
641 | | //===----------------------------------------------------------------------===// |
642 | | |
643 | 593k | bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const { |
644 | 593k | if (isStringAttribute()) return false; |
645 | 589k | return getKindAsEnum() == A; |
646 | 593k | } |
647 | | |
648 | 339k | bool AttributeImpl::hasAttribute(StringRef Kind) const { |
649 | 339k | if (!isStringAttribute()) return false; |
650 | 339k | return getKindAsString() == Kind; |
651 | 339k | } |
652 | | |
653 | 56.9M | Attribute::AttrKind AttributeImpl::getKindAsEnum() const { |
654 | 56.9M | assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute()); |
655 | 0 | return static_cast<const EnumAttributeImpl *>(this)->getEnumKind(); |
656 | 56.9M | } |
657 | | |
658 | 989k | uint64_t AttributeImpl::getValueAsInt() const { |
659 | 989k | assert(isIntAttribute()); |
660 | 0 | return static_cast<const IntAttributeImpl *>(this)->getValue(); |
661 | 989k | } |
662 | | |
663 | 18.1k | bool AttributeImpl::getValueAsBool() const { |
664 | 18.1k | assert(getValueAsString().empty() || getValueAsString() == "false" || getValueAsString() == "true"); |
665 | 0 | return getValueAsString() == "true"; |
666 | 18.1k | } |
667 | | |
668 | 4.65M | StringRef AttributeImpl::getKindAsString() const { |
669 | 4.65M | assert(isStringAttribute()); |
670 | 0 | return static_cast<const StringAttributeImpl *>(this)->getStringKind(); |
671 | 4.65M | } |
672 | | |
673 | 1.00M | StringRef AttributeImpl::getValueAsString() const { |
674 | 1.00M | assert(isStringAttribute()); |
675 | 0 | return static_cast<const StringAttributeImpl *>(this)->getStringValue(); |
676 | 1.00M | } |
677 | | |
678 | 13.1k | Type *AttributeImpl::getValueAsType() const { |
679 | 13.1k | assert(isTypeAttribute()); |
680 | 0 | return static_cast<const TypeAttributeImpl *>(this)->getTypeValue(); |
681 | 13.1k | } |
682 | | |
683 | 10.5M | bool AttributeImpl::operator<(const AttributeImpl &AI) const { |
684 | 10.5M | if (this == &AI) |
685 | 0 | return false; |
686 | | |
687 | | // This sorts the attributes with Attribute::AttrKinds coming first (sorted |
688 | | // relative to their enum value) and then strings. |
689 | 10.5M | if (!isStringAttribute()) { |
690 | 10.4M | if (AI.isStringAttribute()) |
691 | 42 | return true; |
692 | 10.4M | if (getKindAsEnum() != AI.getKindAsEnum()) |
693 | 10.4M | return getKindAsEnum() < AI.getKindAsEnum(); |
694 | 0 | assert(!AI.isEnumAttribute() && "Non-unique attribute"); |
695 | 0 | assert(!AI.isTypeAttribute() && "Comparison of types would be unstable"); |
696 | | // TODO: Is this actually needed? |
697 | 0 | assert(AI.isIntAttribute() && "Only possibility left"); |
698 | 0 | return getValueAsInt() < AI.getValueAsInt(); |
699 | 10.4M | } |
700 | | |
701 | 123k | if (!AI.isStringAttribute()) |
702 | 10.6k | return false; |
703 | 112k | if (getKindAsString() == AI.getKindAsString()) |
704 | 0 | return getValueAsString() < AI.getValueAsString(); |
705 | 112k | return getKindAsString() < AI.getKindAsString(); |
706 | 112k | } |
707 | | |
708 | | //===----------------------------------------------------------------------===// |
709 | | // AttributeSet Definition |
710 | | //===----------------------------------------------------------------------===// |
711 | | |
712 | 21.1M | AttributeSet AttributeSet::get(LLVMContext &C, const AttrBuilder &B) { |
713 | 21.1M | return AttributeSet(AttributeSetNode::get(C, B)); |
714 | 21.1M | } |
715 | | |
716 | 1.11M | AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef<Attribute> Attrs) { |
717 | 1.11M | return AttributeSet(AttributeSetNode::get(C, Attrs)); |
718 | 1.11M | } |
719 | | |
720 | | AttributeSet AttributeSet::addAttribute(LLVMContext &C, |
721 | 0 | Attribute::AttrKind Kind) const { |
722 | 0 | if (hasAttribute(Kind)) return *this; |
723 | 0 | AttrBuilder B(C); |
724 | 0 | B.addAttribute(Kind); |
725 | 0 | return addAttributes(C, AttributeSet::get(C, B)); |
726 | 0 | } |
727 | | |
728 | | AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind, |
729 | 0 | StringRef Value) const { |
730 | 0 | AttrBuilder B(C); |
731 | 0 | B.addAttribute(Kind, Value); |
732 | 0 | return addAttributes(C, AttributeSet::get(C, B)); |
733 | 0 | } |
734 | | |
735 | | AttributeSet AttributeSet::addAttributes(LLVMContext &C, |
736 | 0 | const AttributeSet AS) const { |
737 | 0 | if (!hasAttributes()) |
738 | 0 | return AS; |
739 | | |
740 | 0 | if (!AS.hasAttributes()) |
741 | 0 | return *this; |
742 | | |
743 | 0 | AttrBuilder B(C, *this); |
744 | 0 | B.merge(AttrBuilder(C, AS)); |
745 | 0 | return get(C, B); |
746 | 0 | } |
747 | | |
748 | | AttributeSet AttributeSet::removeAttribute(LLVMContext &C, |
749 | 10.1k | Attribute::AttrKind Kind) const { |
750 | 10.1k | if (!hasAttribute(Kind)) return *this; |
751 | 1.85k | AttrBuilder B(C, *this); |
752 | 1.85k | B.removeAttribute(Kind); |
753 | 1.85k | return get(C, B); |
754 | 10.1k | } |
755 | | |
756 | | AttributeSet AttributeSet::removeAttribute(LLVMContext &C, |
757 | 15.5k | StringRef Kind) const { |
758 | 15.5k | if (!hasAttribute(Kind)) return *this; |
759 | 0 | AttrBuilder B(C, *this); |
760 | 0 | B.removeAttribute(Kind); |
761 | 0 | return get(C, B); |
762 | 15.5k | } |
763 | | |
764 | | AttributeSet AttributeSet::removeAttributes(LLVMContext &C, |
765 | 13.5M | const AttributeMask &Attrs) const { |
766 | 13.5M | AttrBuilder B(C, *this); |
767 | | // If there is nothing to remove, directly return the original set. |
768 | 13.5M | if (!B.overlaps(Attrs)) |
769 | 13.5M | return *this; |
770 | | |
771 | 61 | B.remove(Attrs); |
772 | 61 | return get(C, B); |
773 | 13.5M | } |
774 | | |
775 | 144k | unsigned AttributeSet::getNumAttributes() const { |
776 | 144k | return SetNode ? SetNode->getNumAttributes() : 0; |
777 | 144k | } |
778 | | |
779 | 60.1M | bool AttributeSet::hasAttribute(Attribute::AttrKind Kind) const { |
780 | 60.1M | return SetNode ? SetNode->hasAttribute(Kind) : false; |
781 | 60.1M | } |
782 | | |
783 | 25.6M | bool AttributeSet::hasAttribute(StringRef Kind) const { |
784 | 25.6M | return SetNode ? SetNode->hasAttribute(Kind) : false; |
785 | 25.6M | } |
786 | | |
787 | 906k | Attribute AttributeSet::getAttribute(Attribute::AttrKind Kind) const { |
788 | 906k | return SetNode ? SetNode->getAttribute(Kind) : Attribute(); |
789 | 906k | } |
790 | | |
791 | 18.5M | Attribute AttributeSet::getAttribute(StringRef Kind) const { |
792 | 18.5M | return SetNode ? SetNode->getAttribute(Kind) : Attribute(); |
793 | 18.5M | } |
794 | | |
795 | 122k | MaybeAlign AttributeSet::getAlignment() const { |
796 | 122k | return SetNode ? SetNode->getAlignment() : std::nullopt; |
797 | 122k | } |
798 | | |
799 | 354k | MaybeAlign AttributeSet::getStackAlignment() const { |
800 | 354k | return SetNode ? SetNode->getStackAlignment() : std::nullopt; |
801 | 354k | } |
802 | | |
803 | 515k | uint64_t AttributeSet::getDereferenceableBytes() const { |
804 | 515k | return SetNode ? SetNode->getDereferenceableBytes() : 0; |
805 | 515k | } |
806 | | |
807 | 497k | uint64_t AttributeSet::getDereferenceableOrNullBytes() const { |
808 | 497k | return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0; |
809 | 497k | } |
810 | | |
811 | 484k | Type *AttributeSet::getByRefType() const { |
812 | 484k | return SetNode ? SetNode->getAttributeType(Attribute::ByRef) : nullptr; |
813 | 484k | } |
814 | | |
815 | 488k | Type *AttributeSet::getByValType() const { |
816 | 488k | return SetNode ? SetNode->getAttributeType(Attribute::ByVal) : nullptr; |
817 | 488k | } |
818 | | |
819 | 484k | Type *AttributeSet::getStructRetType() const { |
820 | 484k | return SetNode ? SetNode->getAttributeType(Attribute::StructRet) : nullptr; |
821 | 484k | } |
822 | | |
823 | 484k | Type *AttributeSet::getPreallocatedType() const { |
824 | 484k | return SetNode ? SetNode->getAttributeType(Attribute::Preallocated) : nullptr; |
825 | 484k | } |
826 | | |
827 | 485k | Type *AttributeSet::getInAllocaType() const { |
828 | 485k | return SetNode ? SetNode->getAttributeType(Attribute::InAlloca) : nullptr; |
829 | 485k | } |
830 | | |
831 | 716 | Type *AttributeSet::getElementType() const { |
832 | 716 | return SetNode ? SetNode->getAttributeType(Attribute::ElementType) : nullptr; |
833 | 716 | } |
834 | | |
835 | | std::optional<std::pair<unsigned, std::optional<unsigned>>> |
836 | 462k | AttributeSet::getAllocSizeArgs() const { |
837 | 462k | if (SetNode) |
838 | 462k | return SetNode->getAllocSizeArgs(); |
839 | 0 | return std::nullopt; |
840 | 462k | } |
841 | | |
842 | 0 | unsigned AttributeSet::getVScaleRangeMin() const { |
843 | 0 | return SetNode ? SetNode->getVScaleRangeMin() : 1; |
844 | 0 | } |
845 | | |
846 | 0 | std::optional<unsigned> AttributeSet::getVScaleRangeMax() const { |
847 | 0 | return SetNode ? SetNode->getVScaleRangeMax() : std::nullopt; |
848 | 0 | } |
849 | | |
850 | 709k | UWTableKind AttributeSet::getUWTableKind() const { |
851 | 709k | return SetNode ? SetNode->getUWTableKind() : UWTableKind::None; |
852 | 709k | } |
853 | | |
854 | 11.6k | AllocFnKind AttributeSet::getAllocKind() const { |
855 | 11.6k | return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown; |
856 | 11.6k | } |
857 | | |
858 | 575k | MemoryEffects AttributeSet::getMemoryEffects() const { |
859 | 575k | return SetNode ? SetNode->getMemoryEffects() : MemoryEffects::unknown(); |
860 | 575k | } |
861 | | |
862 | 19.2k | FPClassTest AttributeSet::getNoFPClass() const { |
863 | 19.2k | return SetNode ? SetNode->getNoFPClass() : fcNone; |
864 | 19.2k | } |
865 | | |
866 | 0 | std::string AttributeSet::getAsString(bool InAttrGrp) const { |
867 | 0 | return SetNode ? SetNode->getAsString(InAttrGrp) : ""; |
868 | 0 | } |
869 | | |
870 | 268k | bool AttributeSet::hasParentContext(LLVMContext &C) const { |
871 | 268k | assert(hasAttributes() && "empty AttributeSet doesn't refer to any context"); |
872 | 0 | FoldingSetNodeID ID; |
873 | 268k | SetNode->Profile(ID); |
874 | 268k | void *Unused; |
875 | 268k | return C.pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, Unused) == SetNode; |
876 | 268k | } |
877 | | |
878 | 306M | AttributeSet::iterator AttributeSet::begin() const { |
879 | 306M | return SetNode ? SetNode->begin() : nullptr; |
880 | 306M | } |
881 | | |
882 | 306M | AttributeSet::iterator AttributeSet::end() const { |
883 | 306M | return SetNode ? SetNode->end() : nullptr; |
884 | 306M | } |
885 | | |
886 | | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
887 | 0 | LLVM_DUMP_METHOD void AttributeSet::dump() const { |
888 | 0 | dbgs() << "AS =\n"; |
889 | 0 | dbgs() << " { "; |
890 | 0 | dbgs() << getAsString(true) << " }\n"; |
891 | 0 | } |
892 | | #endif |
893 | | |
894 | | //===----------------------------------------------------------------------===// |
895 | | // AttributeSetNode Definition |
896 | | //===----------------------------------------------------------------------===// |
897 | | |
898 | | AttributeSetNode::AttributeSetNode(ArrayRef<Attribute> Attrs) |
899 | 152k | : NumAttrs(Attrs.size()) { |
900 | | // There's memory after the node where we can store the entries in. |
901 | 152k | llvm::copy(Attrs, getTrailingObjects<Attribute>()); |
902 | | |
903 | 477k | for (const auto &I : *this) { |
904 | 477k | if (I.isStringAttribute()) |
905 | 64.2k | StringAttrs.insert({ I.getKindAsString(), I }); |
906 | 413k | else |
907 | 413k | AvailableAttrs.addAttribute(I.getKindAsEnum()); |
908 | 477k | } |
909 | 152k | } |
910 | | |
911 | | AttributeSetNode *AttributeSetNode::get(LLVMContext &C, |
912 | 1.11M | ArrayRef<Attribute> Attrs) { |
913 | 1.11M | SmallVector<Attribute, 8> SortedAttrs(Attrs.begin(), Attrs.end()); |
914 | 1.11M | llvm::sort(SortedAttrs); |
915 | 1.11M | return getSorted(C, SortedAttrs); |
916 | 1.11M | } |
917 | | |
918 | | AttributeSetNode *AttributeSetNode::getSorted(LLVMContext &C, |
919 | 22.3M | ArrayRef<Attribute> SortedAttrs) { |
920 | 22.3M | if (SortedAttrs.empty()) |
921 | 20.9M | return nullptr; |
922 | | |
923 | | // Build a key to look up the existing attributes. |
924 | 1.36M | LLVMContextImpl *pImpl = C.pImpl; |
925 | 1.36M | FoldingSetNodeID ID; |
926 | | |
927 | 1.36M | assert(llvm::is_sorted(SortedAttrs) && "Expected sorted attributes!"); |
928 | 0 | for (const auto &Attr : SortedAttrs) |
929 | 4.56M | Attr.Profile(ID); |
930 | | |
931 | 1.36M | void *InsertPoint; |
932 | 1.36M | AttributeSetNode *PA = |
933 | 1.36M | pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, InsertPoint); |
934 | | |
935 | | // If we didn't find any existing attributes of the same shape then create a |
936 | | // new one and insert it. |
937 | 1.36M | if (!PA) { |
938 | | // Coallocate entries after the AttributeSetNode itself. |
939 | 152k | void *Mem = ::operator new(totalSizeToAlloc<Attribute>(SortedAttrs.size())); |
940 | 152k | PA = new (Mem) AttributeSetNode(SortedAttrs); |
941 | 152k | pImpl->AttrsSetNodes.InsertNode(PA, InsertPoint); |
942 | 152k | } |
943 | | |
944 | | // Return the AttributeSetNode that we found or created. |
945 | 1.36M | return PA; |
946 | 22.3M | } |
947 | | |
948 | 21.1M | AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) { |
949 | 21.1M | return getSorted(C, B.attrs()); |
950 | 21.1M | } |
951 | | |
952 | 7.84M | bool AttributeSetNode::hasAttribute(StringRef Kind) const { |
953 | 7.84M | return StringAttrs.count(Kind); |
954 | 7.84M | } |
955 | | |
956 | | std::optional<Attribute> |
957 | 1.59M | AttributeSetNode::findEnumAttribute(Attribute::AttrKind Kind) const { |
958 | | // Do a quick presence check. |
959 | 1.59M | if (!hasAttribute(Kind)) |
960 | 1.31M | return std::nullopt; |
961 | | |
962 | | // Attributes in a set are sorted by enum value, followed by string |
963 | | // attributes. Binary search the one we want. |
964 | 286k | const Attribute *I = |
965 | 286k | std::lower_bound(begin(), end() - StringAttrs.size(), Kind, |
966 | 698k | [](Attribute A, Attribute::AttrKind Kind) { |
967 | 698k | return A.getKindAsEnum() < Kind; |
968 | 698k | }); |
969 | 286k | assert(I != end() && I->hasAttribute(Kind) && "Presence check failed?"); |
970 | 0 | return *I; |
971 | 1.59M | } |
972 | | |
973 | 459k | Attribute AttributeSetNode::getAttribute(Attribute::AttrKind Kind) const { |
974 | 459k | if (auto A = findEnumAttribute(Kind)) |
975 | 2.20k | return *A; |
976 | 457k | return {}; |
977 | 459k | } |
978 | | |
979 | 4.20M | Attribute AttributeSetNode::getAttribute(StringRef Kind) const { |
980 | 4.20M | return StringAttrs.lookup(Kind); |
981 | 4.20M | } |
982 | | |
983 | 78.9k | MaybeAlign AttributeSetNode::getAlignment() const { |
984 | 78.9k | if (auto A = findEnumAttribute(Attribute::Alignment)) |
985 | 28.8k | return A->getAlignment(); |
986 | 50.1k | return std::nullopt; |
987 | 78.9k | } |
988 | | |
989 | 37.9k | MaybeAlign AttributeSetNode::getStackAlignment() const { |
990 | 37.9k | if (auto A = findEnumAttribute(Attribute::StackAlignment)) |
991 | 0 | return A->getStackAlignment(); |
992 | 37.9k | return std::nullopt; |
993 | 37.9k | } |
994 | | |
995 | 169k | Type *AttributeSetNode::getAttributeType(Attribute::AttrKind Kind) const { |
996 | 169k | if (auto A = findEnumAttribute(Kind)) |
997 | 7.24k | return A->getValueAsType(); |
998 | 161k | return nullptr; |
999 | 169k | } |
1000 | | |
1001 | 39.0k | uint64_t AttributeSetNode::getDereferenceableBytes() const { |
1002 | 39.0k | if (auto A = findEnumAttribute(Attribute::Dereferenceable)) |
1003 | 9.57k | return A->getDereferenceableBytes(); |
1004 | 29.4k | return 0; |
1005 | 39.0k | } |
1006 | | |
1007 | 30.0k | uint64_t AttributeSetNode::getDereferenceableOrNullBytes() const { |
1008 | 30.0k | if (auto A = findEnumAttribute(Attribute::DereferenceableOrNull)) |
1009 | 688 | return A->getDereferenceableOrNullBytes(); |
1010 | 29.3k | return 0; |
1011 | 30.0k | } |
1012 | | |
1013 | | std::optional<std::pair<unsigned, std::optional<unsigned>>> |
1014 | 462k | AttributeSetNode::getAllocSizeArgs() const { |
1015 | 462k | if (auto A = findEnumAttribute(Attribute::AllocSize)) |
1016 | 1.15k | return A->getAllocSizeArgs(); |
1017 | 461k | return std::nullopt; |
1018 | 462k | } |
1019 | | |
1020 | 0 | unsigned AttributeSetNode::getVScaleRangeMin() const { |
1021 | 0 | if (auto A = findEnumAttribute(Attribute::VScaleRange)) |
1022 | 0 | return A->getVScaleRangeMin(); |
1023 | 0 | return 1; |
1024 | 0 | } |
1025 | | |
1026 | 0 | std::optional<unsigned> AttributeSetNode::getVScaleRangeMax() const { |
1027 | 0 | if (auto A = findEnumAttribute(Attribute::VScaleRange)) |
1028 | 0 | return A->getVScaleRangeMax(); |
1029 | 0 | return std::nullopt; |
1030 | 0 | } |
1031 | | |
1032 | 73.8k | UWTableKind AttributeSetNode::getUWTableKind() const { |
1033 | 73.8k | if (auto A = findEnumAttribute(Attribute::UWTable)) |
1034 | 31.6k | return A->getUWTableKind(); |
1035 | 42.1k | return UWTableKind::None; |
1036 | 73.8k | } |
1037 | | |
1038 | 3.83k | AllocFnKind AttributeSetNode::getAllocKind() const { |
1039 | 3.83k | if (auto A = findEnumAttribute(Attribute::AllocKind)) |
1040 | 31 | return A->getAllocKind(); |
1041 | 3.80k | return AllocFnKind::Unknown; |
1042 | 3.83k | } |
1043 | | |
1044 | 242k | MemoryEffects AttributeSetNode::getMemoryEffects() const { |
1045 | 242k | if (auto A = findEnumAttribute(Attribute::Memory)) |
1046 | 205k | return A->getMemoryEffects(); |
1047 | 36.9k | return MemoryEffects::unknown(); |
1048 | 242k | } |
1049 | | |
1050 | 44 | FPClassTest AttributeSetNode::getNoFPClass() const { |
1051 | 44 | if (auto A = findEnumAttribute(Attribute::NoFPClass)) |
1052 | 0 | return A->getNoFPClass(); |
1053 | 44 | return fcNone; |
1054 | 44 | } |
1055 | | |
1056 | 0 | std::string AttributeSetNode::getAsString(bool InAttrGrp) const { |
1057 | 0 | std::string Str; |
1058 | 0 | for (iterator I = begin(), E = end(); I != E; ++I) { |
1059 | 0 | if (I != begin()) |
1060 | 0 | Str += ' '; |
1061 | 0 | Str += I->getAsString(InAttrGrp); |
1062 | 0 | } |
1063 | 0 | return Str; |
1064 | 0 | } |
1065 | | |
1066 | | //===----------------------------------------------------------------------===// |
1067 | | // AttributeListImpl Definition |
1068 | | //===----------------------------------------------------------------------===// |
1069 | | |
1070 | | /// Map from AttributeList index to the internal array index. Adding one happens |
1071 | | /// to work, because -1 wraps around to 0. |
1072 | 221M | static unsigned attrIdxToArrayIdx(unsigned Index) { |
1073 | 221M | return Index + 1; |
1074 | 221M | } |
1075 | | |
1076 | | AttributeListImpl::AttributeListImpl(ArrayRef<AttributeSet> Sets) |
1077 | 204k | : NumAttrSets(Sets.size()) { |
1078 | 204k | assert(!Sets.empty() && "pointless AttributeListImpl"); |
1079 | | |
1080 | | // There's memory after the node where we can store the entries in. |
1081 | 0 | llvm::copy(Sets, getTrailingObjects<AttributeSet>()); |
1082 | | |
1083 | | // Initialize AvailableFunctionAttrs and AvailableSomewhereAttrs |
1084 | | // summary bitsets. |
1085 | 204k | for (const auto &I : Sets[attrIdxToArrayIdx(AttributeList::FunctionIndex)]) |
1086 | 485k | if (!I.isStringAttribute()) |
1087 | 449k | AvailableFunctionAttrs.addAttribute(I.getKindAsEnum()); |
1088 | | |
1089 | 204k | for (const auto &Set : Sets) |
1090 | 175M | for (const auto &I : Set) |
1091 | 747k | if (!I.isStringAttribute()) |
1092 | 702k | AvailableSomewhereAttrs.addAttribute(I.getKindAsEnum()); |
1093 | 204k | } |
1094 | | |
1095 | 910k | void AttributeListImpl::Profile(FoldingSetNodeID &ID) const { |
1096 | 910k | Profile(ID, ArrayRef(begin(), end())); |
1097 | 910k | } |
1098 | | |
1099 | | void AttributeListImpl::Profile(FoldingSetNodeID &ID, |
1100 | 1.67M | ArrayRef<AttributeSet> Sets) { |
1101 | 1.67M | for (const auto &Set : Sets) |
1102 | 184M | ID.AddPointer(Set.SetNode); |
1103 | 1.67M | } |
1104 | | |
1105 | | bool AttributeListImpl::hasAttrSomewhere(Attribute::AttrKind Kind, |
1106 | 2.54M | unsigned *Index) const { |
1107 | 2.54M | if (!AvailableSomewhereAttrs.hasAttribute(Kind)) |
1108 | 2.54M | return false; |
1109 | | |
1110 | 1.82k | if (Index) { |
1111 | 5.15k | for (unsigned I = 0, E = NumAttrSets; I != E; ++I) { |
1112 | 5.15k | if (begin()[I].hasAttribute(Kind)) { |
1113 | 1.71k | *Index = I - 1; |
1114 | 1.71k | break; |
1115 | 1.71k | } |
1116 | 5.15k | } |
1117 | 1.71k | } |
1118 | | |
1119 | 1.82k | return true; |
1120 | 2.54M | } |
1121 | | |
1122 | | |
1123 | | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
1124 | 0 | LLVM_DUMP_METHOD void AttributeListImpl::dump() const { |
1125 | 0 | AttributeList(const_cast<AttributeListImpl *>(this)).dump(); |
1126 | 0 | } |
1127 | | #endif |
1128 | | |
1129 | | //===----------------------------------------------------------------------===// |
1130 | | // AttributeList Construction and Mutation Methods |
1131 | | //===----------------------------------------------------------------------===// |
1132 | | |
1133 | | AttributeList AttributeList::getImpl(LLVMContext &C, |
1134 | 761k | ArrayRef<AttributeSet> AttrSets) { |
1135 | 761k | assert(!AttrSets.empty() && "pointless AttributeListImpl"); |
1136 | | |
1137 | 0 | LLVMContextImpl *pImpl = C.pImpl; |
1138 | 761k | FoldingSetNodeID ID; |
1139 | 761k | AttributeListImpl::Profile(ID, AttrSets); |
1140 | | |
1141 | 761k | void *InsertPoint; |
1142 | 761k | AttributeListImpl *PA = |
1143 | 761k | pImpl->AttrsLists.FindNodeOrInsertPos(ID, InsertPoint); |
1144 | | |
1145 | | // If we didn't find any existing attributes of the same shape then |
1146 | | // create a new one and insert it. |
1147 | 761k | if (!PA) { |
1148 | | // Coallocate entries after the AttributeListImpl itself. |
1149 | 204k | void *Mem = pImpl->Alloc.Allocate( |
1150 | 204k | AttributeListImpl::totalSizeToAlloc<AttributeSet>(AttrSets.size()), |
1151 | 204k | alignof(AttributeListImpl)); |
1152 | 204k | PA = new (Mem) AttributeListImpl(AttrSets); |
1153 | 204k | pImpl->AttrsLists.InsertNode(PA, InsertPoint); |
1154 | 204k | } |
1155 | | |
1156 | | // Return the AttributesList that we found or created. |
1157 | 761k | return AttributeList(PA); |
1158 | 761k | } |
1159 | | |
1160 | | AttributeList |
1161 | | AttributeList::get(LLVMContext &C, |
1162 | 90.4k | ArrayRef<std::pair<unsigned, Attribute>> Attrs) { |
1163 | | // If there are no attributes then return a null AttributesList pointer. |
1164 | 90.4k | if (Attrs.empty()) |
1165 | 19.6k | return {}; |
1166 | | |
1167 | 70.8k | assert(llvm::is_sorted(Attrs, llvm::less_first()) && |
1168 | 70.8k | "Misordered Attributes list!"); |
1169 | 0 | assert(llvm::all_of(Attrs, |
1170 | 70.8k | [](const std::pair<unsigned, Attribute> &Pair) { |
1171 | 70.8k | return Pair.second.isValid(); |
1172 | 70.8k | }) && |
1173 | 70.8k | "Pointless attribute!"); |
1174 | | |
1175 | | // Create a vector if (unsigned, AttributeSetNode*) pairs from the attributes |
1176 | | // list. |
1177 | 0 | SmallVector<std::pair<unsigned, AttributeSet>, 8> AttrPairVec; |
1178 | 70.8k | for (ArrayRef<std::pair<unsigned, Attribute>>::iterator I = Attrs.begin(), |
1179 | 141k | E = Attrs.end(); I != E; ) { |
1180 | 70.8k | unsigned Index = I->first; |
1181 | 70.8k | SmallVector<Attribute, 4> AttrVec; |
1182 | 141k | while (I != E && I->first == Index) { |
1183 | 70.8k | AttrVec.push_back(I->second); |
1184 | 70.8k | ++I; |
1185 | 70.8k | } |
1186 | | |
1187 | 70.8k | AttrPairVec.emplace_back(Index, AttributeSet::get(C, AttrVec)); |
1188 | 70.8k | } |
1189 | | |
1190 | 70.8k | return get(C, AttrPairVec); |
1191 | 90.4k | } |
1192 | | |
1193 | | AttributeList |
1194 | | AttributeList::get(LLVMContext &C, |
1195 | 594k | ArrayRef<std::pair<unsigned, AttributeSet>> Attrs) { |
1196 | | // If there are no attributes then return a null AttributesList pointer. |
1197 | 594k | if (Attrs.empty()) |
1198 | 0 | return {}; |
1199 | | |
1200 | 594k | assert(llvm::is_sorted(Attrs, llvm::less_first()) && |
1201 | 594k | "Misordered Attributes list!"); |
1202 | 0 | assert(llvm::none_of(Attrs, |
1203 | 594k | [](const std::pair<unsigned, AttributeSet> &Pair) { |
1204 | 594k | return !Pair.second.hasAttributes(); |
1205 | 594k | }) && |
1206 | 594k | "Pointless attribute!"); |
1207 | | |
1208 | 0 | unsigned MaxIndex = Attrs.back().first; |
1209 | | // If the MaxIndex is FunctionIndex and there are other indices in front |
1210 | | // of it, we need to use the largest of those to get the right size. |
1211 | 594k | if (MaxIndex == FunctionIndex && Attrs.size() > 1) |
1212 | 256k | MaxIndex = Attrs[Attrs.size() - 2].first; |
1213 | | |
1214 | 594k | SmallVector<AttributeSet, 4> AttrVec(attrIdxToArrayIdx(MaxIndex) + 1); |
1215 | 594k | for (const auto &Pair : Attrs) |
1216 | 1.11M | AttrVec[attrIdxToArrayIdx(Pair.first)] = Pair.second; |
1217 | | |
1218 | 594k | return getImpl(C, AttrVec); |
1219 | 594k | } |
1220 | | |
1221 | | AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs, |
1222 | | AttributeSet RetAttrs, |
1223 | 3.16k | ArrayRef<AttributeSet> ArgAttrs) { |
1224 | | // Scan from the end to find the last argument with attributes. Most |
1225 | | // arguments don't have attributes, so it's nice if we can have fewer unique |
1226 | | // AttributeListImpls by dropping empty attribute sets at the end of the list. |
1227 | 3.16k | unsigned NumSets = 0; |
1228 | 8.13k | for (size_t I = ArgAttrs.size(); I != 0; --I) { |
1229 | 5.09k | if (ArgAttrs[I - 1].hasAttributes()) { |
1230 | 127 | NumSets = I + 2; |
1231 | 127 | break; |
1232 | 127 | } |
1233 | 5.09k | } |
1234 | 3.16k | if (NumSets == 0) { |
1235 | | // Check function and return attributes if we didn't have argument |
1236 | | // attributes. |
1237 | 3.03k | if (RetAttrs.hasAttributes()) |
1238 | 728 | NumSets = 2; |
1239 | 2.30k | else if (FnAttrs.hasAttributes()) |
1240 | 17 | NumSets = 1; |
1241 | 3.03k | } |
1242 | | |
1243 | | // If all attribute sets were empty, we can use the empty attribute list. |
1244 | 3.16k | if (NumSets == 0) |
1245 | 2.28k | return {}; |
1246 | | |
1247 | 872 | SmallVector<AttributeSet, 8> AttrSets; |
1248 | 872 | AttrSets.reserve(NumSets); |
1249 | | // If we have any attributes, we always have function attributes. |
1250 | 872 | AttrSets.push_back(FnAttrs); |
1251 | 872 | if (NumSets > 1) |
1252 | 855 | AttrSets.push_back(RetAttrs); |
1253 | 872 | if (NumSets > 2) { |
1254 | | // Drop the empty argument attribute sets at the end. |
1255 | 127 | ArgAttrs = ArgAttrs.take_front(NumSets - 2); |
1256 | 127 | llvm::append_range(AttrSets, ArgAttrs); |
1257 | 127 | } |
1258 | | |
1259 | 872 | return getImpl(C, AttrSets); |
1260 | 3.16k | } |
1261 | | |
1262 | | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, |
1263 | 112k | AttributeSet Attrs) { |
1264 | 112k | if (!Attrs.hasAttributes()) |
1265 | 342 | return {}; |
1266 | 111k | Index = attrIdxToArrayIdx(Index); |
1267 | 111k | SmallVector<AttributeSet, 8> AttrSets(Index + 1); |
1268 | 111k | AttrSets[Index] = Attrs; |
1269 | 111k | return getImpl(C, AttrSets); |
1270 | 112k | } |
1271 | | |
1272 | | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, |
1273 | 112k | const AttrBuilder &B) { |
1274 | 112k | return get(C, Index, AttributeSet::get(C, B)); |
1275 | 112k | } |
1276 | | |
1277 | | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, |
1278 | 90.4k | ArrayRef<Attribute::AttrKind> Kinds) { |
1279 | 90.4k | SmallVector<std::pair<unsigned, Attribute>, 8> Attrs; |
1280 | 90.4k | for (const auto K : Kinds) |
1281 | 70.8k | Attrs.emplace_back(Index, Attribute::get(C, K)); |
1282 | 90.4k | return get(C, Attrs); |
1283 | 90.4k | } |
1284 | | |
1285 | | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, |
1286 | | ArrayRef<Attribute::AttrKind> Kinds, |
1287 | 0 | ArrayRef<uint64_t> Values) { |
1288 | 0 | assert(Kinds.size() == Values.size() && "Mismatched attribute values."); |
1289 | 0 | SmallVector<std::pair<unsigned, Attribute>, 8> Attrs; |
1290 | 0 | auto VI = Values.begin(); |
1291 | 0 | for (const auto K : Kinds) |
1292 | 0 | Attrs.emplace_back(Index, Attribute::get(C, K, *VI++)); |
1293 | 0 | return get(C, Attrs); |
1294 | 0 | } |
1295 | | |
1296 | | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, |
1297 | 0 | ArrayRef<StringRef> Kinds) { |
1298 | 0 | SmallVector<std::pair<unsigned, Attribute>, 8> Attrs; |
1299 | 0 | for (const auto &K : Kinds) |
1300 | 0 | Attrs.emplace_back(Index, Attribute::get(C, K)); |
1301 | 0 | return get(C, Attrs); |
1302 | 0 | } |
1303 | | |
1304 | | AttributeList AttributeList::get(LLVMContext &C, |
1305 | 81.5k | ArrayRef<AttributeList> Attrs) { |
1306 | 81.5k | if (Attrs.empty()) |
1307 | 9 | return {}; |
1308 | 81.5k | if (Attrs.size() == 1) |
1309 | 46.8k | return Attrs[0]; |
1310 | | |
1311 | 34.7k | unsigned MaxSize = 0; |
1312 | 34.7k | for (const auto &List : Attrs) |
1313 | 101k | MaxSize = std::max(MaxSize, List.getNumAttrSets()); |
1314 | | |
1315 | | // If every list was empty, there is no point in merging the lists. |
1316 | 34.7k | if (MaxSize == 0) |
1317 | 98 | return {}; |
1318 | | |
1319 | 34.6k | SmallVector<AttributeSet, 8> NewAttrSets(MaxSize); |
1320 | 21.0M | for (unsigned I = 0; I < MaxSize; ++I) { |
1321 | 21.0M | AttrBuilder CurBuilder(C); |
1322 | 21.0M | for (const auto &List : Attrs) |
1323 | 111M | CurBuilder.merge(AttrBuilder(C, List.getAttributes(I - 1))); |
1324 | 21.0M | NewAttrSets[I] = AttributeSet::get(C, CurBuilder); |
1325 | 21.0M | } |
1326 | | |
1327 | 34.6k | return getImpl(C, NewAttrSets); |
1328 | 34.7k | } |
1329 | | |
1330 | | AttributeList |
1331 | | AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, |
1332 | 5.37k | Attribute::AttrKind Kind) const { |
1333 | 5.37k | AttributeSet Attrs = getAttributes(Index); |
1334 | 5.37k | if (Attrs.hasAttribute(Kind)) |
1335 | 107 | return *this; |
1336 | | // TODO: Insert at correct position and avoid sort. |
1337 | 5.26k | SmallVector<Attribute, 8> NewAttrs(Attrs.begin(), Attrs.end()); |
1338 | 5.26k | NewAttrs.push_back(Attribute::get(C, Kind)); |
1339 | 5.26k | return setAttributesAtIndex(C, Index, AttributeSet::get(C, NewAttrs)); |
1340 | 5.37k | } |
1341 | | |
1342 | | AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, |
1343 | | StringRef Kind, |
1344 | 7.76k | StringRef Value) const { |
1345 | 7.76k | AttrBuilder B(C); |
1346 | 7.76k | B.addAttribute(Kind, Value); |
1347 | 7.76k | return addAttributesAtIndex(C, Index, B); |
1348 | 7.76k | } |
1349 | | |
1350 | | AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, |
1351 | 1.36k | Attribute A) const { |
1352 | 1.36k | AttrBuilder B(C); |
1353 | 1.36k | B.addAttribute(A); |
1354 | 1.36k | return addAttributesAtIndex(C, Index, B); |
1355 | 1.36k | } |
1356 | | |
1357 | | AttributeList AttributeList::setAttributesAtIndex(LLVMContext &C, |
1358 | | unsigned Index, |
1359 | 10.2k | AttributeSet Attrs) const { |
1360 | 10.2k | Index = attrIdxToArrayIdx(Index); |
1361 | 10.2k | SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end()); |
1362 | 10.2k | if (Index >= AttrSets.size()) |
1363 | 1.91k | AttrSets.resize(Index + 1); |
1364 | 10.2k | AttrSets[Index] = Attrs; |
1365 | | |
1366 | | // Remove trailing empty attribute sets. |
1367 | 10.8k | while (!AttrSets.empty() && !AttrSets.back().hasAttributes()) |
1368 | 629 | AttrSets.pop_back(); |
1369 | 10.2k | if (AttrSets.empty()) |
1370 | 139 | return {}; |
1371 | 10.0k | return AttributeList::getImpl(C, AttrSets); |
1372 | 10.2k | } |
1373 | | |
1374 | | AttributeList AttributeList::addAttributesAtIndex(LLVMContext &C, |
1375 | | unsigned Index, |
1376 | 806k | const AttrBuilder &B) const { |
1377 | 806k | if (!B.hasAttributes()) |
1378 | 796k | return *this; |
1379 | | |
1380 | 9.12k | if (!pImpl) |
1381 | 6.09k | return AttributeList::get(C, {{Index, AttributeSet::get(C, B)}}); |
1382 | | |
1383 | 3.02k | AttrBuilder Merged(C, getAttributes(Index)); |
1384 | 3.02k | Merged.merge(B); |
1385 | 3.02k | return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged)); |
1386 | 9.12k | } |
1387 | | |
1388 | | AttributeList AttributeList::addParamAttribute(LLVMContext &C, |
1389 | | ArrayRef<unsigned> ArgNos, |
1390 | 9.56k | Attribute A) const { |
1391 | 9.56k | assert(llvm::is_sorted(ArgNos)); |
1392 | | |
1393 | 0 | SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end()); |
1394 | 9.56k | unsigned MaxIndex = attrIdxToArrayIdx(ArgNos.back() + FirstArgIndex); |
1395 | 9.56k | if (MaxIndex >= AttrSets.size()) |
1396 | 4.74k | AttrSets.resize(MaxIndex + 1); |
1397 | | |
1398 | 10.4k | for (unsigned ArgNo : ArgNos) { |
1399 | 10.4k | unsigned Index = attrIdxToArrayIdx(ArgNo + FirstArgIndex); |
1400 | 10.4k | AttrBuilder B(C, AttrSets[Index]); |
1401 | 10.4k | B.addAttribute(A); |
1402 | 10.4k | AttrSets[Index] = AttributeSet::get(C, B); |
1403 | 10.4k | } |
1404 | | |
1405 | 9.56k | return getImpl(C, AttrSets); |
1406 | 9.56k | } |
1407 | | |
1408 | | AttributeList |
1409 | | AttributeList::removeAttributeAtIndex(LLVMContext &C, unsigned Index, |
1410 | 10.1k | Attribute::AttrKind Kind) const { |
1411 | 10.1k | AttributeSet Attrs = getAttributes(Index); |
1412 | 10.1k | AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind); |
1413 | 10.1k | if (Attrs == NewAttrs) |
1414 | 8.27k | return *this; |
1415 | 1.85k | return setAttributesAtIndex(C, Index, NewAttrs); |
1416 | 10.1k | } |
1417 | | |
1418 | | AttributeList AttributeList::removeAttributeAtIndex(LLVMContext &C, |
1419 | | unsigned Index, |
1420 | 15.5k | StringRef Kind) const { |
1421 | 15.5k | AttributeSet Attrs = getAttributes(Index); |
1422 | 15.5k | AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind); |
1423 | 15.5k | if (Attrs == NewAttrs) |
1424 | 15.5k | return *this; |
1425 | 0 | return setAttributesAtIndex(C, Index, NewAttrs); |
1426 | 15.5k | } |
1427 | | |
1428 | | AttributeList AttributeList::removeAttributesAtIndex( |
1429 | 13.5M | LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const { |
1430 | 13.5M | AttributeSet Attrs = getAttributes(Index); |
1431 | 13.5M | AttributeSet NewAttrs = Attrs.removeAttributes(C, AttrsToRemove); |
1432 | | // If nothing was removed, return the original list. |
1433 | 13.5M | if (Attrs == NewAttrs) |
1434 | 13.5M | return *this; |
1435 | 61 | return setAttributesAtIndex(C, Index, NewAttrs); |
1436 | 13.5M | } |
1437 | | |
1438 | | AttributeList |
1439 | | AttributeList::removeAttributesAtIndex(LLVMContext &C, |
1440 | 1.86k | unsigned WithoutIndex) const { |
1441 | 1.86k | if (!pImpl) |
1442 | 1.86k | return {}; |
1443 | 2 | if (attrIdxToArrayIdx(WithoutIndex) >= getNumAttrSets()) |
1444 | 0 | return *this; |
1445 | 2 | return setAttributesAtIndex(C, WithoutIndex, AttributeSet()); |
1446 | 2 | } |
1447 | | |
1448 | | AttributeList AttributeList::addDereferenceableRetAttr(LLVMContext &C, |
1449 | 0 | uint64_t Bytes) const { |
1450 | 0 | AttrBuilder B(C); |
1451 | 0 | B.addDereferenceableAttr(Bytes); |
1452 | 0 | return addRetAttributes(C, B); |
1453 | 0 | } |
1454 | | |
1455 | | AttributeList AttributeList::addDereferenceableParamAttr(LLVMContext &C, |
1456 | | unsigned Index, |
1457 | 0 | uint64_t Bytes) const { |
1458 | 0 | AttrBuilder B(C); |
1459 | 0 | B.addDereferenceableAttr(Bytes); |
1460 | 0 | return addParamAttributes(C, Index, B); |
1461 | 0 | } |
1462 | | |
1463 | | AttributeList |
1464 | | AttributeList::addDereferenceableOrNullParamAttr(LLVMContext &C, unsigned Index, |
1465 | 0 | uint64_t Bytes) const { |
1466 | 0 | AttrBuilder B(C); |
1467 | 0 | B.addDereferenceableOrNullAttr(Bytes); |
1468 | 0 | return addParamAttributes(C, Index, B); |
1469 | 0 | } |
1470 | | |
1471 | | AttributeList AttributeList::addAllocSizeParamAttr( |
1472 | | LLVMContext &C, unsigned Index, unsigned ElemSizeArg, |
1473 | 0 | const std::optional<unsigned> &NumElemsArg) { |
1474 | 0 | AttrBuilder B(C); |
1475 | 0 | B.addAllocSizeAttr(ElemSizeArg, NumElemsArg); |
1476 | 0 | return addParamAttributes(C, Index, B); |
1477 | 0 | } |
1478 | | |
1479 | | //===----------------------------------------------------------------------===// |
1480 | | // AttributeList Accessor Methods |
1481 | | //===----------------------------------------------------------------------===// |
1482 | | |
1483 | 2.73M | AttributeSet AttributeList::getParamAttrs(unsigned ArgNo) const { |
1484 | 2.73M | return getAttributes(ArgNo + FirstArgIndex); |
1485 | 2.73M | } |
1486 | | |
1487 | 766k | AttributeSet AttributeList::getRetAttrs() const { |
1488 | 766k | return getAttributes(ReturnIndex); |
1489 | 766k | } |
1490 | | |
1491 | 5.75M | AttributeSet AttributeList::getFnAttrs() const { |
1492 | 5.75M | return getAttributes(FunctionIndex); |
1493 | 5.75M | } |
1494 | | |
1495 | | bool AttributeList::hasAttributeAtIndex(unsigned Index, |
1496 | 39.7M | Attribute::AttrKind Kind) const { |
1497 | 39.7M | return getAttributes(Index).hasAttribute(Kind); |
1498 | 39.7M | } |
1499 | | |
1500 | 24.5M | bool AttributeList::hasAttributeAtIndex(unsigned Index, StringRef Kind) const { |
1501 | 24.5M | return getAttributes(Index).hasAttribute(Kind); |
1502 | 24.5M | } |
1503 | | |
1504 | 549k | bool AttributeList::hasAttributesAtIndex(unsigned Index) const { |
1505 | 549k | return getAttributes(Index).hasAttributes(); |
1506 | 549k | } |
1507 | | |
1508 | 50.2M | bool AttributeList::hasFnAttr(Attribute::AttrKind Kind) const { |
1509 | 50.2M | return pImpl && pImpl->hasFnAttribute(Kind); |
1510 | 50.2M | } |
1511 | | |
1512 | 24.5M | bool AttributeList::hasFnAttr(StringRef Kind) const { |
1513 | 24.5M | return hasAttributeAtIndex(AttributeList::FunctionIndex, Kind); |
1514 | 24.5M | } |
1515 | | |
1516 | | bool AttributeList::hasAttrSomewhere(Attribute::AttrKind Attr, |
1517 | 6.34M | unsigned *Index) const { |
1518 | 6.34M | return pImpl && pImpl->hasAttrSomewhere(Attr, Index); |
1519 | 6.34M | } |
1520 | | |
1521 | | Attribute AttributeList::getAttributeAtIndex(unsigned Index, |
1522 | 905k | Attribute::AttrKind Kind) const { |
1523 | 905k | return getAttributes(Index).getAttribute(Kind); |
1524 | 905k | } |
1525 | | |
1526 | | Attribute AttributeList::getAttributeAtIndex(unsigned Index, |
1527 | 18.5M | StringRef Kind) const { |
1528 | 18.5M | return getAttributes(Index).getAttribute(Kind); |
1529 | 18.5M | } |
1530 | | |
1531 | 8.93k | MaybeAlign AttributeList::getRetAlignment() const { |
1532 | 8.93k | return getAttributes(ReturnIndex).getAlignment(); |
1533 | 8.93k | } |
1534 | | |
1535 | 113k | MaybeAlign AttributeList::getParamAlignment(unsigned ArgNo) const { |
1536 | 113k | return getAttributes(ArgNo + FirstArgIndex).getAlignment(); |
1537 | 113k | } |
1538 | | |
1539 | 224k | MaybeAlign AttributeList::getParamStackAlignment(unsigned ArgNo) const { |
1540 | 224k | return getAttributes(ArgNo + FirstArgIndex).getStackAlignment(); |
1541 | 224k | } |
1542 | | |
1543 | 27 | Type *AttributeList::getParamByValType(unsigned Index) const { |
1544 | 27 | return getAttributes(Index+FirstArgIndex).getByValType(); |
1545 | 27 | } |
1546 | | |
1547 | 44 | Type *AttributeList::getParamStructRetType(unsigned Index) const { |
1548 | 44 | return getAttributes(Index + FirstArgIndex).getStructRetType(); |
1549 | 44 | } |
1550 | | |
1551 | 0 | Type *AttributeList::getParamByRefType(unsigned Index) const { |
1552 | 0 | return getAttributes(Index + FirstArgIndex).getByRefType(); |
1553 | 0 | } |
1554 | | |
1555 | 0 | Type *AttributeList::getParamPreallocatedType(unsigned Index) const { |
1556 | 0 | return getAttributes(Index + FirstArgIndex).getPreallocatedType(); |
1557 | 0 | } |
1558 | | |
1559 | 1 | Type *AttributeList::getParamInAllocaType(unsigned Index) const { |
1560 | 1 | return getAttributes(Index + FirstArgIndex).getInAllocaType(); |
1561 | 1 | } |
1562 | | |
1563 | 716 | Type *AttributeList::getParamElementType(unsigned Index) const { |
1564 | 716 | return getAttributes(Index + FirstArgIndex).getElementType(); |
1565 | 716 | } |
1566 | | |
1567 | 130k | MaybeAlign AttributeList::getFnStackAlignment() const { |
1568 | 130k | return getFnAttrs().getStackAlignment(); |
1569 | 130k | } |
1570 | | |
1571 | 0 | MaybeAlign AttributeList::getRetStackAlignment() const { |
1572 | 0 | return getRetAttrs().getStackAlignment(); |
1573 | 0 | } |
1574 | | |
1575 | 90.4k | uint64_t AttributeList::getRetDereferenceableBytes() const { |
1576 | 90.4k | return getRetAttrs().getDereferenceableBytes(); |
1577 | 90.4k | } |
1578 | | |
1579 | 425k | uint64_t AttributeList::getParamDereferenceableBytes(unsigned Index) const { |
1580 | 425k | return getParamAttrs(Index).getDereferenceableBytes(); |
1581 | 425k | } |
1582 | | |
1583 | 89.0k | uint64_t AttributeList::getRetDereferenceableOrNullBytes() const { |
1584 | 89.0k | return getRetAttrs().getDereferenceableOrNullBytes(); |
1585 | 89.0k | } |
1586 | | |
1587 | | uint64_t |
1588 | 408k | AttributeList::getParamDereferenceableOrNullBytes(unsigned Index) const { |
1589 | 408k | return getParamAttrs(Index).getDereferenceableOrNullBytes(); |
1590 | 408k | } |
1591 | | |
1592 | 4.96k | FPClassTest AttributeList::getRetNoFPClass() const { |
1593 | 4.96k | return getRetAttrs().getNoFPClass(); |
1594 | 4.96k | } |
1595 | | |
1596 | 14.3k | FPClassTest AttributeList::getParamNoFPClass(unsigned Index) const { |
1597 | 14.3k | return getParamAttrs(Index).getNoFPClass(); |
1598 | 14.3k | } |
1599 | | |
1600 | 709k | UWTableKind AttributeList::getUWTableKind() const { |
1601 | 709k | return getFnAttrs().getUWTableKind(); |
1602 | 709k | } |
1603 | | |
1604 | 11.6k | AllocFnKind AttributeList::getAllocKind() const { |
1605 | 11.6k | return getFnAttrs().getAllocKind(); |
1606 | 11.6k | } |
1607 | | |
1608 | 575k | MemoryEffects AttributeList::getMemoryEffects() const { |
1609 | 575k | return getFnAttrs().getMemoryEffects(); |
1610 | 575k | } |
1611 | | |
1612 | 0 | std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const { |
1613 | 0 | return getAttributes(Index).getAsString(InAttrGrp); |
1614 | 0 | } |
1615 | | |
1616 | 219M | AttributeSet AttributeList::getAttributes(unsigned Index) const { |
1617 | 219M | Index = attrIdxToArrayIdx(Index); |
1618 | 219M | if (!pImpl || Index >= getNumAttrSets()) |
1619 | 170M | return {}; |
1620 | 48.7M | return pImpl->begin()[Index]; |
1621 | 219M | } |
1622 | | |
1623 | 150k | bool AttributeList::hasParentContext(LLVMContext &C) const { |
1624 | 150k | assert(!isEmpty() && "an empty attribute list has no parent context"); |
1625 | 0 | FoldingSetNodeID ID; |
1626 | 150k | pImpl->Profile(ID); |
1627 | 150k | void *Unused; |
1628 | 150k | return C.pImpl->AttrsLists.FindNodeOrInsertPos(ID, Unused) == pImpl; |
1629 | 150k | } |
1630 | | |
1631 | 169k | AttributeList::iterator AttributeList::begin() const { |
1632 | 169k | return pImpl ? pImpl->begin() : nullptr; |
1633 | 169k | } |
1634 | | |
1635 | 169k | AttributeList::iterator AttributeList::end() const { |
1636 | 169k | return pImpl ? pImpl->end() : nullptr; |
1637 | 169k | } |
1638 | | |
1639 | | //===----------------------------------------------------------------------===// |
1640 | | // AttributeList Introspection Methods |
1641 | | //===----------------------------------------------------------------------===// |
1642 | | |
1643 | 112M | unsigned AttributeList::getNumAttrSets() const { |
1644 | 112M | return pImpl ? pImpl->NumAttrSets : 0; |
1645 | 112M | } |
1646 | | |
1647 | 0 | void AttributeList::print(raw_ostream &O) const { |
1648 | 0 | O << "AttributeList[\n"; |
1649 | |
|
1650 | 0 | for (unsigned i : indexes()) { |
1651 | 0 | if (!getAttributes(i).hasAttributes()) |
1652 | 0 | continue; |
1653 | 0 | O << " { "; |
1654 | 0 | switch (i) { |
1655 | 0 | case AttrIndex::ReturnIndex: |
1656 | 0 | O << "return"; |
1657 | 0 | break; |
1658 | 0 | case AttrIndex::FunctionIndex: |
1659 | 0 | O << "function"; |
1660 | 0 | break; |
1661 | 0 | default: |
1662 | 0 | O << "arg(" << i - AttrIndex::FirstArgIndex << ")"; |
1663 | 0 | } |
1664 | 0 | O << " => " << getAsString(i) << " }\n"; |
1665 | 0 | } |
1666 | | |
1667 | 0 | O << "]\n"; |
1668 | 0 | } |
1669 | | |
1670 | | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
1671 | 0 | LLVM_DUMP_METHOD void AttributeList::dump() const { print(dbgs()); } |
1672 | | #endif |
1673 | | |
1674 | | //===----------------------------------------------------------------------===// |
1675 | | // AttrBuilder Method Implementations |
1676 | | //===----------------------------------------------------------------------===// |
1677 | | |
1678 | 125M | AttrBuilder::AttrBuilder(LLVMContext &Ctx, AttributeSet AS) : Ctx(Ctx) { |
1679 | 125M | append_range(Attrs, AS); |
1680 | 125M | assert(is_sorted(Attrs) && "AttributeSet should be sorted"); |
1681 | 125M | } |
1682 | | |
1683 | 61.1k | void AttrBuilder::clear() { Attrs.clear(); } |
1684 | | |
1685 | | /// Attribute comparator that only compares attribute keys. Enum attributes are |
1686 | | /// sorted before string attributes. |
1687 | | struct AttributeComparator { |
1688 | 0 | bool operator()(Attribute A0, Attribute A1) const { |
1689 | 0 | bool A0IsString = A0.isStringAttribute(); |
1690 | 0 | bool A1IsString = A1.isStringAttribute(); |
1691 | 0 | if (A0IsString) { |
1692 | 0 | if (A1IsString) |
1693 | 0 | return A0.getKindAsString() < A1.getKindAsString(); |
1694 | 0 | else |
1695 | 0 | return false; |
1696 | 0 | } |
1697 | 0 | if (A1IsString) |
1698 | 0 | return true; |
1699 | 0 | return A0.getKindAsEnum() < A1.getKindAsEnum(); |
1700 | 0 | } |
1701 | 458k | bool operator()(Attribute A0, Attribute::AttrKind Kind) const { |
1702 | 458k | if (A0.isStringAttribute()) |
1703 | 71.3k | return false; |
1704 | 386k | return A0.getKindAsEnum() < Kind; |
1705 | 458k | } |
1706 | 2.09M | bool operator()(Attribute A0, StringRef Kind) const { |
1707 | 2.09M | if (A0.isStringAttribute()) |
1708 | 1.50M | return A0.getKindAsString() < Kind; |
1709 | 588k | return true; |
1710 | 2.09M | } |
1711 | | }; |
1712 | | |
1713 | | template <typename K> |
1714 | | static void addAttributeImpl(SmallVectorImpl<Attribute> &Attrs, K Kind, |
1715 | 896k | Attribute Attr) { |
1716 | 896k | auto It = lower_bound(Attrs, Kind, AttributeComparator()); |
1717 | 896k | if (It != Attrs.end() && It->hasAttribute(Kind)) |
1718 | 281k | std::swap(*It, Attr); |
1719 | 615k | else |
1720 | 615k | Attrs.insert(It, Attr); |
1721 | 896k | } Attributes.cpp:void addAttributeImpl<llvm::StringRef>(llvm::SmallVectorImpl<llvm::Attribute>&, llvm::StringRef, llvm::Attribute) Line | Count | Source | 1715 | 410k | Attribute Attr) { | 1716 | 410k | auto It = lower_bound(Attrs, Kind, AttributeComparator()); | 1717 | 410k | if (It != Attrs.end() && It->hasAttribute(Kind)) | 1718 | 261k | std::swap(*It, Attr); | 1719 | 148k | else | 1720 | 148k | Attrs.insert(It, Attr); | 1721 | 410k | } |
Attributes.cpp:void addAttributeImpl<llvm::Attribute::AttrKind>(llvm::SmallVectorImpl<llvm::Attribute>&, llvm::Attribute::AttrKind, llvm::Attribute) Line | Count | Source | 1715 | 486k | Attribute Attr) { | 1716 | 486k | auto It = lower_bound(Attrs, Kind, AttributeComparator()); | 1717 | 486k | if (It != Attrs.end() && It->hasAttribute(Kind)) | 1718 | 19.8k | std::swap(*It, Attr); | 1719 | 466k | else | 1720 | 466k | Attrs.insert(It, Attr); | 1721 | 486k | } |
|
1722 | | |
1723 | 261k | AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) { |
1724 | 261k | if (Attr.isStringAttribute()) |
1725 | 13.7k | addAttributeImpl(Attrs, Attr.getKindAsString(), Attr); |
1726 | 247k | else |
1727 | 247k | addAttributeImpl(Attrs, Attr.getKindAsEnum(), Attr); |
1728 | 261k | return *this; |
1729 | 261k | } |
1730 | | |
1731 | 238k | AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Kind) { |
1732 | 238k | addAttributeImpl(Attrs, Kind, Attribute::get(Ctx, Kind)); |
1733 | 238k | return *this; |
1734 | 238k | } |
1735 | | |
1736 | 396k | AttrBuilder &AttrBuilder::addAttribute(StringRef A, StringRef V) { |
1737 | 396k | addAttributeImpl(Attrs, A, Attribute::get(Ctx, A, V)); |
1738 | 396k | return *this; |
1739 | 396k | } |
1740 | | |
1741 | 209k | AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) { |
1742 | 209k | assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); |
1743 | 0 | auto It = lower_bound(Attrs, Val, AttributeComparator()); |
1744 | 209k | if (It != Attrs.end() && It->hasAttribute(Val)) |
1745 | 2.05k | Attrs.erase(It); |
1746 | 209k | return *this; |
1747 | 209k | } |
1748 | | |
1749 | 518 | AttrBuilder &AttrBuilder::removeAttribute(StringRef A) { |
1750 | 518 | auto It = lower_bound(Attrs, A, AttributeComparator()); |
1751 | 518 | if (It != Attrs.end() && It->hasAttribute(A)) |
1752 | 518 | Attrs.erase(It); |
1753 | 518 | return *this; |
1754 | 518 | } |
1755 | | |
1756 | | std::optional<uint64_t> |
1757 | 4.70k | AttrBuilder::getRawIntAttr(Attribute::AttrKind Kind) const { |
1758 | 4.70k | assert(Attribute::isIntAttrKind(Kind) && "Not an int attribute"); |
1759 | 0 | Attribute A = getAttribute(Kind); |
1760 | 4.70k | if (A.isValid()) |
1761 | 0 | return A.getValueAsInt(); |
1762 | 4.70k | return std::nullopt; |
1763 | 4.70k | } |
1764 | | |
1765 | | AttrBuilder &AttrBuilder::addRawIntAttr(Attribute::AttrKind Kind, |
1766 | 40.0k | uint64_t Value) { |
1767 | 40.0k | return addAttribute(Attribute::get(Ctx, Kind, Value)); |
1768 | 40.0k | } |
1769 | | |
1770 | | std::optional<std::pair<unsigned, std::optional<unsigned>>> |
1771 | 0 | AttrBuilder::getAllocSizeArgs() const { |
1772 | 0 | Attribute A = getAttribute(Attribute::AllocSize); |
1773 | 0 | if (A.isValid()) |
1774 | 0 | return A.getAllocSizeArgs(); |
1775 | 0 | return std::nullopt; |
1776 | 0 | } |
1777 | | |
1778 | 4.44k | AttrBuilder &AttrBuilder::addAlignmentAttr(MaybeAlign Align) { |
1779 | 4.44k | if (!Align) |
1780 | 0 | return *this; |
1781 | | |
1782 | 4.44k | assert(*Align <= llvm::Value::MaximumAlignment && "Alignment too large."); |
1783 | 0 | return addRawIntAttr(Attribute::Alignment, Align->value()); |
1784 | 4.44k | } |
1785 | | |
1786 | 1 | AttrBuilder &AttrBuilder::addStackAlignmentAttr(MaybeAlign Align) { |
1787 | | // Default alignment, allow the target to define how to align it. |
1788 | 1 | if (!Align) |
1789 | 0 | return *this; |
1790 | | |
1791 | 1 | assert(*Align <= 0x100 && "Alignment too large."); |
1792 | 0 | return addRawIntAttr(Attribute::StackAlignment, Align->value()); |
1793 | 1 | } |
1794 | | |
1795 | 1.06k | AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) { |
1796 | 1.06k | if (Bytes == 0) return *this; |
1797 | | |
1798 | 1.06k | return addRawIntAttr(Attribute::Dereferenceable, Bytes); |
1799 | 1.06k | } |
1800 | | |
1801 | 195 | AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) { |
1802 | 195 | if (Bytes == 0) |
1803 | 0 | return *this; |
1804 | | |
1805 | 195 | return addRawIntAttr(Attribute::DereferenceableOrNull, Bytes); |
1806 | 195 | } |
1807 | | |
1808 | | AttrBuilder & |
1809 | | AttrBuilder::addAllocSizeAttr(unsigned ElemSize, |
1810 | 0 | const std::optional<unsigned> &NumElems) { |
1811 | 0 | return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems)); |
1812 | 0 | } |
1813 | | |
1814 | 471 | AttrBuilder &AttrBuilder::addAllocSizeAttrFromRawRepr(uint64_t RawArgs) { |
1815 | | // (0, 0) is our "not present" value, so we need to check for it here. |
1816 | 471 | assert(RawArgs && "Invalid allocsize arguments -- given allocsize(0, 0)"); |
1817 | 0 | return addRawIntAttr(Attribute::AllocSize, RawArgs); |
1818 | 471 | } |
1819 | | |
1820 | | AttrBuilder &AttrBuilder::addVScaleRangeAttr(unsigned MinValue, |
1821 | 0 | std::optional<unsigned> MaxValue) { |
1822 | 0 | return addVScaleRangeAttrFromRawRepr(packVScaleRangeArgs(MinValue, MaxValue)); |
1823 | 0 | } |
1824 | | |
1825 | 0 | AttrBuilder &AttrBuilder::addVScaleRangeAttrFromRawRepr(uint64_t RawArgs) { |
1826 | | // (0, 0) is not present hence ignore this case |
1827 | 0 | if (RawArgs == 0) |
1828 | 0 | return *this; |
1829 | | |
1830 | 0 | return addRawIntAttr(Attribute::VScaleRange, RawArgs); |
1831 | 0 | } |
1832 | | |
1833 | 5.85k | AttrBuilder &AttrBuilder::addUWTableAttr(UWTableKind Kind) { |
1834 | 5.85k | if (Kind == UWTableKind::None) |
1835 | 0 | return *this; |
1836 | 5.85k | return addRawIntAttr(Attribute::UWTable, uint64_t(Kind)); |
1837 | 5.85k | } |
1838 | | |
1839 | 28.0k | AttrBuilder &AttrBuilder::addMemoryAttr(MemoryEffects ME) { |
1840 | 28.0k | return addRawIntAttr(Attribute::Memory, ME.toIntValue()); |
1841 | 28.0k | } |
1842 | | |
1843 | 1 | AttrBuilder &AttrBuilder::addNoFPClassAttr(FPClassTest Mask) { |
1844 | 1 | if (Mask == fcNone) |
1845 | 0 | return *this; |
1846 | | |
1847 | 1 | return addRawIntAttr(Attribute::NoFPClass, Mask); |
1848 | 1 | } |
1849 | | |
1850 | 0 | AttrBuilder &AttrBuilder::addAllocKindAttr(AllocFnKind Kind) { |
1851 | 0 | return addRawIntAttr(Attribute::AllocKind, static_cast<uint64_t>(Kind)); |
1852 | 0 | } |
1853 | | |
1854 | 0 | Type *AttrBuilder::getTypeAttr(Attribute::AttrKind Kind) const { |
1855 | 0 | assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute"); |
1856 | 0 | Attribute A = getAttribute(Kind); |
1857 | 0 | return A.isValid() ? A.getValueAsType() : nullptr; |
1858 | 0 | } |
1859 | | |
1860 | 1.47k | AttrBuilder &AttrBuilder::addTypeAttr(Attribute::AttrKind Kind, Type *Ty) { |
1861 | 1.47k | return addAttribute(Attribute::get(Ctx, Kind, Ty)); |
1862 | 1.47k | } |
1863 | | |
1864 | 51 | AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) { |
1865 | 51 | return addTypeAttr(Attribute::ByVal, Ty); |
1866 | 51 | } |
1867 | | |
1868 | 40 | AttrBuilder &AttrBuilder::addStructRetAttr(Type *Ty) { |
1869 | 40 | return addTypeAttr(Attribute::StructRet, Ty); |
1870 | 40 | } |
1871 | | |
1872 | 0 | AttrBuilder &AttrBuilder::addByRefAttr(Type *Ty) { |
1873 | 0 | return addTypeAttr(Attribute::ByRef, Ty); |
1874 | 0 | } |
1875 | | |
1876 | 0 | AttrBuilder &AttrBuilder::addPreallocatedAttr(Type *Ty) { |
1877 | 0 | return addTypeAttr(Attribute::Preallocated, Ty); |
1878 | 0 | } |
1879 | | |
1880 | 21 | AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) { |
1881 | 21 | return addTypeAttr(Attribute::InAlloca, Ty); |
1882 | 21 | } |
1883 | | |
1884 | 111M | AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) { |
1885 | | // TODO: Could make this O(n) as we're merging two sorted lists. |
1886 | 111M | for (const auto &I : B.attrs()) |
1887 | 208k | addAttribute(I); |
1888 | | |
1889 | 111M | return *this; |
1890 | 111M | } |
1891 | | |
1892 | 109 | AttrBuilder &AttrBuilder::remove(const AttributeMask &AM) { |
1893 | 109 | erase_if(Attrs, [&](Attribute A) { return AM.contains(A); }); |
1894 | 109 | return *this; |
1895 | 109 | } |
1896 | | |
1897 | 13.5M | bool AttrBuilder::overlaps(const AttributeMask &AM) const { |
1898 | 13.5M | return any_of(Attrs, [&](Attribute A) { return AM.contains(A); }); |
1899 | 13.5M | } |
1900 | | |
1901 | 76.0k | Attribute AttrBuilder::getAttribute(Attribute::AttrKind A) const { |
1902 | 76.0k | assert((unsigned)A < Attribute::EndAttrKinds && "Attribute out of range!"); |
1903 | 0 | auto It = lower_bound(Attrs, A, AttributeComparator()); |
1904 | 76.0k | if (It != Attrs.end() && It->hasAttribute(A)) |
1905 | 21 | return *It; |
1906 | 76.0k | return {}; |
1907 | 76.0k | } |
1908 | | |
1909 | 332k | Attribute AttrBuilder::getAttribute(StringRef A) const { |
1910 | 332k | auto It = lower_bound(Attrs, A, AttributeComparator()); |
1911 | 332k | if (It != Attrs.end() && It->hasAttribute(A)) |
1912 | 518 | return *It; |
1913 | 331k | return {}; |
1914 | 332k | } |
1915 | | |
1916 | 71.3k | bool AttrBuilder::contains(Attribute::AttrKind A) const { |
1917 | 71.3k | return getAttribute(A).isValid(); |
1918 | 71.3k | } |
1919 | | |
1920 | 110k | bool AttrBuilder::contains(StringRef A) const { |
1921 | 110k | return getAttribute(A).isValid(); |
1922 | 110k | } |
1923 | | |
1924 | 350 | bool AttrBuilder::operator==(const AttrBuilder &B) const { |
1925 | 350 | return Attrs == B.Attrs; |
1926 | 350 | } |
1927 | | |
1928 | | //===----------------------------------------------------------------------===// |
1929 | | // AttributeFuncs Function Defintions |
1930 | | //===----------------------------------------------------------------------===// |
1931 | | |
1932 | | /// Returns true if this is a type legal for the 'nofpclass' attribute. This |
1933 | | /// follows the same type rules as FPMathOperator. |
1934 | | /// |
1935 | | /// TODO: Consider relaxing to any FP type struct fields. |
1936 | 14.0M | bool AttributeFuncs::isNoFPClassCompatibleType(Type *Ty) { |
1937 | 14.0M | while (ArrayType *ArrTy = dyn_cast<ArrayType>(Ty)) |
1938 | 16.0k | Ty = ArrTy->getElementType(); |
1939 | 14.0M | return Ty->isFPOrFPVectorTy(); |
1940 | 14.0M | } |
1941 | | |
1942 | | /// Which attributes cannot be applied to a type. |
1943 | | AttributeMask AttributeFuncs::typeIncompatible(Type *Ty, |
1944 | 14.0M | AttributeSafetyKind ASK) { |
1945 | 14.0M | AttributeMask Incompatible; |
1946 | | |
1947 | 14.0M | if (!Ty->isIntegerTy()) { |
1948 | | // Attributes that only apply to integers. |
1949 | 8.84M | if (ASK & ASK_SAFE_TO_DROP) |
1950 | 8.84M | Incompatible.addAttribute(Attribute::AllocAlign); |
1951 | 8.84M | if (ASK & ASK_UNSAFE_TO_DROP) |
1952 | 8.84M | Incompatible.addAttribute(Attribute::SExt).addAttribute(Attribute::ZExt); |
1953 | 8.84M | } |
1954 | | |
1955 | 14.0M | if (!Ty->isPointerTy()) { |
1956 | | // Attributes that only apply to pointers. |
1957 | 12.5M | if (ASK & ASK_SAFE_TO_DROP) |
1958 | 12.5M | Incompatible.addAttribute(Attribute::NoAlias) |
1959 | 12.5M | .addAttribute(Attribute::NoCapture) |
1960 | 12.5M | .addAttribute(Attribute::NonNull) |
1961 | 12.5M | .addAttribute(Attribute::ReadNone) |
1962 | 12.5M | .addAttribute(Attribute::ReadOnly) |
1963 | 12.5M | .addAttribute(Attribute::Dereferenceable) |
1964 | 12.5M | .addAttribute(Attribute::DereferenceableOrNull) |
1965 | 12.5M | .addAttribute(Attribute::Writable) |
1966 | 12.5M | .addAttribute(Attribute::DeadOnUnwind); |
1967 | 12.5M | if (ASK & ASK_UNSAFE_TO_DROP) |
1968 | 12.5M | Incompatible.addAttribute(Attribute::Nest) |
1969 | 12.5M | .addAttribute(Attribute::SwiftError) |
1970 | 12.5M | .addAttribute(Attribute::Preallocated) |
1971 | 12.5M | .addAttribute(Attribute::InAlloca) |
1972 | 12.5M | .addAttribute(Attribute::ByVal) |
1973 | 12.5M | .addAttribute(Attribute::StructRet) |
1974 | 12.5M | .addAttribute(Attribute::ByRef) |
1975 | 12.5M | .addAttribute(Attribute::ElementType) |
1976 | 12.5M | .addAttribute(Attribute::AllocatedPointer); |
1977 | 12.5M | } |
1978 | | |
1979 | | // Attributes that only apply to pointers or vectors of pointers. |
1980 | 14.0M | if (!Ty->isPtrOrPtrVectorTy()) { |
1981 | 12.5M | if (ASK & ASK_SAFE_TO_DROP) |
1982 | 12.5M | Incompatible.addAttribute(Attribute::Alignment); |
1983 | 12.5M | } |
1984 | | |
1985 | 14.0M | if (ASK & ASK_SAFE_TO_DROP) { |
1986 | 14.0M | if (!isNoFPClassCompatibleType(Ty)) |
1987 | 10.1M | Incompatible.addAttribute(Attribute::NoFPClass); |
1988 | 14.0M | } |
1989 | | |
1990 | | // Some attributes can apply to all "values" but there are no `void` values. |
1991 | 14.0M | if (Ty->isVoidTy()) { |
1992 | 839k | if (ASK & ASK_SAFE_TO_DROP) |
1993 | 839k | Incompatible.addAttribute(Attribute::NoUndef); |
1994 | 839k | } |
1995 | | |
1996 | 14.0M | return Incompatible; |
1997 | 14.0M | } |
1998 | | |
1999 | 97 | AttributeMask AttributeFuncs::getUBImplyingAttributes() { |
2000 | 97 | AttributeMask AM; |
2001 | 97 | AM.addAttribute(Attribute::NoUndef); |
2002 | 97 | AM.addAttribute(Attribute::Dereferenceable); |
2003 | 97 | AM.addAttribute(Attribute::DereferenceableOrNull); |
2004 | 97 | return AM; |
2005 | 97 | } |
2006 | | |
2007 | | /// Callees with dynamic denormal modes are compatible with any caller mode. |
2008 | | static bool denormModeCompatible(DenormalMode CallerMode, |
2009 | 0 | DenormalMode CalleeMode) { |
2010 | 0 | if (CallerMode == CalleeMode || CalleeMode == DenormalMode::getDynamic()) |
2011 | 0 | return true; |
2012 | | |
2013 | | // If they don't exactly match, it's OK if the mismatched component is |
2014 | | // dynamic. |
2015 | 0 | if (CalleeMode.Input == CallerMode.Input && |
2016 | 0 | CalleeMode.Output == DenormalMode::Dynamic) |
2017 | 0 | return true; |
2018 | | |
2019 | 0 | if (CalleeMode.Output == CallerMode.Output && |
2020 | 0 | CalleeMode.Input == DenormalMode::Dynamic) |
2021 | 0 | return true; |
2022 | 0 | return false; |
2023 | 0 | } |
2024 | | |
2025 | 0 | static bool checkDenormMode(const Function &Caller, const Function &Callee) { |
2026 | 0 | DenormalMode CallerMode = Caller.getDenormalModeRaw(); |
2027 | 0 | DenormalMode CalleeMode = Callee.getDenormalModeRaw(); |
2028 | |
|
2029 | 0 | if (denormModeCompatible(CallerMode, CalleeMode)) { |
2030 | 0 | DenormalMode CallerModeF32 = Caller.getDenormalModeF32Raw(); |
2031 | 0 | DenormalMode CalleeModeF32 = Callee.getDenormalModeF32Raw(); |
2032 | 0 | if (CallerModeF32 == DenormalMode::getInvalid()) |
2033 | 0 | CallerModeF32 = CallerMode; |
2034 | 0 | if (CalleeModeF32 == DenormalMode::getInvalid()) |
2035 | 0 | CalleeModeF32 = CalleeMode; |
2036 | 0 | return denormModeCompatible(CallerModeF32, CalleeModeF32); |
2037 | 0 | } |
2038 | | |
2039 | 0 | return false; |
2040 | 0 | } |
2041 | | |
2042 | | template<typename AttrClass> |
2043 | 0 | static bool isEqual(const Function &Caller, const Function &Callee) { |
2044 | 0 | return Caller.getFnAttribute(AttrClass::getKind()) == |
2045 | 0 | Callee.getFnAttribute(AttrClass::getKind()); |
2046 | 0 | } Unexecuted instantiation: Attributes.cpp:bool isEqual<SanitizeAddressAttr>(llvm::Function const&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:bool isEqual<SanitizeThreadAttr>(llvm::Function const&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:bool isEqual<SanitizeMemoryAttr>(llvm::Function const&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:bool isEqual<SanitizeHWAddressAttr>(llvm::Function const&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:bool isEqual<SanitizeMemTagAttr>(llvm::Function const&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:bool isEqual<SafeStackAttr>(llvm::Function const&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:bool isEqual<ShadowCallStackAttr>(llvm::Function const&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:bool isEqual<UseSampleProfileAttr>(llvm::Function const&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:bool isEqual<NoProfileAttr>(llvm::Function const&, llvm::Function const&) |
2047 | | |
2048 | | /// Compute the logical AND of the attributes of the caller and the |
2049 | | /// callee. |
2050 | | /// |
2051 | | /// This function sets the caller's attribute to false if the callee's attribute |
2052 | | /// is false. |
2053 | | template<typename AttrClass> |
2054 | 0 | static void setAND(Function &Caller, const Function &Callee) { |
2055 | 0 | if (AttrClass::isSet(Caller, AttrClass::getKind()) && |
2056 | 0 | !AttrClass::isSet(Callee, AttrClass::getKind())) |
2057 | 0 | AttrClass::set(Caller, AttrClass::getKind(), false); |
2058 | 0 | } Unexecuted instantiation: Attributes.cpp:void setAND<LessPreciseFPMADAttr>(llvm::Function&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:void setAND<NoInfsFPMathAttr>(llvm::Function&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:void setAND<NoNansFPMathAttr>(llvm::Function&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:void setAND<ApproxFuncFPMathAttr>(llvm::Function&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:void setAND<NoSignedZerosFPMathAttr>(llvm::Function&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:void setAND<UnsafeFPMathAttr>(llvm::Function&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:void setAND<MustProgressAttr>(llvm::Function&, llvm::Function const&) |
2059 | | |
2060 | | /// Compute the logical OR of the attributes of the caller and the |
2061 | | /// callee. |
2062 | | /// |
2063 | | /// This function sets the caller's attribute to true if the callee's attribute |
2064 | | /// is true. |
2065 | | template<typename AttrClass> |
2066 | 0 | static void setOR(Function &Caller, const Function &Callee) { |
2067 | 0 | if (!AttrClass::isSet(Caller, AttrClass::getKind()) && |
2068 | 0 | AttrClass::isSet(Callee, AttrClass::getKind())) |
2069 | 0 | AttrClass::set(Caller, AttrClass::getKind(), true); |
2070 | 0 | } Unexecuted instantiation: Attributes.cpp:void setOR<NoImplicitFloatAttr>(llvm::Function&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:void setOR<NoJumpTablesAttr>(llvm::Function&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:void setOR<ProfileSampleAccurateAttr>(llvm::Function&, llvm::Function const&) Unexecuted instantiation: Attributes.cpp:void setOR<SpeculativeLoadHardeningAttr>(llvm::Function&, llvm::Function const&) |
2071 | | |
2072 | | /// If the inlined function had a higher stack protection level than the |
2073 | | /// calling function, then bump up the caller's stack protection level. |
2074 | 0 | static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) { |
2075 | | // If the calling function has *no* stack protection level (e.g. it was built |
2076 | | // with Clang's -fno-stack-protector or no_stack_protector attribute), don't |
2077 | | // change it as that could change the program's semantics. |
2078 | 0 | if (!Caller.hasStackProtectorFnAttr()) |
2079 | 0 | return; |
2080 | | |
2081 | | // If upgrading the SSP attribute, clear out the old SSP Attributes first. |
2082 | | // Having multiple SSP attributes doesn't actually hurt, but it adds useless |
2083 | | // clutter to the IR. |
2084 | 0 | AttributeMask OldSSPAttr; |
2085 | 0 | OldSSPAttr.addAttribute(Attribute::StackProtect) |
2086 | 0 | .addAttribute(Attribute::StackProtectStrong) |
2087 | 0 | .addAttribute(Attribute::StackProtectReq); |
2088 | |
|
2089 | 0 | if (Callee.hasFnAttribute(Attribute::StackProtectReq)) { |
2090 | 0 | Caller.removeFnAttrs(OldSSPAttr); |
2091 | 0 | Caller.addFnAttr(Attribute::StackProtectReq); |
2092 | 0 | } else if (Callee.hasFnAttribute(Attribute::StackProtectStrong) && |
2093 | 0 | !Caller.hasFnAttribute(Attribute::StackProtectReq)) { |
2094 | 0 | Caller.removeFnAttrs(OldSSPAttr); |
2095 | 0 | Caller.addFnAttr(Attribute::StackProtectStrong); |
2096 | 0 | } else if (Callee.hasFnAttribute(Attribute::StackProtect) && |
2097 | 0 | !Caller.hasFnAttribute(Attribute::StackProtectReq) && |
2098 | 0 | !Caller.hasFnAttribute(Attribute::StackProtectStrong)) |
2099 | 0 | Caller.addFnAttr(Attribute::StackProtect); |
2100 | 0 | } |
2101 | | |
2102 | | /// If the inlined function required stack probes, then ensure that |
2103 | | /// the calling function has those too. |
2104 | 0 | static void adjustCallerStackProbes(Function &Caller, const Function &Callee) { |
2105 | 0 | if (!Caller.hasFnAttribute("probe-stack") && |
2106 | 0 | Callee.hasFnAttribute("probe-stack")) { |
2107 | 0 | Caller.addFnAttr(Callee.getFnAttribute("probe-stack")); |
2108 | 0 | } |
2109 | 0 | } |
2110 | | |
2111 | | /// If the inlined function defines the size of guard region |
2112 | | /// on the stack, then ensure that the calling function defines a guard region |
2113 | | /// that is no larger. |
2114 | | static void |
2115 | 0 | adjustCallerStackProbeSize(Function &Caller, const Function &Callee) { |
2116 | 0 | Attribute CalleeAttr = Callee.getFnAttribute("stack-probe-size"); |
2117 | 0 | if (CalleeAttr.isValid()) { |
2118 | 0 | Attribute CallerAttr = Caller.getFnAttribute("stack-probe-size"); |
2119 | 0 | if (CallerAttr.isValid()) { |
2120 | 0 | uint64_t CallerStackProbeSize, CalleeStackProbeSize; |
2121 | 0 | CallerAttr.getValueAsString().getAsInteger(0, CallerStackProbeSize); |
2122 | 0 | CalleeAttr.getValueAsString().getAsInteger(0, CalleeStackProbeSize); |
2123 | |
|
2124 | 0 | if (CallerStackProbeSize > CalleeStackProbeSize) { |
2125 | 0 | Caller.addFnAttr(CalleeAttr); |
2126 | 0 | } |
2127 | 0 | } else { |
2128 | 0 | Caller.addFnAttr(CalleeAttr); |
2129 | 0 | } |
2130 | 0 | } |
2131 | 0 | } |
2132 | | |
2133 | | /// If the inlined function defines a min legal vector width, then ensure |
2134 | | /// the calling function has the same or larger min legal vector width. If the |
2135 | | /// caller has the attribute, but the callee doesn't, we need to remove the |
2136 | | /// attribute from the caller since we can't make any guarantees about the |
2137 | | /// caller's requirements. |
2138 | | /// This function is called after the inlining decision has been made so we have |
2139 | | /// to merge the attribute this way. Heuristics that would use |
2140 | | /// min-legal-vector-width to determine inline compatibility would need to be |
2141 | | /// handled as part of inline cost analysis. |
2142 | | static void |
2143 | 0 | adjustMinLegalVectorWidth(Function &Caller, const Function &Callee) { |
2144 | 0 | Attribute CallerAttr = Caller.getFnAttribute("min-legal-vector-width"); |
2145 | 0 | if (CallerAttr.isValid()) { |
2146 | 0 | Attribute CalleeAttr = Callee.getFnAttribute("min-legal-vector-width"); |
2147 | 0 | if (CalleeAttr.isValid()) { |
2148 | 0 | uint64_t CallerVectorWidth, CalleeVectorWidth; |
2149 | 0 | CallerAttr.getValueAsString().getAsInteger(0, CallerVectorWidth); |
2150 | 0 | CalleeAttr.getValueAsString().getAsInteger(0, CalleeVectorWidth); |
2151 | 0 | if (CallerVectorWidth < CalleeVectorWidth) |
2152 | 0 | Caller.addFnAttr(CalleeAttr); |
2153 | 0 | } else { |
2154 | | // If the callee doesn't have the attribute then we don't know anything |
2155 | | // and must drop the attribute from the caller. |
2156 | 0 | Caller.removeFnAttr("min-legal-vector-width"); |
2157 | 0 | } |
2158 | 0 | } |
2159 | 0 | } |
2160 | | |
2161 | | /// If the inlined function has null_pointer_is_valid attribute, |
2162 | | /// set this attribute in the caller post inlining. |
2163 | | static void |
2164 | 0 | adjustNullPointerValidAttr(Function &Caller, const Function &Callee) { |
2165 | 0 | if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) { |
2166 | 0 | Caller.addFnAttr(Attribute::NullPointerIsValid); |
2167 | 0 | } |
2168 | 0 | } |
2169 | | |
2170 | | struct EnumAttr { |
2171 | | static bool isSet(const Function &Fn, |
2172 | 0 | Attribute::AttrKind Kind) { |
2173 | 0 | return Fn.hasFnAttribute(Kind); |
2174 | 0 | } |
2175 | | |
2176 | | static void set(Function &Fn, |
2177 | 0 | Attribute::AttrKind Kind, bool Val) { |
2178 | 0 | if (Val) |
2179 | 0 | Fn.addFnAttr(Kind); |
2180 | 0 | else |
2181 | 0 | Fn.removeFnAttr(Kind); |
2182 | 0 | } |
2183 | | }; |
2184 | | |
2185 | | struct StrBoolAttr { |
2186 | | static bool isSet(const Function &Fn, |
2187 | 0 | StringRef Kind) { |
2188 | 0 | auto A = Fn.getFnAttribute(Kind); |
2189 | 0 | return A.getValueAsString().equals("true"); |
2190 | 0 | } |
2191 | | |
2192 | | static void set(Function &Fn, |
2193 | 0 | StringRef Kind, bool Val) { |
2194 | 0 | Fn.addFnAttr(Kind, Val ? "true" : "false"); |
2195 | 0 | } |
2196 | | }; |
2197 | | |
2198 | | #define GET_ATTR_NAMES |
2199 | | #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \ |
2200 | | struct ENUM_NAME##Attr : EnumAttr { \ |
2201 | 0 | static enum Attribute::AttrKind getKind() { \ |
2202 | 0 | return llvm::Attribute::ENUM_NAME; \ |
2203 | 0 | } \ Unexecuted instantiation: SanitizeAddressAttr::getKind() Unexecuted instantiation: SanitizeThreadAttr::getKind() Unexecuted instantiation: SanitizeMemoryAttr::getKind() Unexecuted instantiation: SanitizeHWAddressAttr::getKind() Unexecuted instantiation: SanitizeMemTagAttr::getKind() Unexecuted instantiation: SafeStackAttr::getKind() Unexecuted instantiation: ShadowCallStackAttr::getKind() Unexecuted instantiation: NoProfileAttr::getKind() Unexecuted instantiation: NoImplicitFloatAttr::getKind() Unexecuted instantiation: SpeculativeLoadHardeningAttr::getKind() Unexecuted instantiation: MustProgressAttr::getKind() Unexecuted instantiation: AllocAlignAttr::getKind() Unexecuted instantiation: AllocatedPointerAttr::getKind() Unexecuted instantiation: AlwaysInlineAttr::getKind() Unexecuted instantiation: BuiltinAttr::getKind() Unexecuted instantiation: ColdAttr::getKind() Unexecuted instantiation: ConvergentAttr::getKind() Unexecuted instantiation: CoroDestroyOnlyWhenCompleteAttr::getKind() Unexecuted instantiation: DeadOnUnwindAttr::getKind() Unexecuted instantiation: DisableSanitizerInstrumentationAttr::getKind() Unexecuted instantiation: FnRetThunkExternAttr::getKind() Unexecuted instantiation: HotAttr::getKind() Unexecuted instantiation: ImmArgAttr::getKind() Unexecuted instantiation: InRegAttr::getKind() Unexecuted instantiation: InlineHintAttr::getKind() Unexecuted instantiation: JumpTableAttr::getKind() Unexecuted instantiation: MinSizeAttr::getKind() Unexecuted instantiation: NakedAttr::getKind() Unexecuted instantiation: NestAttr::getKind() Unexecuted instantiation: NoAliasAttr::getKind() Unexecuted instantiation: NoBuiltinAttr::getKind() Unexecuted instantiation: NoCallbackAttr::getKind() Unexecuted instantiation: NoCaptureAttr::getKind() Unexecuted instantiation: NoCfCheckAttr::getKind() Unexecuted instantiation: NoDuplicateAttr::getKind() Unexecuted instantiation: NoFreeAttr::getKind() Unexecuted instantiation: NoInlineAttr::getKind() Unexecuted instantiation: NoMergeAttr::getKind() Unexecuted instantiation: NoRecurseAttr::getKind() Unexecuted instantiation: NoRedZoneAttr::getKind() Unexecuted instantiation: NoReturnAttr::getKind() Unexecuted instantiation: NoSanitizeBoundsAttr::getKind() Unexecuted instantiation: NoSanitizeCoverageAttr::getKind() Unexecuted instantiation: NoSyncAttr::getKind() Unexecuted instantiation: NoUndefAttr::getKind() Unexecuted instantiation: NoUnwindAttr::getKind() Unexecuted instantiation: NonLazyBindAttr::getKind() Unexecuted instantiation: NonNullAttr::getKind() Unexecuted instantiation: NullPointerIsValidAttr::getKind() Unexecuted instantiation: OptForFuzzingAttr::getKind() Unexecuted instantiation: OptimizeForDebuggingAttr::getKind() Unexecuted instantiation: OptimizeForSizeAttr::getKind() Unexecuted instantiation: OptimizeNoneAttr::getKind() Unexecuted instantiation: PresplitCoroutineAttr::getKind() Unexecuted instantiation: ReadNoneAttr::getKind() Unexecuted instantiation: ReadOnlyAttr::getKind() Unexecuted instantiation: ReturnedAttr::getKind() Unexecuted instantiation: ReturnsTwiceAttr::getKind() Unexecuted instantiation: SExtAttr::getKind() Unexecuted instantiation: SkipProfileAttr::getKind() Unexecuted instantiation: SpeculatableAttr::getKind() Unexecuted instantiation: StackProtectAttr::getKind() Unexecuted instantiation: StackProtectReqAttr::getKind() Unexecuted instantiation: StackProtectStrongAttr::getKind() Unexecuted instantiation: StrictFPAttr::getKind() Unexecuted instantiation: SwiftAsyncAttr::getKind() Unexecuted instantiation: SwiftErrorAttr::getKind() Unexecuted instantiation: SwiftSelfAttr::getKind() Unexecuted instantiation: WillReturnAttr::getKind() Unexecuted instantiation: WritableAttr::getKind() Unexecuted instantiation: WriteOnlyAttr::getKind() Unexecuted instantiation: ZExtAttr::getKind() Unexecuted instantiation: ByRefAttr::getKind() Unexecuted instantiation: ByValAttr::getKind() Unexecuted instantiation: ElementTypeAttr::getKind() Unexecuted instantiation: InAllocaAttr::getKind() Unexecuted instantiation: PreallocatedAttr::getKind() Unexecuted instantiation: StructRetAttr::getKind() Unexecuted instantiation: AlignmentAttr::getKind() Unexecuted instantiation: AllocKindAttr::getKind() Unexecuted instantiation: AllocSizeAttr::getKind() Unexecuted instantiation: DereferenceableAttr::getKind() Unexecuted instantiation: DereferenceableOrNullAttr::getKind() Unexecuted instantiation: MemoryAttr::getKind() Unexecuted instantiation: NoFPClassAttr::getKind() Unexecuted instantiation: StackAlignmentAttr::getKind() Unexecuted instantiation: UWTableAttr::getKind() Unexecuted instantiation: VScaleRangeAttr::getKind() |
2204 | | }; |
2205 | | #define ATTRIBUTE_STRBOOL(ENUM_NAME, DISPLAY_NAME) \ |
2206 | | struct ENUM_NAME##Attr : StrBoolAttr { \ |
2207 | 0 | static StringRef getKind() { return #DISPLAY_NAME; } \ Unexecuted instantiation: UseSampleProfileAttr::getKind() Unexecuted instantiation: LessPreciseFPMADAttr::getKind() Unexecuted instantiation: NoInfsFPMathAttr::getKind() Unexecuted instantiation: NoNansFPMathAttr::getKind() Unexecuted instantiation: ApproxFuncFPMathAttr::getKind() Unexecuted instantiation: NoSignedZerosFPMathAttr::getKind() Unexecuted instantiation: UnsafeFPMathAttr::getKind() Unexecuted instantiation: NoJumpTablesAttr::getKind() Unexecuted instantiation: ProfileSampleAccurateAttr::getKind() Unexecuted instantiation: NoInlineLineTablesAttr::getKind() |
2208 | | }; |
2209 | | #include "llvm/IR/Attributes.inc" |
2210 | | |
2211 | | #define GET_ATTR_COMPAT_FUNC |
2212 | | #include "llvm/IR/Attributes.inc" |
2213 | | |
2214 | | bool AttributeFuncs::areInlineCompatible(const Function &Caller, |
2215 | 0 | const Function &Callee) { |
2216 | 0 | return hasCompatibleFnAttrs(Caller, Callee); |
2217 | 0 | } |
2218 | | |
2219 | | bool AttributeFuncs::areOutlineCompatible(const Function &A, |
2220 | 0 | const Function &B) { |
2221 | 0 | return hasCompatibleFnAttrs(A, B); |
2222 | 0 | } |
2223 | | |
2224 | | void AttributeFuncs::mergeAttributesForInlining(Function &Caller, |
2225 | 0 | const Function &Callee) { |
2226 | 0 | mergeFnAttrs(Caller, Callee); |
2227 | 0 | } |
2228 | | |
2229 | | void AttributeFuncs::mergeAttributesForOutlining(Function &Base, |
2230 | 0 | const Function &ToMerge) { |
2231 | | |
2232 | | // We merge functions so that they meet the most general case. |
2233 | | // For example, if the NoNansFPMathAttr is set in one function, but not in |
2234 | | // the other, in the merged function we can say that the NoNansFPMathAttr |
2235 | | // is not set. |
2236 | | // However if we have the SpeculativeLoadHardeningAttr set true in one |
2237 | | // function, but not the other, we make sure that the function retains |
2238 | | // that aspect in the merged function. |
2239 | 0 | mergeFnAttrs(Base, ToMerge); |
2240 | 0 | } |
2241 | | |
2242 | | void AttributeFuncs::updateMinLegalVectorWidthAttr(Function &Fn, |
2243 | 0 | uint64_t Width) { |
2244 | 0 | Attribute Attr = Fn.getFnAttribute("min-legal-vector-width"); |
2245 | 0 | if (Attr.isValid()) { |
2246 | 0 | uint64_t OldWidth; |
2247 | 0 | Attr.getValueAsString().getAsInteger(0, OldWidth); |
2248 | 0 | if (Width > OldWidth) |
2249 | 0 | Fn.addFnAttr("min-legal-vector-width", llvm::utostr(Width)); |
2250 | 0 | } |
2251 | 0 | } |