LLVM 20.0.0git
Attributes.cpp
Go to the documentation of this file.
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"
23#include "llvm/ADT/StringRef.h"
25#include "llvm/Config/llvm-config.h"
29#include "llvm/IR/Function.h"
30#include "llvm/IR/LLVMContext.h"
31#include "llvm/IR/Operator.h"
32#include "llvm/IR/Type.h"
35#include "llvm/Support/ModRef.h"
37#include <algorithm>
38#include <cassert>
39#include <cstddef>
40#include <cstdint>
41#include <limits>
42#include <optional>
43#include <string>
44#include <tuple>
45#include <utility>
46
47using namespace llvm;
48
49//===----------------------------------------------------------------------===//
50// Attribute Construction Methods
51//===----------------------------------------------------------------------===//
52
53// allocsize has two integer arguments, but because they're both 32 bits, we can
54// pack them into one 64-bit value, at the cost of making said value
55// nonsensical.
56//
57// In order to do this, we need to reserve one value of the second (optional)
58// allocsize argument to signify "not present."
59static const unsigned AllocSizeNumElemsNotPresent = -1;
60
61static uint64_t packAllocSizeArgs(unsigned ElemSizeArg,
62 const std::optional<unsigned> &NumElemsArg) {
63 assert((!NumElemsArg || *NumElemsArg != AllocSizeNumElemsNotPresent) &&
64 "Attempting to pack a reserved value");
65
66 return uint64_t(ElemSizeArg) << 32 |
67 NumElemsArg.value_or(AllocSizeNumElemsNotPresent);
68}
69
70static std::pair<unsigned, std::optional<unsigned>>
72 unsigned NumElems = Num & std::numeric_limits<unsigned>::max();
73 unsigned ElemSizeArg = Num >> 32;
74
75 std::optional<unsigned> NumElemsArg;
76 if (NumElems != AllocSizeNumElemsNotPresent)
77 NumElemsArg = NumElems;
78 return std::make_pair(ElemSizeArg, NumElemsArg);
79}
80
81static uint64_t packVScaleRangeArgs(unsigned MinValue,
82 std::optional<unsigned> MaxValue) {
83 return uint64_t(MinValue) << 32 | MaxValue.value_or(0);
84}
85
86static std::pair<unsigned, std::optional<unsigned>>
88 unsigned MaxValue = Value & std::numeric_limits<unsigned>::max();
89 unsigned MinValue = Value >> 32;
90
91 return std::make_pair(MinValue,
92 MaxValue > 0 ? MaxValue : std::optional<unsigned>());
93}
94
96 uint64_t Val) {
97 bool IsIntAttr = Attribute::isIntAttrKind(Kind);
98 assert((IsIntAttr || Attribute::isEnumAttrKind(Kind)) &&
99 "Not an enum or int attribute");
100
101 LLVMContextImpl *pImpl = Context.pImpl;
103 ID.AddInteger(Kind);
104 if (IsIntAttr)
105 ID.AddInteger(Val);
106 else
107 assert(Val == 0 && "Value must be zero for enum attributes");
108
109 void *InsertPoint;
110 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
111
112 if (!PA) {
113 // If we didn't find any existing attributes of the same shape then create a
114 // new one and insert it.
115 if (!IsIntAttr)
116 PA = new (pImpl->Alloc) EnumAttributeImpl(Kind);
117 else
118 PA = new (pImpl->Alloc) IntAttributeImpl(Kind, Val);
119 pImpl->AttrsSet.InsertNode(PA, InsertPoint);
120 }
121
122 // Return the Attribute that we found or created.
123 return Attribute(PA);
124}
125
127 LLVMContextImpl *pImpl = Context.pImpl;
129 ID.AddString(Kind);
130 if (!Val.empty()) ID.AddString(Val);
131
132 void *InsertPoint;
133 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
134
135 if (!PA) {
136 // If we didn't find any existing attributes of the same shape then create a
137 // new one and insert it.
138 void *Mem =
140 alignof(StringAttributeImpl));
141 PA = new (Mem) StringAttributeImpl(Kind, Val);
142 pImpl->AttrsSet.InsertNode(PA, InsertPoint);
143 }
144
145 // Return the Attribute that we found or created.
146 return Attribute(PA);
147}
148
150 Type *Ty) {
151 assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute");
152 LLVMContextImpl *pImpl = Context.pImpl;
154 ID.AddInteger(Kind);
155 ID.AddPointer(Ty);
156
157 void *InsertPoint;
158 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
159
160 if (!PA) {
161 // If we didn't find any existing attributes of the same shape then create a
162 // new one and insert it.
163 PA = new (pImpl->Alloc) TypeAttributeImpl(Kind, Ty);
164 pImpl->AttrsSet.InsertNode(PA, InsertPoint);
165 }
166
167 // Return the Attribute that we found or created.
168 return Attribute(PA);
169}
170
172 const ConstantRange &CR) {
174 "Not a ConstantRange attribute");
175 assert(!CR.isFullSet() && "ConstantRange attribute must not be full");
176 LLVMContextImpl *pImpl = Context.pImpl;
178 ID.AddInteger(Kind);
179 CR.getLower().Profile(ID);
180 CR.getUpper().Profile(ID);
181
182 void *InsertPoint;
183 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
184
185 if (!PA) {
186 // If we didn't find any existing attributes of the same shape then create a
187 // new one and insert it.
188 PA = new (pImpl->ConstantRangeAttributeAlloc.Allocate())
190 pImpl->AttrsSet.InsertNode(PA, InsertPoint);
191 }
192
193 // Return the Attribute that we found or created.
194 return Attribute(PA);
195}
196
200 "Not a ConstantRangeList attribute");
201 LLVMContextImpl *pImpl = Context.pImpl;
203 ID.AddInteger(Kind);
204 ID.AddInteger(Val.size());
205 for (auto &CR : Val) {
206 CR.getLower().Profile(ID);
207 CR.getUpper().Profile(ID);
208 }
209
210 void *InsertPoint;
211 AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
212
213 if (!PA) {
214 // If we didn't find any existing attributes of the same shape then create a
215 // new one and insert it.
216 // ConstantRangeListAttributeImpl is a dynamically sized class and cannot
217 // use SpecificBumpPtrAllocator. Instead, we use normal Alloc for
218 // allocation and record the allocated pointer in
219 // `ConstantRangeListAttributes`. LLVMContext destructor will call the
220 // destructor of the allocated pointer explicitly.
221 void *Mem = pImpl->Alloc.Allocate(
224 PA = new (Mem) ConstantRangeListAttributeImpl(Kind, Val);
225 pImpl->AttrsSet.InsertNode(PA, InsertPoint);
226 pImpl->ConstantRangeListAttributes.push_back(
227 reinterpret_cast<ConstantRangeListAttributeImpl *>(PA));
228 }
229
230 // Return the Attribute that we found or created.
231 return Attribute(PA);
232}
233
235 assert(A <= llvm::Value::MaximumAlignment && "Alignment too large.");
236 return get(Context, Alignment, A.value());
237}
238
240 assert(A <= 0x100 && "Alignment too large.");
241 return get(Context, StackAlignment, A.value());
242}
243
245 uint64_t Bytes) {
246 assert(Bytes && "Bytes must be non-zero.");
247 return get(Context, Dereferenceable, Bytes);
248}
249
251 uint64_t Bytes) {
252 assert(Bytes && "Bytes must be non-zero.");
253 return get(Context, DereferenceableOrNull, Bytes);
254}
255
257 return get(Context, ByVal, Ty);
258}
259
261 return get(Context, StructRet, Ty);
262}
263
265 return get(Context, ByRef, Ty);
266}
267
269 return get(Context, Preallocated, Ty);
270}
271
273 return get(Context, InAlloca, Ty);
274}
275
277 UWTableKind Kind) {
278 return get(Context, UWTable, uint64_t(Kind));
279}
280
282 MemoryEffects ME) {
283 return get(Context, Memory, ME.toIntValue());
284}
285
287 FPClassTest ClassMask) {
288 return get(Context, NoFPClass, ClassMask);
289}
290
292Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg,
293 const std::optional<unsigned> &NumElemsArg) {
294 assert(!(ElemSizeArg == 0 && NumElemsArg && *NumElemsArg == 0) &&
295 "Invalid allocsize arguments -- given allocsize(0, 0)");
296 return get(Context, AllocSize, packAllocSizeArgs(ElemSizeArg, NumElemsArg));
297}
298
300 unsigned MinValue,
301 unsigned MaxValue) {
302 return get(Context, VScaleRange, packVScaleRangeArgs(MinValue, MaxValue));
303}
304
306 return StringSwitch<Attribute::AttrKind>(AttrName)
307#define GET_ATTR_NAMES
308#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \
309 .Case(#DISPLAY_NAME, Attribute::ENUM_NAME)
310#include "llvm/IR/Attributes.inc"
312}
313
315 switch (AttrKind) {
316#define GET_ATTR_NAMES
317#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \
318 case Attribute::ENUM_NAME: \
319 return #DISPLAY_NAME;
320#include "llvm/IR/Attributes.inc"
321 case Attribute::None:
322 return "none";
323 default:
324 llvm_unreachable("invalid Kind");
325 }
326}
327
330#define GET_ATTR_NAMES
331#define ATTRIBUTE_ALL(ENUM_NAME, DISPLAY_NAME) .Case(#DISPLAY_NAME, true)
332#include "llvm/IR/Attributes.inc"
333 .Default(false);
334}
335
336//===----------------------------------------------------------------------===//
337// Attribute Accessor Methods
338//===----------------------------------------------------------------------===//
339
341 return pImpl && pImpl->isEnumAttribute();
342}
343
345 return pImpl && pImpl->isIntAttribute();
346}
347
349 return pImpl && pImpl->isStringAttribute();
350}
351
353 return pImpl && pImpl->isTypeAttribute();
354}
355
357 return pImpl && pImpl->isConstantRangeAttribute();
358}
359
361 return pImpl && pImpl->isConstantRangeListAttribute();
362}
363
365 if (!pImpl) return None;
367 "Invalid attribute type to get the kind as an enum!");
368 return pImpl->getKindAsEnum();
369}
370
372 if (!pImpl) return 0;
374 "Expected the attribute to be an integer attribute!");
375 return pImpl->getValueAsInt();
376}
377
379 if (!pImpl) return false;
381 "Expected the attribute to be a string attribute!");
382 return pImpl->getValueAsBool();
383}
384
386 if (!pImpl) return {};
388 "Invalid attribute type to get the kind as a string!");
389 return pImpl->getKindAsString();
390}
391
393 if (!pImpl) return {};
395 "Invalid attribute type to get the value as a string!");
396 return pImpl->getValueAsString();
397}
398
400 if (!pImpl) return {};
402 "Invalid attribute type to get the value as a type!");
403 return pImpl->getValueAsType();
404}
405
408 "Invalid attribute type to get the value as a ConstantRange!");
409 return pImpl->getValueAsConstantRange();
410}
411
414 "Invalid attribute type to get the value as a ConstantRangeList!");
415 return pImpl->getValueAsConstantRangeList();
416}
417
419 return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None);
420}
421
423 if (!isStringAttribute()) return false;
424 return pImpl && pImpl->hasAttribute(Kind);
425}
426
428 assert(hasAttribute(Attribute::Alignment) &&
429 "Trying to get alignment from non-alignment attribute!");
430 return MaybeAlign(pImpl->getValueAsInt());
431}
432
434 assert(hasAttribute(Attribute::StackAlignment) &&
435 "Trying to get alignment from non-alignment attribute!");
436 return MaybeAlign(pImpl->getValueAsInt());
437}
438
440 assert(hasAttribute(Attribute::Dereferenceable) &&
441 "Trying to get dereferenceable bytes from "
442 "non-dereferenceable attribute!");
443 return pImpl->getValueAsInt();
444}
445
447 assert(hasAttribute(Attribute::DereferenceableOrNull) &&
448 "Trying to get dereferenceable bytes from "
449 "non-dereferenceable attribute!");
450 return pImpl->getValueAsInt();
451}
452
453std::pair<unsigned, std::optional<unsigned>>
455 assert(hasAttribute(Attribute::AllocSize) &&
456 "Trying to get allocsize args from non-allocsize attribute");
457 return unpackAllocSizeArgs(pImpl->getValueAsInt());
458}
459
461 assert(hasAttribute(Attribute::VScaleRange) &&
462 "Trying to get vscale args from non-vscale attribute");
463 return unpackVScaleRangeArgs(pImpl->getValueAsInt()).first;
464}
465
466std::optional<unsigned> Attribute::getVScaleRangeMax() const {
467 assert(hasAttribute(Attribute::VScaleRange) &&
468 "Trying to get vscale args from non-vscale attribute");
469 return unpackVScaleRangeArgs(pImpl->getValueAsInt()).second;
470}
471
473 assert(hasAttribute(Attribute::UWTable) &&
474 "Trying to get unwind table kind from non-uwtable attribute");
475 return UWTableKind(pImpl->getValueAsInt());
476}
477
479 assert(hasAttribute(Attribute::AllocKind) &&
480 "Trying to get allockind value from non-allockind attribute");
481 return AllocFnKind(pImpl->getValueAsInt());
482}
483
485 assert(hasAttribute(Attribute::Memory) &&
486 "Can only call getMemoryEffects() on memory attribute");
488}
489
491 assert(hasAttribute(Attribute::NoFPClass) &&
492 "Can only call getNoFPClass() on nofpclass attribute");
493 return static_cast<FPClassTest>(pImpl->getValueAsInt());
494}
495
497 assert(hasAttribute(Attribute::Range) &&
498 "Trying to get range args from non-range attribute");
499 return pImpl->getValueAsConstantRange();
500}
501
503 assert(hasAttribute(Attribute::Initializes) &&
504 "Trying to get initializes attr from non-ConstantRangeList attribute");
505 return pImpl->getValueAsConstantRangeList();
506}
507
508static const char *getModRefStr(ModRefInfo MR) {
509 switch (MR) {
511 return "none";
512 case ModRefInfo::Ref:
513 return "read";
514 case ModRefInfo::Mod:
515 return "write";
517 return "readwrite";
518 }
519 llvm_unreachable("Invalid ModRefInfo");
520}
521
522std::string Attribute::getAsString(bool InAttrGrp) const {
523 if (!pImpl) return {};
524
525 if (isEnumAttribute())
527
528 if (isTypeAttribute()) {
529 std::string Result = getNameFromAttrKind(getKindAsEnum()).str();
530 Result += '(';
531 raw_string_ostream OS(Result);
532 getValueAsType()->print(OS, false, true);
533 OS.flush();
534 Result += ')';
535 return Result;
536 }
537
538 // FIXME: These should be output like this:
539 //
540 // align=4
541 // alignstack=8
542 //
543 if (hasAttribute(Attribute::Alignment))
544 return (InAttrGrp ? "align=" + Twine(getValueAsInt())
545 : "align " + Twine(getValueAsInt()))
546 .str();
547
548 auto AttrWithBytesToString = [&](const char *Name) {
549 return (InAttrGrp ? Name + ("=" + Twine(getValueAsInt()))
550 : Name + ("(" + Twine(getValueAsInt())) + ")")
551 .str();
552 };
553
554 if (hasAttribute(Attribute::StackAlignment))
555 return AttrWithBytesToString("alignstack");
556
557 if (hasAttribute(Attribute::Dereferenceable))
558 return AttrWithBytesToString("dereferenceable");
559
560 if (hasAttribute(Attribute::DereferenceableOrNull))
561 return AttrWithBytesToString("dereferenceable_or_null");
562
563 if (hasAttribute(Attribute::AllocSize)) {
564 unsigned ElemSize;
565 std::optional<unsigned> NumElems;
566 std::tie(ElemSize, NumElems) = getAllocSizeArgs();
567
568 return (NumElems
569 ? "allocsize(" + Twine(ElemSize) + "," + Twine(*NumElems) + ")"
570 : "allocsize(" + Twine(ElemSize) + ")")
571 .str();
572 }
573
574 if (hasAttribute(Attribute::VScaleRange)) {
575 unsigned MinValue = getVScaleRangeMin();
576 std::optional<unsigned> MaxValue = getVScaleRangeMax();
577 return ("vscale_range(" + Twine(MinValue) + "," +
578 Twine(MaxValue.value_or(0)) + ")")
579 .str();
580 }
581
582 if (hasAttribute(Attribute::UWTable)) {
584 assert(Kind != UWTableKind::None && "uwtable attribute should not be none");
585 return Kind == UWTableKind::Default ? "uwtable" : "uwtable(sync)";
586 }
587
588 if (hasAttribute(Attribute::AllocKind)) {
589 AllocFnKind Kind = getAllocKind();
592 parts.push_back("alloc");
594 parts.push_back("realloc");
596 parts.push_back("free");
598 parts.push_back("uninitialized");
600 parts.push_back("zeroed");
602 parts.push_back("aligned");
603 return ("allockind(\"" +
604 Twine(llvm::join(parts.begin(), parts.end(), ",")) + "\")")
605 .str();
606 }
607
608 if (hasAttribute(Attribute::Memory)) {
609 std::string Result;
610 raw_string_ostream OS(Result);
611 bool First = true;
612 OS << "memory(";
613
615
616 // Print access kind for "other" as the default access kind. This way it
617 // will apply to any new location kinds that get split out of "other".
619 if (OtherMR != ModRefInfo::NoModRef || ME.getModRef() == OtherMR) {
620 First = false;
621 OS << getModRefStr(OtherMR);
622 }
623
624 for (auto Loc : MemoryEffects::locations()) {
625 ModRefInfo MR = ME.getModRef(Loc);
626 if (MR == OtherMR)
627 continue;
628
629 if (!First)
630 OS << ", ";
631 First = false;
632
633 switch (Loc) {
635 OS << "argmem: ";
636 break;
638 OS << "inaccessiblemem: ";
639 break;
641 llvm_unreachable("This is represented as the default access kind");
642 }
643 OS << getModRefStr(MR);
644 }
645 OS << ")";
646 OS.flush();
647 return Result;
648 }
649
650 if (hasAttribute(Attribute::NoFPClass)) {
651 std::string Result = "nofpclass";
652 raw_string_ostream OS(Result);
653 OS << getNoFPClass();
654 return Result;
655 }
656
657 if (hasAttribute(Attribute::Range)) {
658 std::string Result;
659 raw_string_ostream OS(Result);
661 OS << "range(";
662 OS << "i" << CR.getBitWidth() << " ";
663 OS << CR.getLower() << ", " << CR.getUpper();
664 OS << ")";
665 OS.flush();
666 return Result;
667 }
668
669 if (hasAttribute(Attribute::Initializes)) {
670 std::string Result;
671 raw_string_ostream OS(Result);
673 OS << "initializes(";
674 CRL.print(OS);
675 OS << ")";
676 OS.flush();
677 return Result;
678 }
679
680 // Convert target-dependent attributes to strings of the form:
681 //
682 // "kind"
683 // "kind" = "value"
684 //
685 if (isStringAttribute()) {
686 std::string Result;
687 {
688 raw_string_ostream OS(Result);
689 OS << '"' << getKindAsString() << '"';
690
691 // Since some attribute strings contain special characters that cannot be
692 // printable, those have to be escaped to make the attribute value
693 // printable as is. e.g. "\01__gnu_mcount_nc"
694 const auto &AttrVal = pImpl->getValueAsString();
695 if (!AttrVal.empty()) {
696 OS << "=\"";
697 printEscapedString(AttrVal, OS);
698 OS << "\"";
699 }
700 }
701 return Result;
702 }
703
704 llvm_unreachable("Unknown attribute");
705}
706
708 assert(isValid() && "invalid Attribute doesn't refer to any context");
710 pImpl->Profile(ID);
711 void *Unused;
712 return C.pImpl->AttrsSet.FindNodeOrInsertPos(ID, Unused) == pImpl;
713}
714
716 if (!pImpl && !A.pImpl)
717 return 0;
718 if (!pImpl)
719 return 1;
720 if (!A.pImpl)
721 return -1;
722 return pImpl->cmp(*A.pImpl, /*KindOnly=*/true);
723}
724
726 if (!pImpl && !A.pImpl) return false;
727 if (!pImpl) return true;
728 if (!A.pImpl) return false;
729 return *pImpl < *A.pImpl;
730}
731
733 ID.AddPointer(pImpl);
734}
735
737 FnAttr = (1 << 0),
738 ParamAttr = (1 << 1),
739 RetAttr = (1 << 2),
741 IntersectAnd = (1 << 3),
742 IntersectMin = (2 << 3),
743 IntersectCustom = (3 << 3),
745};
746
747#define GET_ATTR_PROP_TABLE
748#include "llvm/IR/Attributes.inc"
749
751 unsigned Index = Kind - 1;
752 assert(Index < std::size(AttrPropTable) && "Invalid attribute kind");
753 return AttrPropTable[Index];
754}
755
757 AttributeProperty Prop) {
758 return getAttributeProperties(Kind) & Prop;
759}
760
762 return hasAttributeProperty(Kind, AttributeProperty::FnAttr);
763}
764
766 return hasAttributeProperty(Kind, AttributeProperty::ParamAttr);
767}
768
770 return hasAttributeProperty(Kind, AttributeProperty::RetAttr);
771}
772
774 AttributeProperty Prop) {
775 assert((Prop == AttributeProperty::IntersectPreserve ||
776 Prop == AttributeProperty::IntersectAnd ||
777 Prop == AttributeProperty::IntersectMin ||
778 Prop == AttributeProperty::IntersectCustom) &&
779 "Unknown intersect property");
780 return (getAttributeProperties(Kind) &
781 AttributeProperty::IntersectPropertyMask) == Prop;
782}
783
785 return hasIntersectProperty(Kind, AttributeProperty::IntersectPreserve);
786}
788 return hasIntersectProperty(Kind, AttributeProperty::IntersectAnd);
789}
791 return hasIntersectProperty(Kind, AttributeProperty::IntersectMin);
792}
794 return hasIntersectProperty(Kind, AttributeProperty::IntersectCustom);
795}
796
797//===----------------------------------------------------------------------===//
798// AttributeImpl Definition
799//===----------------------------------------------------------------------===//
800
802 if (isStringAttribute()) return false;
803 return getKindAsEnum() == A;
804}
805
807 if (!isStringAttribute()) return false;
808 return getKindAsString() == Kind;
809}
810
814 return static_cast<const EnumAttributeImpl *>(this)->getEnumKind();
815}
816
819 return static_cast<const IntAttributeImpl *>(this)->getValue();
820}
821
823 assert(getValueAsString().empty() || getValueAsString() == "false" || getValueAsString() == "true");
824 return getValueAsString() == "true";
825}
826
829 return static_cast<const StringAttributeImpl *>(this)->getStringKind();
830}
831
834 return static_cast<const StringAttributeImpl *>(this)->getStringValue();
835}
836
839 return static_cast<const TypeAttributeImpl *>(this)->getTypeValue();
840}
841
844 return static_cast<const ConstantRangeAttributeImpl *>(this)
845 ->getConstantRangeValue();
846}
847
850 return static_cast<const ConstantRangeListAttributeImpl *>(this)
851 ->getConstantRangeListValue();
852}
853
854int AttributeImpl::cmp(const AttributeImpl &AI, bool KindOnly) const {
855 if (this == &AI)
856 return 0;
857
858 // This sorts the attributes with Attribute::AttrKinds coming first (sorted
859 // relative to their enum value) and then strings.
860 if (!isStringAttribute()) {
861 if (AI.isStringAttribute())
862 return -1;
863
864 if (getKindAsEnum() != AI.getKindAsEnum())
865 return getKindAsEnum() < AI.getKindAsEnum() ? -1 : 1;
866 else if (KindOnly)
867 return 0;
868
869 assert(!AI.isEnumAttribute() && "Non-unique attribute");
870 assert(!AI.isTypeAttribute() && "Comparison of types would be unstable");
871 assert(!AI.isConstantRangeAttribute() && "Unclear how to compare ranges");
873 "Unclear how to compare range list");
874 // TODO: Is this actually needed?
875 assert(AI.isIntAttribute() && "Only possibility left");
876 if (getValueAsInt() < AI.getValueAsInt())
877 return -1;
878 return getValueAsInt() == AI.getValueAsInt() ? 0 : 1;
879 }
880 if (!AI.isStringAttribute())
881 return 1;
882 if (KindOnly)
884 if (getKindAsString() == AI.getKindAsString())
887}
888
890 return cmp(AI, /*KindOnly=*/false) < 0;
891}
892
893//===----------------------------------------------------------------------===//
894// AttributeSet Definition
895//===----------------------------------------------------------------------===//
896
899}
900
902 return AttributeSet(AttributeSetNode::get(C, Attrs));
903}
904
906 Attribute::AttrKind Kind) const {
907 if (hasAttribute(Kind)) return *this;
908 AttrBuilder B(C);
909 B.addAttribute(Kind);
911}
912
914 StringRef Value) const {
915 AttrBuilder B(C);
916 B.addAttribute(Kind, Value);
918}
919
921 const AttributeSet AS) const {
922 if (!hasAttributes())
923 return AS;
924
925 if (!AS.hasAttributes())
926 return *this;
927
928 AttrBuilder B(C, *this);
929 B.merge(AttrBuilder(C, AS));
930 return get(C, B);
931}
932
934 Attribute::AttrKind Kind) const {
935 if (!hasAttribute(Kind)) return *this;
936 AttrBuilder B(C, *this);
937 B.removeAttribute(Kind);
938 return get(C, B);
939}
940
942 StringRef Kind) const {
943 if (!hasAttribute(Kind)) return *this;
944 AttrBuilder B(C, *this);
945 B.removeAttribute(Kind);
946 return get(C, B);
947}
948
950 const AttributeMask &Attrs) const {
951 AttrBuilder B(C, *this);
952 // If there is nothing to remove, directly return the original set.
953 if (!B.overlaps(Attrs))
954 return *this;
955
956 B.remove(Attrs);
957 return get(C, B);
958}
959
960std::optional<AttributeSet>
962 if (*this == Other)
963 return *this;
964
965 AttrBuilder Intersected(C);
966 // Iterate over both attr sets at once.
967 auto ItBegin0 = begin();
968 auto ItEnd0 = end();
969 auto ItBegin1 = Other.begin();
970 auto ItEnd1 = Other.end();
971
972 while (ItBegin0 != ItEnd0 || ItBegin1 != ItEnd1) {
973 // Loop through all attributes in both this and Other in sorted order. If
974 // the attribute is only present in one of the sets, it will be set in
975 // Attr0. If it is present in both sets both Attr0 and Attr1 will be set.
976 Attribute Attr0, Attr1;
977 if (ItBegin1 == ItEnd1)
978 Attr0 = *ItBegin0++;
979 else if (ItBegin0 == ItEnd0)
980 Attr0 = *ItBegin1++;
981 else {
982 int Cmp = ItBegin0->cmpKind(*ItBegin1);
983 if (Cmp == 0) {
984 Attr0 = *ItBegin0++;
985 Attr1 = *ItBegin1++;
986 } else if (Cmp < 0)
987 Attr0 = *ItBegin0++;
988 else
989 Attr0 = *ItBegin1++;
990 }
991 assert(Attr0.isValid() && "Iteration should always yield a valid attr");
992
993 auto IntersectEq = [&]() {
994 if (!Attr1.isValid())
995 return false;
996 if (Attr0 != Attr1)
997 return false;
998 Intersected.addAttribute(Attr0);
999 return true;
1000 };
1001
1002 // Non-enum assume we must preserve. Handle early so we can unconditionally
1003 // use Kind below.
1004 if (!Attr0.hasKindAsEnum()) {
1005 if (!IntersectEq())
1006 return std::nullopt;
1007 continue;
1008 }
1009
1010 Attribute::AttrKind Kind = Attr0.getKindAsEnum();
1011 // If we don't have both attributes, then fail if the attribute is
1012 // must-preserve or drop it otherwise.
1013 if (!Attr1.isValid()) {
1015 return std::nullopt;
1016 continue;
1017 }
1018
1019 // We have both attributes so apply the intersection rule.
1020 assert(Attr1.hasKindAsEnum() && Kind == Attr1.getKindAsEnum() &&
1021 "Iterator picked up two different attributes in the same iteration");
1022
1023 // Attribute we can intersect with "and"
1024 if (Attribute::intersectWithAnd(Kind)) {
1026 "Invalid attr type of intersectAnd");
1027 Intersected.addAttribute(Kind);
1028 continue;
1029 }
1030
1031 // Attribute we can intersect with "min"
1032 if (Attribute::intersectWithMin(Kind)) {
1034 "Invalid attr type of intersectMin");
1035 uint64_t NewVal = std::min(Attr0.getValueAsInt(), Attr1.getValueAsInt());
1036 Intersected.addRawIntAttr(Kind, NewVal);
1037 continue;
1038 }
1039 // Attribute we can intersect but need a custom rule for.
1041 switch (Kind) {
1042 case Attribute::Alignment:
1043 // If `byval` is present, alignment become must-preserve. This is
1044 // handled below if we have `byval`.
1045 Intersected.addAlignmentAttr(
1046 std::min(Attr0.getAlignment().valueOrOne(),
1047 Attr1.getAlignment().valueOrOne()));
1048 break;
1049 case Attribute::Memory:
1050 Intersected.addMemoryAttr(Attr0.getMemoryEffects() |
1051 Attr1.getMemoryEffects());
1052 break;
1053 case Attribute::NoFPClass:
1054 Intersected.addNoFPClassAttr(Attr0.getNoFPClass() &
1055 Attr1.getNoFPClass());
1056 break;
1057 case Attribute::Range: {
1058 ConstantRange Range0 = Attr0.getRange();
1059 ConstantRange Range1 = Attr1.getRange();
1060 ConstantRange NewRange = Range0.unionWith(Range1);
1061 if (!NewRange.isFullSet())
1062 Intersected.addRangeAttr(NewRange);
1063 } break;
1064 default:
1065 llvm_unreachable("Unknown attribute with custom intersection rule");
1066 }
1067 continue;
1068 }
1069
1070 // Attributes with no intersection rule. Only intersect if they are equal.
1071 // Otherwise fail.
1072 if (!IntersectEq())
1073 return std::nullopt;
1074
1075 // Special handling of `byval`. `byval` essentially turns align attr into
1076 // must-preserve
1077 if (Kind == Attribute::ByVal &&
1078 getAttribute(Attribute::Alignment) !=
1079 Other.getAttribute(Attribute::Alignment))
1080 return std::nullopt;
1081 }
1082
1083 return get(C, Intersected);
1084}
1085
1087 return SetNode ? SetNode->getNumAttributes() : 0;
1088}
1089
1091 return SetNode ? SetNode->hasAttribute(Kind) : false;
1092}
1093
1095 return SetNode ? SetNode->hasAttribute(Kind) : false;
1096}
1097
1099 return SetNode ? SetNode->getAttribute(Kind) : Attribute();
1100}
1101
1103 return SetNode ? SetNode->getAttribute(Kind) : Attribute();
1104}
1105
1107 return SetNode ? SetNode->getAlignment() : std::nullopt;
1108}
1109
1111 return SetNode ? SetNode->getStackAlignment() : std::nullopt;
1112}
1113
1115 return SetNode ? SetNode->getDereferenceableBytes() : 0;
1116}
1117
1119 return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0;
1120}
1121
1123 return SetNode ? SetNode->getAttributeType(Attribute::ByRef) : nullptr;
1124}
1125
1127 return SetNode ? SetNode->getAttributeType(Attribute::ByVal) : nullptr;
1128}
1129
1131 return SetNode ? SetNode->getAttributeType(Attribute::StructRet) : nullptr;
1132}
1133
1135 return SetNode ? SetNode->getAttributeType(Attribute::Preallocated) : nullptr;
1136}
1137
1139 return SetNode ? SetNode->getAttributeType(Attribute::InAlloca) : nullptr;
1140}
1141
1143 return SetNode ? SetNode->getAttributeType(Attribute::ElementType) : nullptr;
1144}
1145
1146std::optional<std::pair<unsigned, std::optional<unsigned>>>
1148 if (SetNode)
1149 return SetNode->getAllocSizeArgs();
1150 return std::nullopt;
1151}
1152
1154 return SetNode ? SetNode->getVScaleRangeMin() : 1;
1155}
1156
1157std::optional<unsigned> AttributeSet::getVScaleRangeMax() const {
1158 return SetNode ? SetNode->getVScaleRangeMax() : std::nullopt;
1159}
1160
1162 return SetNode ? SetNode->getUWTableKind() : UWTableKind::None;
1163}
1164
1166 return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown;
1167}
1168
1170 return SetNode ? SetNode->getMemoryEffects() : MemoryEffects::unknown();
1171}
1172
1174 return SetNode ? SetNode->getNoFPClass() : fcNone;
1175}
1176
1177std::string AttributeSet::getAsString(bool InAttrGrp) const {
1178 return SetNode ? SetNode->getAsString(InAttrGrp) : "";
1179}
1180
1182 assert(hasAttributes() && "empty AttributeSet doesn't refer to any context");
1184 SetNode->Profile(ID);
1185 void *Unused;
1186 return C.pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, Unused) == SetNode;
1187}
1188
1190 return SetNode ? SetNode->begin() : nullptr;
1191}
1192
1194 return SetNode ? SetNode->end() : nullptr;
1195}
1196
1197#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1199 dbgs() << "AS =\n";
1200 dbgs() << " { ";
1201 dbgs() << getAsString(true) << " }\n";
1202}
1203#endif
1204
1205//===----------------------------------------------------------------------===//
1206// AttributeSetNode Definition
1207//===----------------------------------------------------------------------===//
1208
1209AttributeSetNode::AttributeSetNode(ArrayRef<Attribute> Attrs)
1210 : NumAttrs(Attrs.size()) {
1211 // There's memory after the node where we can store the entries in.
1212 llvm::copy(Attrs, getTrailingObjects<Attribute>());
1213
1214 for (const auto &I : *this) {
1215 if (I.isStringAttribute())
1216 StringAttrs.insert({ I.getKindAsString(), I });
1217 else
1218 AvailableAttrs.addAttribute(I.getKindAsEnum());
1219 }
1220}
1221
1223 ArrayRef<Attribute> Attrs) {
1224 SmallVector<Attribute, 8> SortedAttrs(Attrs);
1225 llvm::sort(SortedAttrs);
1226 return getSorted(C, SortedAttrs);
1227}
1228
1229AttributeSetNode *AttributeSetNode::getSorted(LLVMContext &C,
1230 ArrayRef<Attribute> SortedAttrs) {
1231 if (SortedAttrs.empty())
1232 return nullptr;
1233
1234 // Build a key to look up the existing attributes.
1235 LLVMContextImpl *pImpl = C.pImpl;
1237
1238 assert(llvm::is_sorted(SortedAttrs) && "Expected sorted attributes!");
1239 for (const auto &Attr : SortedAttrs)
1240 Attr.Profile(ID);
1241
1242 void *InsertPoint;
1243 AttributeSetNode *PA =
1244 pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, InsertPoint);
1245
1246 // If we didn't find any existing attributes of the same shape then create a
1247 // new one and insert it.
1248 if (!PA) {
1249 // Coallocate entries after the AttributeSetNode itself.
1250 void *Mem = ::operator new(totalSizeToAlloc<Attribute>(SortedAttrs.size()));
1251 PA = new (Mem) AttributeSetNode(SortedAttrs);
1252 pImpl->AttrsSetNodes.InsertNode(PA, InsertPoint);
1253 }
1254
1255 // Return the AttributeSetNode that we found or created.
1256 return PA;
1257}
1258
1260 return getSorted(C, B.attrs());
1261}
1262
1264 return StringAttrs.count(Kind);
1265}
1266
1267std::optional<Attribute>
1268AttributeSetNode::findEnumAttribute(Attribute::AttrKind Kind) const {
1269 // Do a quick presence check.
1270 if (!hasAttribute(Kind))
1271 return std::nullopt;
1272
1273 // Attributes in a set are sorted by enum value, followed by string
1274 // attributes. Binary search the one we want.
1275 const Attribute *I =
1276 std::lower_bound(begin(), end() - StringAttrs.size(), Kind,
1277 [](Attribute A, Attribute::AttrKind Kind) {
1278 return A.getKindAsEnum() < Kind;
1279 });
1280 assert(I != end() && I->hasAttribute(Kind) && "Presence check failed?");
1281 return *I;
1282}
1283
1285 if (auto A = findEnumAttribute(Kind))
1286 return *A;
1287 return {};
1288}
1289
1291 return StringAttrs.lookup(Kind);
1292}
1293
1295 if (auto A = findEnumAttribute(Attribute::Alignment))
1296 return A->getAlignment();
1297 return std::nullopt;
1298}
1299
1301 if (auto A = findEnumAttribute(Attribute::StackAlignment))
1302 return A->getStackAlignment();
1303 return std::nullopt;
1304}
1305
1307 if (auto A = findEnumAttribute(Kind))
1308 return A->getValueAsType();
1309 return nullptr;
1310}
1311
1313 if (auto A = findEnumAttribute(Attribute::Dereferenceable))
1314 return A->getDereferenceableBytes();
1315 return 0;
1316}
1317
1319 if (auto A = findEnumAttribute(Attribute::DereferenceableOrNull))
1320 return A->getDereferenceableOrNullBytes();
1321 return 0;
1322}
1323
1324std::optional<std::pair<unsigned, std::optional<unsigned>>>
1326 if (auto A = findEnumAttribute(Attribute::AllocSize))
1327 return A->getAllocSizeArgs();
1328 return std::nullopt;
1329}
1330
1332 if (auto A = findEnumAttribute(Attribute::VScaleRange))
1333 return A->getVScaleRangeMin();
1334 return 1;
1335}
1336
1337std::optional<unsigned> AttributeSetNode::getVScaleRangeMax() const {
1338 if (auto A = findEnumAttribute(Attribute::VScaleRange))
1339 return A->getVScaleRangeMax();
1340 return std::nullopt;
1341}
1342
1344 if (auto A = findEnumAttribute(Attribute::UWTable))
1345 return A->getUWTableKind();
1346 return UWTableKind::None;
1347}
1348
1350 if (auto A = findEnumAttribute(Attribute::AllocKind))
1351 return A->getAllocKind();
1352 return AllocFnKind::Unknown;
1353}
1354
1356 if (auto A = findEnumAttribute(Attribute::Memory))
1357 return A->getMemoryEffects();
1358 return MemoryEffects::unknown();
1359}
1360
1362 if (auto A = findEnumAttribute(Attribute::NoFPClass))
1363 return A->getNoFPClass();
1364 return fcNone;
1365}
1366
1367std::string AttributeSetNode::getAsString(bool InAttrGrp) const {
1368 std::string Str;
1369 for (iterator I = begin(), E = end(); I != E; ++I) {
1370 if (I != begin())
1371 Str += ' ';
1372 Str += I->getAsString(InAttrGrp);
1373 }
1374 return Str;
1375}
1376
1377//===----------------------------------------------------------------------===//
1378// AttributeListImpl Definition
1379//===----------------------------------------------------------------------===//
1380
1381/// Map from AttributeList index to the internal array index. Adding one happens
1382/// to work, because -1 wraps around to 0.
1383static unsigned attrIdxToArrayIdx(unsigned Index) {
1384 return Index + 1;
1385}
1386
1388 : NumAttrSets(Sets.size()) {
1389 assert(!Sets.empty() && "pointless AttributeListImpl");
1390
1391 // There's memory after the node where we can store the entries in.
1392 llvm::copy(Sets, getTrailingObjects<AttributeSet>());
1393
1394 // Initialize AvailableFunctionAttrs and AvailableSomewhereAttrs
1395 // summary bitsets.
1396 for (const auto &I : Sets[attrIdxToArrayIdx(AttributeList::FunctionIndex)])
1397 if (!I.isStringAttribute())
1398 AvailableFunctionAttrs.addAttribute(I.getKindAsEnum());
1399
1400 for (const auto &Set : Sets)
1401 for (const auto &I : Set)
1402 if (!I.isStringAttribute())
1403 AvailableSomewhereAttrs.addAttribute(I.getKindAsEnum());
1404}
1405
1407 Profile(ID, ArrayRef(begin(), end()));
1408}
1409
1412 for (const auto &Set : Sets)
1413 ID.AddPointer(Set.SetNode);
1414}
1415
1417 unsigned *Index) const {
1418 if (!AvailableSomewhereAttrs.hasAttribute(Kind))
1419 return false;
1420
1421 if (Index) {
1422 for (unsigned I = 0, E = NumAttrSets; I != E; ++I) {
1423 if (begin()[I].hasAttribute(Kind)) {
1424 *Index = I - 1;
1425 break;
1426 }
1427 }
1428 }
1429
1430 return true;
1431}
1432
1433
1434#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1436 AttributeList(const_cast<AttributeListImpl *>(this)).dump();
1437}
1438#endif
1439
1440//===----------------------------------------------------------------------===//
1441// AttributeList Construction and Mutation Methods
1442//===----------------------------------------------------------------------===//
1443
1444AttributeList AttributeList::getImpl(LLVMContext &C,
1445 ArrayRef<AttributeSet> AttrSets) {
1446 assert(!AttrSets.empty() && "pointless AttributeListImpl");
1447
1448 LLVMContextImpl *pImpl = C.pImpl;
1450 AttributeListImpl::Profile(ID, AttrSets);
1451
1452 void *InsertPoint;
1453 AttributeListImpl *PA =
1454 pImpl->AttrsLists.FindNodeOrInsertPos(ID, InsertPoint);
1455
1456 // If we didn't find any existing attributes of the same shape then
1457 // create a new one and insert it.
1458 if (!PA) {
1459 // Coallocate entries after the AttributeListImpl itself.
1460 void *Mem = pImpl->Alloc.Allocate(
1461 AttributeListImpl::totalSizeToAlloc<AttributeSet>(AttrSets.size()),
1462 alignof(AttributeListImpl));
1463 PA = new (Mem) AttributeListImpl(AttrSets);
1464 pImpl->AttrsLists.InsertNode(PA, InsertPoint);
1465 }
1466
1467 // Return the AttributesList that we found or created.
1468 return AttributeList(PA);
1469}
1470
1473 ArrayRef<std::pair<unsigned, Attribute>> Attrs) {
1474 // If there are no attributes then return a null AttributesList pointer.
1475 if (Attrs.empty())
1476 return {};
1477
1479 "Misordered Attributes list!");
1480 assert(llvm::all_of(Attrs,
1481 [](const std::pair<unsigned, Attribute> &Pair) {
1482 return Pair.second.isValid();
1483 }) &&
1484 "Pointless attribute!");
1485
1486 // Create a vector if (unsigned, AttributeSetNode*) pairs from the attributes
1487 // list.
1489 for (ArrayRef<std::pair<unsigned, Attribute>>::iterator I = Attrs.begin(),
1490 E = Attrs.end(); I != E; ) {
1491 unsigned Index = I->first;
1493 while (I != E && I->first == Index) {
1494 AttrVec.push_back(I->second);
1495 ++I;
1496 }
1497
1498 AttrPairVec.emplace_back(Index, AttributeSet::get(C, AttrVec));
1499 }
1500
1501 return get(C, AttrPairVec);
1502}
1503
1506 ArrayRef<std::pair<unsigned, AttributeSet>> Attrs) {
1507 // If there are no attributes then return a null AttributesList pointer.
1508 if (Attrs.empty())
1509 return {};
1510
1512 "Misordered Attributes list!");
1513 assert(llvm::none_of(Attrs,
1514 [](const std::pair<unsigned, AttributeSet> &Pair) {
1515 return !Pair.second.hasAttributes();
1516 }) &&
1517 "Pointless attribute!");
1518
1519 unsigned MaxIndex = Attrs.back().first;
1520 // If the MaxIndex is FunctionIndex and there are other indices in front
1521 // of it, we need to use the largest of those to get the right size.
1522 if (MaxIndex == FunctionIndex && Attrs.size() > 1)
1523 MaxIndex = Attrs[Attrs.size() - 2].first;
1524
1525 SmallVector<AttributeSet, 4> AttrVec(attrIdxToArrayIdx(MaxIndex) + 1);
1526 for (const auto &Pair : Attrs)
1527 AttrVec[attrIdxToArrayIdx(Pair.first)] = Pair.second;
1528
1529 return getImpl(C, AttrVec);
1530}
1531
1533 AttributeSet RetAttrs,
1534 ArrayRef<AttributeSet> ArgAttrs) {
1535 // Scan from the end to find the last argument with attributes. Most
1536 // arguments don't have attributes, so it's nice if we can have fewer unique
1537 // AttributeListImpls by dropping empty attribute sets at the end of the list.
1538 unsigned NumSets = 0;
1539 for (size_t I = ArgAttrs.size(); I != 0; --I) {
1540 if (ArgAttrs[I - 1].hasAttributes()) {
1541 NumSets = I + 2;
1542 break;
1543 }
1544 }
1545 if (NumSets == 0) {
1546 // Check function and return attributes if we didn't have argument
1547 // attributes.
1548 if (RetAttrs.hasAttributes())
1549 NumSets = 2;
1550 else if (FnAttrs.hasAttributes())
1551 NumSets = 1;
1552 }
1553
1554 // If all attribute sets were empty, we can use the empty attribute list.
1555 if (NumSets == 0)
1556 return {};
1557
1559 AttrSets.reserve(NumSets);
1560 // If we have any attributes, we always have function attributes.
1561 AttrSets.push_back(FnAttrs);
1562 if (NumSets > 1)
1563 AttrSets.push_back(RetAttrs);
1564 if (NumSets > 2) {
1565 // Drop the empty argument attribute sets at the end.
1566 ArgAttrs = ArgAttrs.take_front(NumSets - 2);
1567 llvm::append_range(AttrSets, ArgAttrs);
1568 }
1569
1570 return getImpl(C, AttrSets);
1571}
1572
1574 AttributeSet Attrs) {
1575 if (!Attrs.hasAttributes())
1576 return {};
1577 Index = attrIdxToArrayIdx(Index);
1578 SmallVector<AttributeSet, 8> AttrSets(Index + 1);
1579 AttrSets[Index] = Attrs;
1580 return getImpl(C, AttrSets);
1581}
1582
1584 const AttrBuilder &B) {
1585 return get(C, Index, AttributeSet::get(C, B));
1586}
1587
1591 for (const auto K : Kinds)
1592 Attrs.emplace_back(Index, Attribute::get(C, K));
1593 return get(C, Attrs);
1594}
1595
1598 ArrayRef<uint64_t> Values) {
1599 assert(Kinds.size() == Values.size() && "Mismatched attribute values.");
1601 auto VI = Values.begin();
1602 for (const auto K : Kinds)
1603 Attrs.emplace_back(Index, Attribute::get(C, K, *VI++));
1604 return get(C, Attrs);
1605}
1606
1608 ArrayRef<StringRef> Kinds) {
1610 for (const auto &K : Kinds)
1611 Attrs.emplace_back(Index, Attribute::get(C, K));
1612 return get(C, Attrs);
1613}
1614
1617 if (Attrs.empty())
1618 return {};
1619 if (Attrs.size() == 1)
1620 return Attrs[0];
1621
1622 unsigned MaxSize = 0;
1623 for (const auto &List : Attrs)
1624 MaxSize = std::max(MaxSize, List.getNumAttrSets());
1625
1626 // If every list was empty, there is no point in merging the lists.
1627 if (MaxSize == 0)
1628 return {};
1629
1630 SmallVector<AttributeSet, 8> NewAttrSets(MaxSize);
1631 for (unsigned I = 0; I < MaxSize; ++I) {
1632 AttrBuilder CurBuilder(C);
1633 for (const auto &List : Attrs)
1634 CurBuilder.merge(AttrBuilder(C, List.getAttributes(I - 1)));
1635 NewAttrSets[I] = AttributeSet::get(C, CurBuilder);
1636 }
1637
1638 return getImpl(C, NewAttrSets);
1639}
1640
1643 Attribute::AttrKind Kind) const {
1644 AttributeSet Attrs = getAttributes(Index);
1645 if (Attrs.hasAttribute(Kind))
1646 return *this;
1647 // TODO: Insert at correct position and avoid sort.
1648 SmallVector<Attribute, 8> NewAttrs(Attrs.begin(), Attrs.end());
1649 NewAttrs.push_back(Attribute::get(C, Kind));
1650 return setAttributesAtIndex(C, Index, AttributeSet::get(C, NewAttrs));
1651}
1652
1654 StringRef Kind,
1655 StringRef Value) const {
1656 AttrBuilder B(C);
1657 B.addAttribute(Kind, Value);
1658 return addAttributesAtIndex(C, Index, B);
1659}
1660
1662 Attribute A) const {
1663 AttrBuilder B(C);
1664 B.addAttribute(A);
1665 return addAttributesAtIndex(C, Index, B);
1666}
1667
1668AttributeList AttributeList::setAttributesAtIndex(LLVMContext &C,
1669 unsigned Index,
1670 AttributeSet Attrs) const {
1671 Index = attrIdxToArrayIdx(Index);
1672 SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
1673 if (Index >= AttrSets.size())
1674 AttrSets.resize(Index + 1);
1675 AttrSets[Index] = Attrs;
1676
1677 // Remove trailing empty attribute sets.
1678 while (!AttrSets.empty() && !AttrSets.back().hasAttributes())
1679 AttrSets.pop_back();
1680 if (AttrSets.empty())
1681 return {};
1682 return AttributeList::getImpl(C, AttrSets);
1683}
1684
1686 unsigned Index,
1687 const AttrBuilder &B) const {
1688 if (!B.hasAttributes())
1689 return *this;
1690
1691 if (!pImpl)
1692 return AttributeList::get(C, {{Index, AttributeSet::get(C, B)}});
1693
1694 AttrBuilder Merged(C, getAttributes(Index));
1695 Merged.merge(B);
1696 return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged));
1697}
1698
1700 ArrayRef<unsigned> ArgNos,
1701 Attribute A) const {
1702 assert(llvm::is_sorted(ArgNos));
1703
1704 SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
1705 unsigned MaxIndex = attrIdxToArrayIdx(ArgNos.back() + FirstArgIndex);
1706 if (MaxIndex >= AttrSets.size())
1707 AttrSets.resize(MaxIndex + 1);
1708
1709 for (unsigned ArgNo : ArgNos) {
1710 unsigned Index = attrIdxToArrayIdx(ArgNo + FirstArgIndex);
1711 AttrBuilder B(C, AttrSets[Index]);
1712 B.addAttribute(A);
1713 AttrSets[Index] = AttributeSet::get(C, B);
1714 }
1715
1716 return getImpl(C, AttrSets);
1717}
1718
1721 Attribute::AttrKind Kind) const {
1722 AttributeSet Attrs = getAttributes(Index);
1723 AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind);
1724 if (Attrs == NewAttrs)
1725 return *this;
1726 return setAttributesAtIndex(C, Index, NewAttrs);
1727}
1728
1730 unsigned Index,
1731 StringRef Kind) const {
1732 AttributeSet Attrs = getAttributes(Index);
1733 AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind);
1734 if (Attrs == NewAttrs)
1735 return *this;
1736 return setAttributesAtIndex(C, Index, NewAttrs);
1737}
1738
1740 LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const {
1741 AttributeSet Attrs = getAttributes(Index);
1742 AttributeSet NewAttrs = Attrs.removeAttributes(C, AttrsToRemove);
1743 // If nothing was removed, return the original list.
1744 if (Attrs == NewAttrs)
1745 return *this;
1746 return setAttributesAtIndex(C, Index, NewAttrs);
1747}
1748
1751 unsigned WithoutIndex) const {
1752 if (!pImpl)
1753 return {};
1754 if (attrIdxToArrayIdx(WithoutIndex) >= getNumAttrSets())
1755 return *this;
1756 return setAttributesAtIndex(C, WithoutIndex, AttributeSet());
1757}
1758
1760 uint64_t Bytes) const {
1761 AttrBuilder B(C);
1762 B.addDereferenceableAttr(Bytes);
1763 return addRetAttributes(C, B);
1764}
1765
1767 unsigned Index,
1768 uint64_t Bytes) const {
1769 AttrBuilder B(C);
1770 B.addDereferenceableAttr(Bytes);
1771 return addParamAttributes(C, Index, B);
1772}
1773
1776 uint64_t Bytes) const {
1777 AttrBuilder B(C);
1778 B.addDereferenceableOrNullAttr(Bytes);
1779 return addParamAttributes(C, Index, B);
1780}
1781
1783 const ConstantRange &CR) const {
1784 AttrBuilder B(C);
1785 B.addRangeAttr(CR);
1786 return addRetAttributes(C, B);
1787}
1788
1790 LLVMContext &C, unsigned Index, unsigned ElemSizeArg,
1791 const std::optional<unsigned> &NumElemsArg) const {
1792 AttrBuilder B(C);
1793 B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);
1794 return addParamAttributes(C, Index, B);
1795}
1796
1797std::optional<AttributeList>
1799 // Trivial case, the two lists are equal.
1800 if (*this == Other)
1801 return *this;
1802
1804 auto IndexIt =
1805 index_iterator(std::max(getNumAttrSets(), Other.getNumAttrSets()));
1806 for (unsigned Idx : IndexIt) {
1807 auto IntersectedAS =
1808 getAttributes(Idx).intersectWith(C, Other.getAttributes(Idx));
1809 // If any index fails to intersect, fail.
1810 if (!IntersectedAS)
1811 return std::nullopt;
1812 if (!IntersectedAS->hasAttributes())
1813 continue;
1814 IntersectedAttrs.push_back(std::make_pair(Idx, *IntersectedAS));
1815 }
1816
1817 llvm::sort(IntersectedAttrs, llvm::less_first());
1818 return AttributeList::get(C, IntersectedAttrs);
1819}
1820
1821//===----------------------------------------------------------------------===//
1822// AttributeList Accessor Methods
1823//===----------------------------------------------------------------------===//
1824
1826 return getAttributes(ArgNo + FirstArgIndex);
1827}
1828
1830 return getAttributes(ReturnIndex);
1831}
1832
1835}
1836
1838 Attribute::AttrKind Kind) const {
1839 return getAttributes(Index).hasAttribute(Kind);
1840}
1841
1842bool AttributeList::hasAttributeAtIndex(unsigned Index, StringRef Kind) const {
1843 return getAttributes(Index).hasAttribute(Kind);
1844}
1845
1846bool AttributeList::hasAttributesAtIndex(unsigned Index) const {
1847 return getAttributes(Index).hasAttributes();
1848}
1849
1851 return pImpl && pImpl->hasFnAttribute(Kind);
1852}
1853
1856}
1857
1859 unsigned *Index) const {
1860 return pImpl && pImpl->hasAttrSomewhere(Attr, Index);
1861}
1862
1864 Attribute::AttrKind Kind) const {
1865 return getAttributes(Index).getAttribute(Kind);
1866}
1867
1869 StringRef Kind) const {
1870 return getAttributes(Index).getAttribute(Kind);
1871}
1872
1875}
1876
1878 return getAttributes(ArgNo + FirstArgIndex).getAlignment();
1879}
1880
1883}
1884
1887}
1888
1891}
1892
1894 return getAttributes(Index + FirstArgIndex).getByRefType();
1895}
1896
1899}
1900
1903}
1904
1906 return getAttributes(Index + FirstArgIndex).getElementType();
1907}
1908
1910 return getFnAttrs().getStackAlignment();
1911}
1912
1914 return getRetAttrs().getStackAlignment();
1915}
1916
1919}
1920
1922 return getParamAttrs(Index).getDereferenceableBytes();
1923}
1924
1927}
1928
1932}
1933
1934std::optional<ConstantRange>
1935AttributeList::getParamRange(unsigned ArgNo) const {
1936 auto RangeAttr = getParamAttrs(ArgNo).getAttribute(Attribute::Range);
1937 if (RangeAttr.isValid())
1938 return RangeAttr.getRange();
1939 return std::nullopt;
1940}
1941
1943 return getRetAttrs().getNoFPClass();
1944}
1945
1947 return getParamAttrs(Index).getNoFPClass();
1948}
1949
1951 return getFnAttrs().getUWTableKind();
1952}
1953
1955 return getFnAttrs().getAllocKind();
1956}
1957
1959 return getFnAttrs().getMemoryEffects();
1960}
1961
1962std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const {
1963 return getAttributes(Index).getAsString(InAttrGrp);
1964}
1965
1967 Index = attrIdxToArrayIdx(Index);
1968 if (!pImpl || Index >= getNumAttrSets())
1969 return {};
1970 return pImpl->begin()[Index];
1971}
1972
1974 assert(!isEmpty() && "an empty attribute list has no parent context");
1976 pImpl->Profile(ID);
1977 void *Unused;
1978 return C.pImpl->AttrsLists.FindNodeOrInsertPos(ID, Unused) == pImpl;
1979}
1980
1982 return pImpl ? pImpl->begin() : nullptr;
1983}
1984
1986 return pImpl ? pImpl->end() : nullptr;
1987}
1988
1989//===----------------------------------------------------------------------===//
1990// AttributeList Introspection Methods
1991//===----------------------------------------------------------------------===//
1992
1994 return pImpl ? pImpl->NumAttrSets : 0;
1995}
1996
1998 O << "AttributeList[\n";
1999
2000 for (unsigned i : indexes()) {
2001 if (!getAttributes(i).hasAttributes())
2002 continue;
2003 O << " { ";
2004 switch (i) {
2006 O << "return";
2007 break;
2009 O << "function";
2010 break;
2011 default:
2012 O << "arg(" << i - AttrIndex::FirstArgIndex << ")";
2013 }
2014 O << " => " << getAsString(i) << " }\n";
2015 }
2016
2017 O << "]\n";
2018}
2019
2020#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2022#endif
2023
2024//===----------------------------------------------------------------------===//
2025// AttrBuilder Method Implementations
2026//===----------------------------------------------------------------------===//
2027
2029 append_range(Attrs, AS);
2030 assert(is_sorted(Attrs) && "AttributeSet should be sorted");
2031}
2032
2033void AttrBuilder::clear() { Attrs.clear(); }
2034
2035/// Attribute comparator that only compares attribute keys. Enum attributes are
2036/// sorted before string attributes.
2038 bool operator()(Attribute A0, Attribute A1) const {
2039 bool A0IsString = A0.isStringAttribute();
2040 bool A1IsString = A1.isStringAttribute();
2041 if (A0IsString) {
2042 if (A1IsString)
2043 return A0.getKindAsString() < A1.getKindAsString();
2044 else
2045 return false;
2046 }
2047 if (A1IsString)
2048 return true;
2049 return A0.getKindAsEnum() < A1.getKindAsEnum();
2050 }
2052 if (A0.isStringAttribute())
2053 return false;
2054 return A0.getKindAsEnum() < Kind;
2055 }
2056 bool operator()(Attribute A0, StringRef Kind) const {
2057 if (A0.isStringAttribute())
2058 return A0.getKindAsString() < Kind;
2059 return true;
2060 }
2061};
2062
2063template <typename K>
2065 Attribute Attr) {
2066 auto It = lower_bound(Attrs, Kind, AttributeComparator());
2067 if (It != Attrs.end() && It->hasAttribute(Kind))
2068 std::swap(*It, Attr);
2069 else
2070 Attrs.insert(It, Attr);
2071}
2072
2074 if (Attr.isStringAttribute())
2075 addAttributeImpl(Attrs, Attr.getKindAsString(), Attr);
2076 else
2077 addAttributeImpl(Attrs, Attr.getKindAsEnum(), Attr);
2078 return *this;
2079}
2080
2082 addAttributeImpl(Attrs, Kind, Attribute::get(Ctx, Kind));
2083 return *this;
2084}
2085
2087 addAttributeImpl(Attrs, A, Attribute::get(Ctx, A, V));
2088 return *this;
2089}
2090
2092 assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
2093 auto It = lower_bound(Attrs, Val, AttributeComparator());
2094 if (It != Attrs.end() && It->hasAttribute(Val))
2095 Attrs.erase(It);
2096 return *this;
2097}
2098
2100 auto It = lower_bound(Attrs, A, AttributeComparator());
2101 if (It != Attrs.end() && It->hasAttribute(A))
2102 Attrs.erase(It);
2103 return *this;
2104}
2105
2106std::optional<uint64_t>
2108 assert(Attribute::isIntAttrKind(Kind) && "Not an int attribute");
2109 Attribute A = getAttribute(Kind);
2110 if (A.isValid())
2111 return A.getValueAsInt();
2112 return std::nullopt;
2113}
2114
2116 uint64_t Value) {
2117 return addAttribute(Attribute::get(Ctx, Kind, Value));
2118}
2119
2120std::optional<std::pair<unsigned, std::optional<unsigned>>>
2122 Attribute A = getAttribute(Attribute::AllocSize);
2123 if (A.isValid())
2124 return A.getAllocSizeArgs();
2125 return std::nullopt;
2126}
2127
2129 if (!Align)
2130 return *this;
2131
2132 assert(*Align <= llvm::Value::MaximumAlignment && "Alignment too large.");
2133 return addRawIntAttr(Attribute::Alignment, Align->value());
2134}
2135
2137 // Default alignment, allow the target to define how to align it.
2138 if (!Align)
2139 return *this;
2140
2141 assert(*Align <= 0x100 && "Alignment too large.");
2142 return addRawIntAttr(Attribute::StackAlignment, Align->value());
2143}
2144
2146 if (Bytes == 0) return *this;
2147
2148 return addRawIntAttr(Attribute::Dereferenceable, Bytes);
2149}
2150
2152 if (Bytes == 0)
2153 return *this;
2154
2155 return addRawIntAttr(Attribute::DereferenceableOrNull, Bytes);
2156}
2157
2160 const std::optional<unsigned> &NumElems) {
2161 return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems));
2162}
2163
2165 // (0, 0) is our "not present" value, so we need to check for it here.
2166 assert(RawArgs && "Invalid allocsize arguments -- given allocsize(0, 0)");
2167 return addRawIntAttr(Attribute::AllocSize, RawArgs);
2168}
2169
2171 std::optional<unsigned> MaxValue) {
2172 return addVScaleRangeAttrFromRawRepr(packVScaleRangeArgs(MinValue, MaxValue));
2173}
2174
2176 // (0, 0) is not present hence ignore this case
2177 if (RawArgs == 0)
2178 return *this;
2179
2180 return addRawIntAttr(Attribute::VScaleRange, RawArgs);
2181}
2182
2184 if (Kind == UWTableKind::None)
2185 return *this;
2186 return addRawIntAttr(Attribute::UWTable, uint64_t(Kind));
2187}
2188
2190 return addRawIntAttr(Attribute::Memory, ME.toIntValue());
2191}
2192
2194 if (Mask == fcNone)
2195 return *this;
2196
2197 return addRawIntAttr(Attribute::NoFPClass, Mask);
2198}
2199
2201 return addRawIntAttr(Attribute::AllocKind, static_cast<uint64_t>(Kind));
2202}
2203
2205 assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute");
2206 Attribute A = getAttribute(Kind);
2207 return A.isValid() ? A.getValueAsType() : nullptr;
2208}
2209
2211 return addAttribute(Attribute::get(Ctx, Kind, Ty));
2212}
2213
2215 return addTypeAttr(Attribute::ByVal, Ty);
2216}
2217
2219 return addTypeAttr(Attribute::StructRet, Ty);
2220}
2221
2223 return addTypeAttr(Attribute::ByRef, Ty);
2224}
2225
2227 return addTypeAttr(Attribute::Preallocated, Ty);
2228}
2229
2231 return addTypeAttr(Attribute::InAlloca, Ty);
2232}
2233
2235 const ConstantRange &CR) {
2236 if (CR.isFullSet())
2237 return *this;
2238
2239 return addAttribute(Attribute::get(Ctx, Kind, CR));
2240}
2241
2243 return addConstantRangeAttr(Attribute::Range, CR);
2244}
2245
2249 return addAttribute(Attribute::get(Ctx, Kind, Val));
2250}
2251
2253 return addConstantRangeListAttr(Attribute::Initializes, CRL.rangesRef());
2254}
2255
2257 // TODO: Could make this O(n) as we're merging two sorted lists.
2258 for (const auto &I : B.attrs())
2259 addAttribute(I);
2260
2261 return *this;
2262}
2263
2265 erase_if(Attrs, [&](Attribute A) { return AM.contains(A); });
2266 return *this;
2267}
2268
2270 return any_of(Attrs, [&](Attribute A) { return AM.contains(A); });
2271}
2272
2274 assert((unsigned)A < Attribute::EndAttrKinds && "Attribute out of range!");
2275 auto It = lower_bound(Attrs, A, AttributeComparator());
2276 if (It != Attrs.end() && It->hasAttribute(A))
2277 return *It;
2278 return {};
2279}
2280
2282 auto It = lower_bound(Attrs, A, AttributeComparator());
2283 if (It != Attrs.end() && It->hasAttribute(A))
2284 return *It;
2285 return {};
2286}
2287
2288std::optional<ConstantRange> AttrBuilder::getRange() const {
2289 const Attribute RangeAttr = getAttribute(Attribute::Range);
2290 if (RangeAttr.isValid())
2291 return RangeAttr.getRange();
2292 return std::nullopt;
2293}
2294
2296 return getAttribute(A).isValid();
2297}
2298
2300 return getAttribute(A).isValid();
2301}
2302
2304 return Attrs == B.Attrs;
2305}
2306
2307//===----------------------------------------------------------------------===//
2308// AttributeFuncs Function Defintions
2309//===----------------------------------------------------------------------===//
2310
2311/// Returns true if this is a type legal for the 'nofpclass' attribute. This
2312/// follows the same type rules as FPMathOperator.
2315}
2316
2317/// Which attributes cannot be applied to a type.
2319 AttributeSafetyKind ASK) {
2320 AttributeMask Incompatible;
2321
2322 if (!Ty->isIntegerTy()) {
2323 // Attributes that only apply to integers.
2324 if (ASK & ASK_SAFE_TO_DROP)
2325 Incompatible.addAttribute(Attribute::AllocAlign);
2326 if (ASK & ASK_UNSAFE_TO_DROP)
2327 Incompatible.addAttribute(Attribute::SExt).addAttribute(Attribute::ZExt);
2328 }
2329
2330 if (!Ty->isIntOrIntVectorTy()) {
2331 // Attributes that only apply to integers or vector of integers.
2332 if (ASK & ASK_SAFE_TO_DROP)
2333 Incompatible.addAttribute(Attribute::Range);
2334 } else {
2335 Attribute RangeAttr = AS.getAttribute(Attribute::Range);
2336 if (RangeAttr.isValid() &&
2337 RangeAttr.getRange().getBitWidth() != Ty->getScalarSizeInBits())
2338 Incompatible.addAttribute(Attribute::Range);
2339 }
2340
2341 if (!Ty->isPointerTy()) {
2342 // Attributes that only apply to pointers.
2343 if (ASK & ASK_SAFE_TO_DROP)
2344 Incompatible.addAttribute(Attribute::NoAlias)
2345 .addAttribute(Attribute::NoCapture)
2346 .addAttribute(Attribute::NonNull)
2347 .addAttribute(Attribute::ReadNone)
2348 .addAttribute(Attribute::ReadOnly)
2349 .addAttribute(Attribute::Dereferenceable)
2350 .addAttribute(Attribute::DereferenceableOrNull)
2351 .addAttribute(Attribute::Writable)
2352 .addAttribute(Attribute::DeadOnUnwind)
2353 .addAttribute(Attribute::Initializes);
2354 if (ASK & ASK_UNSAFE_TO_DROP)
2355 Incompatible.addAttribute(Attribute::Nest)
2356 .addAttribute(Attribute::SwiftError)
2357 .addAttribute(Attribute::Preallocated)
2358 .addAttribute(Attribute::InAlloca)
2359 .addAttribute(Attribute::ByVal)
2360 .addAttribute(Attribute::StructRet)
2361 .addAttribute(Attribute::ByRef)
2362 .addAttribute(Attribute::ElementType)
2363 .addAttribute(Attribute::AllocatedPointer);
2364 }
2365
2366 // Attributes that only apply to pointers or vectors of pointers.
2367 if (!Ty->isPtrOrPtrVectorTy()) {
2368 if (ASK & ASK_SAFE_TO_DROP)
2369 Incompatible.addAttribute(Attribute::Alignment);
2370 }
2371
2372 if (ASK & ASK_SAFE_TO_DROP) {
2374 Incompatible.addAttribute(Attribute::NoFPClass);
2375 }
2376
2377 // Some attributes can apply to all "values" but there are no `void` values.
2378 if (Ty->isVoidTy()) {
2379 if (ASK & ASK_SAFE_TO_DROP)
2380 Incompatible.addAttribute(Attribute::NoUndef);
2381 }
2382
2383 return Incompatible;
2384}
2385
2387 AttributeMask AM;
2388 AM.addAttribute(Attribute::NoUndef);
2389 AM.addAttribute(Attribute::Dereferenceable);
2390 AM.addAttribute(Attribute::DereferenceableOrNull);
2391 return AM;
2392}
2393
2394/// Callees with dynamic denormal modes are compatible with any caller mode.
2395static bool denormModeCompatible(DenormalMode CallerMode,
2396 DenormalMode CalleeMode) {
2397 if (CallerMode == CalleeMode || CalleeMode == DenormalMode::getDynamic())
2398 return true;
2399
2400 // If they don't exactly match, it's OK if the mismatched component is
2401 // dynamic.
2402 if (CalleeMode.Input == CallerMode.Input &&
2403 CalleeMode.Output == DenormalMode::Dynamic)
2404 return true;
2405
2406 if (CalleeMode.Output == CallerMode.Output &&
2407 CalleeMode.Input == DenormalMode::Dynamic)
2408 return true;
2409 return false;
2410}
2411
2412static bool checkDenormMode(const Function &Caller, const Function &Callee) {
2413 DenormalMode CallerMode = Caller.getDenormalModeRaw();
2414 DenormalMode CalleeMode = Callee.getDenormalModeRaw();
2415
2416 if (denormModeCompatible(CallerMode, CalleeMode)) {
2417 DenormalMode CallerModeF32 = Caller.getDenormalModeF32Raw();
2418 DenormalMode CalleeModeF32 = Callee.getDenormalModeF32Raw();
2419 if (CallerModeF32 == DenormalMode::getInvalid())
2420 CallerModeF32 = CallerMode;
2421 if (CalleeModeF32 == DenormalMode::getInvalid())
2422 CalleeModeF32 = CalleeMode;
2423 return denormModeCompatible(CallerModeF32, CalleeModeF32);
2424 }
2425
2426 return false;
2427}
2428
2429static bool checkStrictFP(const Function &Caller, const Function &Callee) {
2430 // Do not inline strictfp function into non-strictfp one. It would require
2431 // conversion of all FP operations in host function to constrained intrinsics.
2432 return !Callee.getAttributes().hasFnAttr(Attribute::StrictFP) ||
2433 Caller.getAttributes().hasFnAttr(Attribute::StrictFP);
2434}
2435
2436template<typename AttrClass>
2437static bool isEqual(const Function &Caller, const Function &Callee) {
2438 return Caller.getFnAttribute(AttrClass::getKind()) ==
2439 Callee.getFnAttribute(AttrClass::getKind());
2440}
2441
2442static bool isEqual(const Function &Caller, const Function &Callee,
2443 const StringRef &AttrName) {
2444 return Caller.getFnAttribute(AttrName) == Callee.getFnAttribute(AttrName);
2445}
2446
2447/// Compute the logical AND of the attributes of the caller and the
2448/// callee.
2449///
2450/// This function sets the caller's attribute to false if the callee's attribute
2451/// is false.
2452template<typename AttrClass>
2453static void setAND(Function &Caller, const Function &Callee) {
2454 if (AttrClass::isSet(Caller, AttrClass::getKind()) &&
2455 !AttrClass::isSet(Callee, AttrClass::getKind()))
2456 AttrClass::set(Caller, AttrClass::getKind(), false);
2457}
2458
2459/// Compute the logical OR of the attributes of the caller and the
2460/// callee.
2461///
2462/// This function sets the caller's attribute to true if the callee's attribute
2463/// is true.
2464template<typename AttrClass>
2465static void setOR(Function &Caller, const Function &Callee) {
2466 if (!AttrClass::isSet(Caller, AttrClass::getKind()) &&
2467 AttrClass::isSet(Callee, AttrClass::getKind()))
2468 AttrClass::set(Caller, AttrClass::getKind(), true);
2469}
2470
2471/// If the inlined function had a higher stack protection level than the
2472/// calling function, then bump up the caller's stack protection level.
2473static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) {
2474 // If the calling function has *no* stack protection level (e.g. it was built
2475 // with Clang's -fno-stack-protector or no_stack_protector attribute), don't
2476 // change it as that could change the program's semantics.
2477 if (!Caller.hasStackProtectorFnAttr())
2478 return;
2479
2480 // If upgrading the SSP attribute, clear out the old SSP Attributes first.
2481 // Having multiple SSP attributes doesn't actually hurt, but it adds useless
2482 // clutter to the IR.
2483 AttributeMask OldSSPAttr;
2484 OldSSPAttr.addAttribute(Attribute::StackProtect)
2485 .addAttribute(Attribute::StackProtectStrong)
2486 .addAttribute(Attribute::StackProtectReq);
2487
2488 if (Callee.hasFnAttribute(Attribute::StackProtectReq)) {
2489 Caller.removeFnAttrs(OldSSPAttr);
2490 Caller.addFnAttr(Attribute::StackProtectReq);
2491 } else if (Callee.hasFnAttribute(Attribute::StackProtectStrong) &&
2492 !Caller.hasFnAttribute(Attribute::StackProtectReq)) {
2493 Caller.removeFnAttrs(OldSSPAttr);
2494 Caller.addFnAttr(Attribute::StackProtectStrong);
2495 } else if (Callee.hasFnAttribute(Attribute::StackProtect) &&
2496 !Caller.hasFnAttribute(Attribute::StackProtectReq) &&
2497 !Caller.hasFnAttribute(Attribute::StackProtectStrong))
2498 Caller.addFnAttr(Attribute::StackProtect);
2499}
2500
2501/// If the inlined function required stack probes, then ensure that
2502/// the calling function has those too.
2503static void adjustCallerStackProbes(Function &Caller, const Function &Callee) {
2504 if (!Caller.hasFnAttribute("probe-stack") &&
2505 Callee.hasFnAttribute("probe-stack")) {
2506 Caller.addFnAttr(Callee.getFnAttribute("probe-stack"));
2507 }
2508}
2509
2510/// If the inlined function defines the size of guard region
2511/// on the stack, then ensure that the calling function defines a guard region
2512/// that is no larger.
2513static void
2515 Attribute CalleeAttr = Callee.getFnAttribute("stack-probe-size");
2516 if (CalleeAttr.isValid()) {
2517 Attribute CallerAttr = Caller.getFnAttribute("stack-probe-size");
2518 if (CallerAttr.isValid()) {
2519 uint64_t CallerStackProbeSize, CalleeStackProbeSize;
2520 CallerAttr.getValueAsString().getAsInteger(0, CallerStackProbeSize);
2521 CalleeAttr.getValueAsString().getAsInteger(0, CalleeStackProbeSize);
2522
2523 if (CallerStackProbeSize > CalleeStackProbeSize) {
2524 Caller.addFnAttr(CalleeAttr);
2525 }
2526 } else {
2527 Caller.addFnAttr(CalleeAttr);
2528 }
2529 }
2530}
2531
2532/// If the inlined function defines a min legal vector width, then ensure
2533/// the calling function has the same or larger min legal vector width. If the
2534/// caller has the attribute, but the callee doesn't, we need to remove the
2535/// attribute from the caller since we can't make any guarantees about the
2536/// caller's requirements.
2537/// This function is called after the inlining decision has been made so we have
2538/// to merge the attribute this way. Heuristics that would use
2539/// min-legal-vector-width to determine inline compatibility would need to be
2540/// handled as part of inline cost analysis.
2541static void
2543 Attribute CallerAttr = Caller.getFnAttribute("min-legal-vector-width");
2544 if (CallerAttr.isValid()) {
2545 Attribute CalleeAttr = Callee.getFnAttribute("min-legal-vector-width");
2546 if (CalleeAttr.isValid()) {
2547 uint64_t CallerVectorWidth, CalleeVectorWidth;
2548 CallerAttr.getValueAsString().getAsInteger(0, CallerVectorWidth);
2549 CalleeAttr.getValueAsString().getAsInteger(0, CalleeVectorWidth);
2550 if (CallerVectorWidth < CalleeVectorWidth)
2551 Caller.addFnAttr(CalleeAttr);
2552 } else {
2553 // If the callee doesn't have the attribute then we don't know anything
2554 // and must drop the attribute from the caller.
2555 Caller.removeFnAttr("min-legal-vector-width");
2556 }
2557 }
2558}
2559
2560/// If the inlined function has null_pointer_is_valid attribute,
2561/// set this attribute in the caller post inlining.
2562static void
2564 if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) {
2565 Caller.addFnAttr(Attribute::NullPointerIsValid);
2566 }
2567}
2568
2569struct EnumAttr {
2570 static bool isSet(const Function &Fn,
2571 Attribute::AttrKind Kind) {
2572 return Fn.hasFnAttribute(Kind);
2573 }
2574
2575 static void set(Function &Fn,
2576 Attribute::AttrKind Kind, bool Val) {
2577 if (Val)
2578 Fn.addFnAttr(Kind);
2579 else
2580 Fn.removeFnAttr(Kind);
2581 }
2582};
2583
2585 static bool isSet(const Function &Fn,
2586 StringRef Kind) {
2587 auto A = Fn.getFnAttribute(Kind);
2588 return A.getValueAsString() == "true";
2589 }
2590
2591 static void set(Function &Fn,
2592 StringRef Kind, bool Val) {
2593 Fn.addFnAttr(Kind, Val ? "true" : "false");
2594 }
2595};
2596
2597#define GET_ATTR_NAMES
2598#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \
2599 struct ENUM_NAME##Attr : EnumAttr { \
2600 static enum Attribute::AttrKind getKind() { \
2601 return llvm::Attribute::ENUM_NAME; \
2602 } \
2603 };
2604#define ATTRIBUTE_STRBOOL(ENUM_NAME, DISPLAY_NAME) \
2605 struct ENUM_NAME##Attr : StrBoolAttr { \
2606 static StringRef getKind() { return #DISPLAY_NAME; } \
2607 };
2608#include "llvm/IR/Attributes.inc"
2609
2610#define GET_ATTR_COMPAT_FUNC
2611#include "llvm/IR/Attributes.inc"
2612
2614 const Function &Callee) {
2615 return hasCompatibleFnAttrs(Caller, Callee);
2616}
2617
2619 const Function &B) {
2620 return hasCompatibleFnAttrs(A, B);
2621}
2622
2624 const Function &Callee) {
2625 mergeFnAttrs(Caller, Callee);
2626}
2627
2629 const Function &ToMerge) {
2630
2631 // We merge functions so that they meet the most general case.
2632 // For example, if the NoNansFPMathAttr is set in one function, but not in
2633 // the other, in the merged function we can say that the NoNansFPMathAttr
2634 // is not set.
2635 // However if we have the SpeculativeLoadHardeningAttr set true in one
2636 // function, but not the other, we make sure that the function retains
2637 // that aspect in the merged function.
2638 mergeFnAttrs(Base, ToMerge);
2639}
2640
2642 uint64_t Width) {
2643 Attribute Attr = Fn.getFnAttribute("min-legal-vector-width");
2644 if (Attr.isValid()) {
2645 uint64_t OldWidth;
2646 Attr.getValueAsString().getAsInteger(0, OldWidth);
2647 if (Width > OldWidth)
2648 Fn.addFnAttr("min-legal-vector-width", llvm::utostr(Width));
2649 }
2650}
This file defines various helper methods and classes used by LLVMContextImpl for creating and managin...
static void addAttributeImpl(SmallVectorImpl< Attribute > &Attrs, K Kind, Attribute Attr)
static void setAND(Function &Caller, const Function &Callee)
Compute the logical AND of the attributes of the caller and the callee.
static void adjustCallerStackProbes(Function &Caller, const Function &Callee)
If the inlined function required stack probes, then ensure that the calling function has those too.
static std::pair< unsigned, std::optional< unsigned > > unpackVScaleRangeArgs(uint64_t Value)
Definition: Attributes.cpp:87
static void adjustMinLegalVectorWidth(Function &Caller, const Function &Callee)
If the inlined function defines a min legal vector width, then ensure the calling function has the sa...
AttributeProperty
Definition: Attributes.cpp:736
@ RetAttr
Definition: Attributes.cpp:739
@ IntersectPreserve
Definition: Attributes.cpp:740
@ IntersectMin
Definition: Attributes.cpp:742
@ IntersectCustom
Definition: Attributes.cpp:743
@ ParamAttr
Definition: Attributes.cpp:738
@ FnAttr
Definition: Attributes.cpp:737
@ IntersectPropertyMask
Definition: Attributes.cpp:744
@ IntersectAnd
Definition: Attributes.cpp:741
static void adjustCallerStackProbeSize(Function &Caller, const Function &Callee)
If the inlined function defines the size of guard region on the stack, then ensure that the calling f...
static void adjustCallerSSPLevel(Function &Caller, const Function &Callee)
If the inlined function had a higher stack protection level than the calling function,...
static bool checkStrictFP(const Function &Caller, const Function &Callee)
static uint64_t packAllocSizeArgs(unsigned ElemSizeArg, const std::optional< unsigned > &NumElemsArg)
Definition: Attributes.cpp:61
static uint64_t packVScaleRangeArgs(unsigned MinValue, std::optional< unsigned > MaxValue)
Definition: Attributes.cpp:81
static bool hasIntersectProperty(Attribute::AttrKind Kind, AttributeProperty Prop)
Definition: Attributes.cpp:773
static unsigned attrIdxToArrayIdx(unsigned Index)
Map from AttributeList index to the internal array index.
static bool denormModeCompatible(DenormalMode CallerMode, DenormalMode CalleeMode)
Callees with dynamic denormal modes are compatible with any caller mode.
static void adjustNullPointerValidAttr(Function &Caller, const Function &Callee)
If the inlined function has null_pointer_is_valid attribute, set this attribute in the caller post in...
static const unsigned AllocSizeNumElemsNotPresent
Definition: Attributes.cpp:59
static std::pair< unsigned, std::optional< unsigned > > unpackAllocSizeArgs(uint64_t Num)
Definition: Attributes.cpp:71
static bool checkDenormMode(const Function &Caller, const Function &Callee)
static unsigned getAttributeProperties(Attribute::AttrKind Kind)
Definition: Attributes.cpp:750
static void setOR(Function &Caller, const Function &Callee)
Compute the logical OR of the attributes of the caller and the callee.
static bool hasAttributeProperty(Attribute::AttrKind Kind, AttributeProperty Prop)
Definition: Attributes.cpp:756
static const char * getModRefStr(ModRefInfo MR)
Definition: Attributes.cpp:508
This file contains the simple types necessary to represent the attributes associated with functions a...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Definition: Compiler.h:622
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
std::string Name
This file defines a hash set that can be used to remove duplication of nodes in a graph.
#define I(x, y, z)
Definition: MD5.cpp:58
Load MIR Sample Profile
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains some templates that are useful if you are working with the STL at all.
raw_pwrite_stream & OS
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
void Profile(FoldingSetNodeID &id) const
Used to insert APInt objects, or objects that contain APInt objects, into FoldingSets.
Definition: APInt.cpp:156
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
const T & back() const
back - Get the last element.
Definition: ArrayRef.h:177
ArrayRef< T > take_front(size_t N=1) const
Return a copy of *this with only the first N elements.
Definition: ArrayRef.h:231
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:168
iterator begin() const
Definition: ArrayRef.h:156
bool empty() const
empty - Check if the array is empty.
Definition: ArrayRef.h:163
AttrBuilder & addStructRetAttr(Type *Ty)
This turns a sret type into the form used internally in Attribute.
AttrBuilder & addAlignmentAttr(MaybeAlign Align)
This turns an alignment into the form used internally in Attribute.
AttrBuilder & addVScaleRangeAttrFromRawRepr(uint64_t RawVScaleRangeRepr)
Add a vscale_range attribute, using the representation returned by Attribute.getIntValue().
std::optional< uint64_t > getRawIntAttr(Attribute::AttrKind Kind) const
Return raw (possibly packed/encoded) value of integer attribute or std::nullopt if not set.
AttrBuilder & addAllocKindAttr(AllocFnKind Kind)
Attribute getAttribute(Attribute::AttrKind Kind) const
Return Attribute with the given Kind.
AttrBuilder & addByRefAttr(Type *Ty)
This turns a byref type into the form used internally in Attribute.
AttrBuilder & addNoFPClassAttr(FPClassTest NoFPClassMask)
bool overlaps(const AttributeMask &AM) const
Return true if the builder has any attribute that's in the specified builder.
AttrBuilder & merge(const AttrBuilder &B)
Add the attributes from the builder.
AttrBuilder & addVScaleRangeAttr(unsigned MinValue, std::optional< unsigned > MaxValue)
This turns two ints into the form used internally in Attribute.
AttrBuilder(LLVMContext &Ctx)
Definition: Attributes.h:1065
AttrBuilder & addRawIntAttr(Attribute::AttrKind Kind, uint64_t Value)
Add integer attribute with raw value (packed/encoded if necessary).
AttrBuilder & addAttribute(Attribute::AttrKind Val)
Add an attribute to the builder.
AttrBuilder & addByValAttr(Type *Ty)
This turns a byval type into the form used internally in Attribute.
AttrBuilder & addDereferenceableAttr(uint64_t Bytes)
This turns the number of dereferenceable bytes into the form used internally in Attribute.
AttrBuilder & addInitializesAttr(const ConstantRangeList &CRL)
Add initializes attribute.
bool contains(Attribute::AttrKind A) const
Return true if the builder has the specified attribute.
AttrBuilder & addMemoryAttr(MemoryEffects ME)
Add memory effect attribute.
AttrBuilder & addConstantRangeListAttr(Attribute::AttrKind Kind, ArrayRef< ConstantRange > Val)
Add a ConstantRangeList attribute with the given ranges.
AttrBuilder & addConstantRangeAttr(Attribute::AttrKind Kind, const ConstantRange &CR)
Add a ConstantRange attribute with the given range.
AttrBuilder & addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr)
Add an allocsize attribute, using the representation returned by Attribute.getIntValue().
AttrBuilder & addPreallocatedAttr(Type *Ty)
This turns a preallocated type into the form used internally in Attribute.
AttrBuilder & addStackAlignmentAttr(MaybeAlign Align)
This turns a stack alignment into the form used internally in Attribute.
AttrBuilder & addInAllocaAttr(Type *Ty)
This turns an inalloca type into the form used internally in Attribute.
AttrBuilder & removeAttribute(Attribute::AttrKind Val)
Remove an attribute from the builder.
bool operator==(const AttrBuilder &B) const
Type * getTypeAttr(Attribute::AttrKind Kind) const
Retrieve type for the given type attribute.
AttrBuilder & remove(const AttributeMask &AM)
Remove the attributes from the builder.
std::optional< ConstantRange > getRange() const
Retrieve the range if the attribute exists (std::nullopt is returned otherwise).
AttrBuilder & addDereferenceableOrNullAttr(uint64_t Bytes)
This turns the number of dereferenceable_or_null bytes into the form used internally in Attribute.
AttrBuilder & addTypeAttr(Attribute::AttrKind Kind, Type *Ty)
Add a type attribute with the given type.
std::optional< std::pair< unsigned, std::optional< unsigned > > > getAllocSizeArgs() const
Retrieve the allocsize args, or std::nullopt if the attribute does not exist.
AttrBuilder & addAllocSizeAttr(unsigned ElemSizeArg, const std::optional< unsigned > &NumElemsArg)
This turns one (or two) ints into the form used internally in Attribute.
AttrBuilder & addRangeAttr(const ConstantRange &CR)
Add range attribute.
AttrBuilder & addUWTableAttr(UWTableKind Kind)
This turns the unwind table kind into the form used internally in Attribute.
void addAttribute(Attribute::AttrKind Kind)
bool hasAttribute(Attribute::AttrKind Kind) const
int cmp(const AttributeImpl &AI, bool KindOnly) const
Used to sort attributes.
Definition: Attributes.cpp:854
bool isConstantRangeAttribute() const
Definition: AttributeImpl.h:66
bool hasAttribute(Attribute::AttrKind A) const
Definition: Attributes.cpp:801
void Profile(FoldingSetNodeID &ID) const
Definition: AttributeImpl.h:95
Type * getValueAsType() const
Definition: Attributes.cpp:837
Attribute::AttrKind getKindAsEnum() const
Definition: Attributes.cpp:811
bool operator<(const AttributeImpl &AI) const
Used when sorting the attributes.
Definition: Attributes.cpp:889
uint64_t getValueAsInt() const
Definition: Attributes.cpp:817
bool isIntAttribute() const
Definition: AttributeImpl.h:63
bool isTypeAttribute() const
Definition: AttributeImpl.h:65
bool getValueAsBool() const
Definition: Attributes.cpp:822
StringRef getKindAsString() const
Definition: Attributes.cpp:827
StringRef getValueAsString() const
Definition: Attributes.cpp:832
bool isEnumAttribute() const
Definition: AttributeImpl.h:62
ArrayRef< ConstantRange > getValueAsConstantRangeList() const
Definition: Attributes.cpp:848
bool isConstantRangeListAttribute() const
Definition: AttributeImpl.h:69
bool isStringAttribute() const
Definition: AttributeImpl.h:64
const ConstantRange & getValueAsConstantRange() const
Definition: Attributes.cpp:842
bool hasAttrSomewhere(Attribute::AttrKind Kind, unsigned *Index=nullptr) const
Return true if the specified attribute is set for at least one parameter or for the return value.
iterator begin() const
void Profile(FoldingSetNodeID &ID) const
AttributeListImpl(ArrayRef< AttributeSet > Sets)
iterator end() const
friend class AttributeList
bool hasAttributeAtIndex(unsigned Index, Attribute::AttrKind Kind) const
Return true if the attribute exists at the given index.
Type * getParamStructRetType(unsigned ArgNo) const
Return the sret type for the specified function parameter.
AttributeList addDereferenceableParamAttr(LLVMContext &C, unsigned ArgNo, uint64_t Bytes) const
Add the dereferenceable attribute to the attribute set at the given arg index.
AttributeList removeAttributeAtIndex(LLVMContext &C, unsigned Index, Attribute::AttrKind Kind) const
Remove the specified attribute at the specified index from this attribute list.
AttributeList addRangeRetAttr(LLVMContext &C, const ConstantRange &CR) const
Add the range attribute to the attribute set at the return value index.
bool hasAttributesAtIndex(unsigned Index) const
Return true if attribute exists at the given index.
friend class AttributeListImpl
Definition: Attributes.h:496
AttributeSet getFnAttrs() const
The function attributes are returned.
index_iterator indexes() const
Use this to iterate over the valid attribute indexes.
Definition: Attributes.h:1009
AttributeList removeAttributesAtIndex(LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const
Remove the specified attributes at the specified index from this attribute list.
friend class AttributeSet
Definition: Attributes.h:497
AttributeList()=default
iterator begin() const
MaybeAlign getRetStackAlignment() const
Get the stack alignment of the return value.
AttributeList addRetAttributes(LLVMContext &C, const AttrBuilder &B) const
Add a return value attribute to the list.
Definition: Attributes.h:616
void print(raw_ostream &O) const
AttributeList addDereferenceableRetAttr(LLVMContext &C, uint64_t Bytes) const
Add the dereferenceable attribute to the attribute set at the given index.
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute > > Attrs)
Create an AttributeList with the specified parameters in it.
AllocFnKind getAllocKind() const
bool isEmpty() const
Return true if there are no attributes.
Definition: Attributes.h:1021
AttributeSet getRetAttrs() const
The attributes for the ret value are returned.
friend class AttrBuilder
Definition: Attributes.h:495
bool hasFnAttr(Attribute::AttrKind Kind) const
Return true if the attribute exists for the function.
uint64_t getParamDereferenceableBytes(unsigned Index) const
Get the number of dereferenceable bytes (or zero if unknown) of an arg.
MaybeAlign getParamAlignment(unsigned ArgNo) const
Return the alignment for the specified function parameter.
bool hasAttrSomewhere(Attribute::AttrKind Kind, unsigned *Index=nullptr) const
Return true if the specified attribute is set for at least one parameter or for the return value.
iterator end() const
Type * getParamInAllocaType(unsigned ArgNo) const
Return the inalloca type for the specified function parameter.
unsigned getNumAttrSets() const
FPClassTest getRetNoFPClass() const
Get the disallowed floating-point classes of the return value.
std::string getAsString(unsigned Index, bool InAttrGrp=false) const
Return the attributes at the index as a string.
UWTableKind getUWTableKind() const
Get the unwind table kind requested for the function.
MaybeAlign getRetAlignment() const
Return the alignment of the return value.
Type * getParamElementType(unsigned ArgNo) const
Return the elementtype type for the specified function parameter.
Attribute getAttributeAtIndex(unsigned Index, Attribute::AttrKind Kind) const
Return the attribute object that exists at the given index.
Type * getParamPreallocatedType(unsigned ArgNo) const
Return the preallocated type for the specified function parameter.
bool hasParentContext(LLVMContext &C) const
Return true if this attribute list belongs to the LLVMContext.
const AttributeSet * iterator
Definition: Attributes.h:977
MaybeAlign getFnStackAlignment() const
Get the stack alignment of the function.
AttributeList addAttributesAtIndex(LLVMContext &C, unsigned Index, const AttrBuilder &B) const
Add attributes to the attribute set at the given index.
Type * getParamByValType(unsigned ArgNo) const
Return the byval type for the specified function parameter.
MaybeAlign getParamStackAlignment(unsigned ArgNo) const
Return the stack alignment for the specified function parameter.
uint64_t getRetDereferenceableBytes() const
Get the number of dereferenceable bytes (or zero if unknown) of the return value.
AttributeList addAllocSizeParamAttr(LLVMContext &C, unsigned ArgNo, unsigned ElemSizeArg, const std::optional< unsigned > &NumElemsArg) const
Add the allocsize attribute to the attribute set at the given arg index.
uint64_t getParamDereferenceableOrNullBytes(unsigned ArgNo) const
Get the number of dereferenceable_or_null bytes (or zero if unknown) of an arg.
AttributeList addDereferenceableOrNullParamAttr(LLVMContext &C, unsigned ArgNo, uint64_t Bytes) const
Add the dereferenceable_or_null attribute to the attribute set at the given arg index.
AttributeSet getAttributes(unsigned Index) const
The attributes for the specified index are returned.
FPClassTest getParamNoFPClass(unsigned ArgNo) const
Get the disallowed floating-point classes of the argument value.
std::optional< AttributeList > intersectWith(LLVMContext &C, AttributeList Other) const
Try to intersect this AttributeList with Other.
Type * getParamByRefType(unsigned ArgNo) const
Return the byref type for the specified function parameter.
AttributeList addAttributeAtIndex(LLVMContext &C, unsigned Index, Attribute::AttrKind Kind) const
Add an attribute to the attribute set at the given index.
AttributeSet getParamAttrs(unsigned ArgNo) const
The attributes for the argument or parameter at the given index are returned.
AttributeList addParamAttributes(LLVMContext &C, unsigned ArgNo, const AttrBuilder &B) const
Add an argument attribute to the list.
Definition: Attributes.h:645
std::optional< ConstantRange > getParamRange(unsigned ArgNo) const
Get range (or std::nullopt if unknown) of an arg.
uint64_t getRetDereferenceableOrNullBytes() const
Get the number of dereferenceable_or_null bytes (or zero if unknown) of the return value.
AttributeList addParamAttribute(LLVMContext &C, unsigned ArgNo, Attribute::AttrKind Kind) const
Add an argument attribute to the list.
Definition: Attributes.h:624
MemoryEffects getMemoryEffects() const
Returns memory effects of the function.
AttributeMask & addAttribute(Attribute::AttrKind Val)
Add an attribute to the mask.
Definition: AttributeMask.h:44
bool contains(Attribute::AttrKind A) const
Return true if the builder has the specified attribute.
Definition: AttributeMask.h:67
MaybeAlign getStackAlignment() const
uint64_t getDereferenceableOrNullBytes() const
std::optional< unsigned > getVScaleRangeMax() const
bool hasAttribute(Attribute::AttrKind Kind) const
Type * getAttributeType(Attribute::AttrKind Kind) const
AllocFnKind getAllocKind() const
unsigned getVScaleRangeMin() const
MaybeAlign getAlignment() const
MemoryEffects getMemoryEffects() const
iterator begin() const
UWTableKind getUWTableKind() const
std::optional< std::pair< unsigned, std::optional< unsigned > > > getAllocSizeArgs() const
iterator end() const
uint64_t getDereferenceableBytes() const
unsigned getNumAttributes() const
Return the number of attributes this AttributeList contains.
void Profile(FoldingSetNodeID &ID) const
std::string getAsString(bool InAttrGrp) const
static AttributeSetNode * get(LLVMContext &C, const AttrBuilder &B)
FPClassTest getNoFPClass() const
Attribute getAttribute(Attribute::AttrKind Kind) const
AllocFnKind getAllocKind() const
bool hasAttributes() const
Return true if attributes exists in this set.
Definition: Attributes.h:408
AttributeSet removeAttribute(LLVMContext &C, Attribute::AttrKind Kind) const
Remove the specified attribute from this set.
Definition: Attributes.cpp:933
Type * getInAllocaType() const
Type * getByValType() const
AttributeSet addAttributes(LLVMContext &C, AttributeSet AS) const
Add attributes to the attribute set.
Definition: Attributes.cpp:920
MemoryEffects getMemoryEffects() const
bool hasAttribute(Attribute::AttrKind Kind) const
Return true if the attribute exists in this set.
std::optional< AttributeSet > intersectWith(LLVMContext &C, AttributeSet Other) const
Try to intersect this AttributeSet with Other.
Definition: Attributes.cpp:961
Type * getStructRetType() const
std::string getAsString(bool InAttrGrp=false) const
unsigned getVScaleRangeMin() const
std::optional< std::pair< unsigned, std::optional< unsigned > > > getAllocSizeArgs() const
UWTableKind getUWTableKind() const
bool hasParentContext(LLVMContext &C) const
Return true if this attribute set belongs to the LLVMContext.
iterator begin() const
iterator end() const
AttributeSet removeAttributes(LLVMContext &C, const AttributeMask &AttrsToRemove) const
Remove the specified attributes from this set.
Definition: Attributes.cpp:949
std::optional< unsigned > getVScaleRangeMax() const
MaybeAlign getStackAlignment() const
Attribute getAttribute(Attribute::AttrKind Kind) const
Return the attribute object.
Type * getPreallocatedType() const
uint64_t getDereferenceableBytes() const
MaybeAlign getAlignment() const
FPClassTest getNoFPClass() const
Type * getElementType() const
Type * getByRefType() const
AttributeSet()=default
AttributeSet is a trivially copyable value type.
static AttributeSet get(LLVMContext &C, const AttrBuilder &B)
Definition: Attributes.cpp:897
uint64_t getDereferenceableOrNullBytes() const
unsigned getNumAttributes() const
Return the number of attributes in this set.
AttributeSet addAttribute(LLVMContext &C, Attribute::AttrKind Kind) const
Add an argument attribute.
Definition: Attributes.cpp:905
void dump() const
bool isStringAttribute() const
Return true if the attribute is a string (target-dependent) attribute.
Definition: Attributes.cpp:348
static Attribute getWithStructRetType(LLVMContext &Context, Type *Ty)
Definition: Attributes.cpp:260
static Attribute::AttrKind getAttrKindFromName(StringRef AttrName)
Definition: Attributes.cpp:305
bool isEnumAttribute() const
Return true if the attribute is an Attribute::AttrKind type.
Definition: Attributes.cpp:340
static Attribute getWithStackAlignment(LLVMContext &Context, Align Alignment)
Definition: Attributes.cpp:239
const ConstantRange & getRange() const
Returns the value of the range attribute.
Definition: Attributes.cpp:496
static bool intersectWithCustom(AttrKind Kind)
Definition: Attributes.cpp:793
bool isIntAttribute() const
Return true if the attribute is an integer attribute.
Definition: Attributes.cpp:344
static Attribute getWithByRefType(LLVMContext &Context, Type *Ty)
Definition: Attributes.cpp:264
std::optional< unsigned > getVScaleRangeMax() const
Returns the maximum value for the vscale_range attribute or std::nullopt when unknown.
Definition: Attributes.cpp:466
uint64_t getValueAsInt() const
Return the attribute's value as an integer.
Definition: Attributes.cpp:371
unsigned getVScaleRangeMin() const
Returns the minimum value for the vscale_range attribute.
Definition: Attributes.cpp:460
AllocFnKind getAllocKind() const
Definition: Attributes.cpp:478
bool isConstantRangeAttribute() const
Return true if the attribute is a ConstantRange attribute.
Definition: Attributes.cpp:356
StringRef getKindAsString() const
Return the attribute's kind as a string.
Definition: Attributes.cpp:385
static Attribute getWithPreallocatedType(LLVMContext &Context, Type *Ty)
Definition: Attributes.cpp:268
static bool intersectWithMin(AttrKind Kind)
Definition: Attributes.cpp:790
static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
Definition: Attributes.cpp:95
static bool canUseAsRetAttr(AttrKind Kind)
Definition: Attributes.cpp:769
static bool isTypeAttrKind(AttrKind Kind)
Definition: Attributes.h:105
std::string getAsString(bool InAttrGrp=false) const
The Attribute is converted to a string of equivalent mnemonic.
Definition: Attributes.cpp:522
uint64_t getDereferenceableOrNullBytes() const
Returns the number of dereferenceable_or_null bytes from the dereferenceable_or_null attribute.
Definition: Attributes.cpp:446
static Attribute getWithDereferenceableBytes(LLVMContext &Context, uint64_t Bytes)
Definition: Attributes.cpp:244
std::pair< unsigned, std::optional< unsigned > > getAllocSizeArgs() const
Returns the argument numbers for the allocsize attribute.
Definition: Attributes.cpp:454
static Attribute getWithUWTableKind(LLVMContext &Context, UWTableKind Kind)
Definition: Attributes.cpp:276
FPClassTest getNoFPClass() const
Return the FPClassTest for nofpclass.
Definition: Attributes.cpp:490
static Attribute getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg, const std::optional< unsigned > &NumElemsArg)
Definition: Attributes.cpp:292
Attribute::AttrKind getKindAsEnum() const
Return the attribute's kind as an enum (Attribute::AttrKind).
Definition: Attributes.cpp:364
Attribute()=default
bool getValueAsBool() const
Return the attribute's value as a boolean.
Definition: Attributes.cpp:378
ArrayRef< ConstantRange > getInitializes() const
Returns the value of the initializes attribute.
Definition: Attributes.cpp:502
const ConstantRange & getValueAsConstantRange() const
Return the attribute's value as a ConstantRange.
Definition: Attributes.cpp:406
uint64_t getDereferenceableBytes() const
Returns the number of dereferenceable bytes from the dereferenceable attribute.
Definition: Attributes.cpp:439
static Attribute getWithVScaleRangeArgs(LLVMContext &Context, unsigned MinValue, unsigned MaxValue)
Definition: Attributes.cpp:299
MemoryEffects getMemoryEffects() const
Returns memory effects.
Definition: Attributes.cpp:484
void Profile(FoldingSetNodeID &ID) const
Definition: Attributes.cpp:732
UWTableKind getUWTableKind() const
Definition: Attributes.cpp:472
static Attribute getWithDereferenceableOrNullBytes(LLVMContext &Context, uint64_t Bytes)
Definition: Attributes.cpp:250
ArrayRef< ConstantRange > getValueAsConstantRangeList() const
Return the attribute's value as a ConstantRange array.
Definition: Attributes.cpp:412
StringRef getValueAsString() const
Return the attribute's value as a string.
Definition: Attributes.cpp:392
static bool isExistingAttribute(StringRef Name)
Return true if the provided string matches the IR name of an attribute.
Definition: Attributes.cpp:328
bool hasKindAsEnum() const
Returns true if the attribute's kind can be represented as an enum (Enum, Integer,...
Definition: Attributes.h:218
static StringRef getNameFromAttrKind(Attribute::AttrKind AttrKind)
Definition: Attributes.cpp:314
static bool canUseAsFnAttr(AttrKind Kind)
Definition: Attributes.cpp:761
static bool intersectWithAnd(AttrKind Kind)
Definition: Attributes.cpp:787
static Attribute getWithNoFPClass(LLVMContext &Context, FPClassTest Mask)
Definition: Attributes.cpp:286
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
Definition: Attributes.h:86
@ None
No attributes have been set.
Definition: Attributes.h:88
@ EndAttrKinds
Sentinel value useful for loops.
Definition: Attributes.h:91
static bool isConstantRangeAttrKind(AttrKind Kind)
Definition: Attributes.h:108
bool hasParentContext(LLVMContext &C) const
Return true if this attribute belongs to the LLVMContext.
Definition: Attributes.cpp:707
bool isTypeAttribute() const
Return true if the attribute is a type attribute.
Definition: Attributes.cpp:352
static Attribute getWithInAllocaType(LLVMContext &Context, Type *Ty)
Definition: Attributes.cpp:272
static bool isIntAttrKind(AttrKind Kind)
Definition: Attributes.h:102
static bool isConstantRangeListAttrKind(AttrKind Kind)
Definition: Attributes.h:111
bool isConstantRangeListAttribute() const
Return true if the attribute is a ConstantRangeList attribute.
Definition: Attributes.cpp:360
static Attribute getWithByValType(LLVMContext &Context, Type *Ty)
Definition: Attributes.cpp:256
bool hasAttribute(AttrKind Val) const
Return true if the attribute is present.
Definition: Attributes.cpp:418
static bool isEnumAttrKind(AttrKind Kind)
Definition: Attributes.h:99
static Attribute getWithMemoryEffects(LLVMContext &Context, MemoryEffects ME)
Definition: Attributes.cpp:281
static bool canUseAsParamAttr(AttrKind Kind)
Definition: Attributes.cpp:765
bool isValid() const
Return true if the attribute is any kind of attribute.
Definition: Attributes.h:208
MaybeAlign getStackAlignment() const
Returns the stack alignment field of an attribute as a byte alignment value.
Definition: Attributes.cpp:433
MaybeAlign getAlignment() const
Returns the alignment field of an attribute as a byte alignment value.
Definition: Attributes.cpp:427
static bool intersectMustPreserve(AttrKind Kind)
Definition: Attributes.cpp:784
int cmpKind(Attribute A) const
Used to sort attribute by kind.
Definition: Attributes.cpp:715
bool operator<(Attribute A) const
Less-than operator. Useful for sorting the attributes list.
Definition: Attributes.cpp:725
static Attribute getWithAlignment(LLVMContext &Context, Align Alignment)
Return a uniquified Attribute object that has the specific alignment set.
Definition: Attributes.cpp:234
Type * getValueAsType() const
Return the attribute's value as a Type.
Definition: Attributes.cpp:399
LLVM_ATTRIBUTE_RETURNS_NONNULL void * Allocate(size_t Size, Align Alignment)
Allocate space at the specified alignment.
Definition: Allocator.h:148
static size_t totalSizeToAlloc(ArrayRef< ConstantRange > Val)
This class represents a list of constant ranges.
ArrayRef< ConstantRange > rangesRef() const
void print(raw_ostream &OS) const
Print out the ranges to a stream.
This class represents a range of values.
Definition: ConstantRange.h:47
const APInt & getLower() const
Return the lower value for this range.
bool isFullSet() const
Return true if this set contains all of the elements possible for this data-type.
const APInt & getUpper() const
Return the upper value for this range.
ConstantRange unionWith(const ConstantRange &CR, PreferredRangeType Type=Smallest) const
Return the range that results from the union of this range with another range.
uint32_t getBitWidth() const
Get the bit width of this ConstantRange.
static bool isSupportedFloatingPointType(Type *Ty)
Returns true if Ty is a supported floating-point type for phi, select, or call FPMathOperators.
Definition: Operator.h:349
FoldingSetNodeID - This class is used to gather all the unique data bits of a node.
Definition: FoldingSet.h:327
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
Definition: Function.cpp:641
Attribute getFnAttribute(Attribute::AttrKind Kind) const
Return the attribute for the given attribute kind.
Definition: Function.cpp:766
void removeFnAttr(Attribute::AttrKind Kind)
Remove function attributes from this function.
Definition: Function.cpp:689
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition: Function.cpp:731
FoldingSet< AttributeImpl > AttrsSet
BumpPtrAllocator Alloc
FoldingSet< AttributeSetNode > AttrsSetNodes
FoldingSet< AttributeListImpl > AttrsLists
SpecificBumpPtrAllocator< ConstantRangeAttributeImpl > ConstantRangeAttributeAlloc
std::vector< ConstantRangeListAttributeImpl * > ConstantRangeListAttributes
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
LLVMContextImpl *const pImpl
Definition: LLVMContext.h:69
ModRefInfo getModRef(Location Loc) const
Get ModRefInfo for the given Location.
Definition: ModRef.h:165
static MemoryEffectsBase createFromIntValue(uint32_t Data)
Create MemoryEffectsBase from an encoded integer value (used by memory attribute).
Definition: ModRef.h:154
static auto locations()
Returns iterator over all supported location kinds.
Definition: ModRef.h:95
uint32_t toIntValue() const
Convert MemoryEffectsBase into an encoded integer value (used by memory attribute).
Definition: ModRef.h:160
static MemoryEffectsBase unknown()
Create MemoryEffectsBase that can read and write any memory.
Definition: ModRef.h:112
size_t size() const
Definition: SmallVector.h:78
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:573
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:937
void reserve(size_type N)
Definition: SmallVector.h:663
void resize(size_type N)
Definition: SmallVector.h:638
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
static size_t totalSizeToAlloc(StringRef Kind, StringRef Val)
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
Definition: StringRef.h:470
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:229
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:147
int compare(StringRef RHS) const
compare - Compare two strings; the result is negative, zero, or positive if this string is lexicograp...
Definition: StringRef.h:183
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
R Default(T Value)
Definition: StringSwitch.h:182
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
bool isIntOrIntVectorTy() const
Return true if this is an integer type or a vector of integer types.
Definition: Type.h:243
bool isPointerTy() const
True if this is an instance of PointerType.
Definition: Type.h:264
void print(raw_ostream &O, bool IsForDebug=false, bool NoDetails=false) const
Print the current type.
unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isPtrOrPtrVectorTy() const
Return true if this is a pointer type or a vector of pointer types.
Definition: Type.h:267
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition: Type.h:237
bool isVoidTy() const
Return true if this is 'void'.
Definition: Type.h:139
LLVM Value Representation.
Definition: Value.h:74
static constexpr uint64_t MaximumAlignment
Definition: Value.h:811
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:661
This class provides various memory handling functions that manipulate MemoryBlock instances.
Definition: Memory.h:53
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool areInlineCompatible(const Function &Caller, const Function &Callee)
AttributeMask getUBImplyingAttributes()
Get param/return attributes which imply immediate undefined behavior if an invalid value is passed.
bool isNoFPClassCompatibleType(Type *Ty)
Returns true if this is a type legal for the 'nofpclass' attribute.
bool areOutlineCompatible(const Function &A, const Function &B)
Checks if there are any incompatible function attributes between A and B.
void updateMinLegalVectorWidthAttr(Function &Fn, uint64_t Width)
Update min-legal-vector-width if it is in Attribute and less than Width.
void mergeAttributesForOutlining(Function &Base, const Function &ToMerge)
Merges the functions attributes from ToMerge into function Base.
AttributeMask typeIncompatible(Type *Ty, AttributeSet AS, AttributeSafetyKind ASK=ASK_ALL)
Which attributes cannot be applied to a type.
void mergeAttributesForInlining(Function &Caller, const Function &Callee)
Merge caller's and callee's attributes.
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1739
bool isEqual(const GCNRPTracker::LiveRegSet &S1, const GCNRPTracker::LiveRegSet &S2)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition: STLExtras.h:1697
AllocFnKind
Definition: Attributes.h:49
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition: STLExtras.h:2115
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1746
UWTableKind
Definition: CodeGen.h:120
@ None
No unwind table requested.
void sort(IteratorTy Start, IteratorTy End)
Definition: STLExtras.h:1664
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1753
bool is_sorted(R &&Range, Compare C)
Wrapper function around std::is_sorted to check if elements in a range R are sorted with respect to a...
Definition: STLExtras.h:1926
ModRefInfo
Flags indicating whether a memory access modifies or references memory.
Definition: ModRef.h:27
@ Ref
The access may reference the value stored in memory.
@ ModRef
The access may reference and may modify the value stored in memory.
@ Mod
The access may modify the value stored in memory.
@ NoModRef
The access neither references nor modifies the value stored in memory.
@ ArgMem
Access to memory via argument pointers.
@ Other
Any other memory.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
@ InaccessibleMem
Memory that is inaccessible via LLVM IR.
auto lower_bound(R &&Range, T &&Value)
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:1978
OutputIt copy(R &&Range, OutputIt Out)
Definition: STLExtras.h:1841
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
Definition: STLExtras.h:2099
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition: BitVector.h:860
Attribute comparator that only compares attribute keys.
bool operator()(Attribute A0, StringRef Kind) const
bool operator()(Attribute A0, Attribute A1) const
bool operator()(Attribute A0, Attribute::AttrKind Kind) const
static void set(Function &Fn, Attribute::AttrKind Kind, bool Val)
static bool isSet(const Function &Fn, Attribute::AttrKind Kind)
static bool isSet(const Function &Fn, StringRef Kind)
static void set(Function &Fn, StringRef Kind, bool Val)
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
uint64_t value() const
This is a hole in the type system and should not be abused.
Definition: Alignment.h:85
Represent subnormal handling kind for floating point instruction inputs and outputs.
DenormalModeKind Input
Denormal treatment kind for floating point instruction inputs in the default floating-point environme...
@ Dynamic
Denormals have unknown treatment.
static constexpr DenormalMode getInvalid()
DenormalModeKind Output
Denormal flushing mode for floating point instruction results in the default floating point environme...
static constexpr DenormalMode getDynamic()
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Definition: Alignment.h:117
Align valueOrOne() const
For convenience, returns a valid alignment or 1 if undefined.
Definition: Alignment.h:141
Function object to check whether the first component of a container supported by std::get (like std::...
Definition: STLExtras.h:1467