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

source code of llvm/lib/IR/Attributes.cpp