xref: /freebsd-src/contrib/llvm-project/llvm/lib/IR/Attributes.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- Attributes.cpp - Implement AttributesList --------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // \file
100b57cec5SDimitry Andric // This file implements the Attribute, AttributeImpl, AttrBuilder,
110b57cec5SDimitry Andric // AttributeListImpl, and AttributeList classes.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "llvm/IR/Attributes.h"
160b57cec5SDimitry Andric #include "AttributeImpl.h"
170b57cec5SDimitry Andric #include "LLVMContextImpl.h"
180b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
190b57cec5SDimitry Andric #include "llvm/ADT/FoldingSet.h"
200b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
210b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
220b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
230b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
245ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h"
250b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
2606c3fb27SDimitry Andric #include "llvm/IR/AttributeMask.h"
27*0fca6ea1SDimitry Andric #include "llvm/IR/ConstantRange.h"
28*0fca6ea1SDimitry Andric #include "llvm/IR/ConstantRangeList.h"
290b57cec5SDimitry Andric #include "llvm/IR/Function.h"
300b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
310b57cec5SDimitry Andric #include "llvm/IR/Type.h"
320b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
330b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
34bdd1243dSDimitry Andric #include "llvm/Support/ModRef.h"
350b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
360b57cec5SDimitry Andric #include <algorithm>
370b57cec5SDimitry Andric #include <cassert>
380b57cec5SDimitry Andric #include <cstddef>
390b57cec5SDimitry Andric #include <cstdint>
400b57cec5SDimitry Andric #include <limits>
41bdd1243dSDimitry Andric #include <optional>
420b57cec5SDimitry Andric #include <string>
430b57cec5SDimitry Andric #include <tuple>
440b57cec5SDimitry Andric #include <utility>
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric using namespace llvm;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
490b57cec5SDimitry Andric // Attribute Construction Methods
500b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric // allocsize has two integer arguments, but because they're both 32 bits, we can
530b57cec5SDimitry Andric // pack them into one 64-bit value, at the cost of making said value
540b57cec5SDimitry Andric // nonsensical.
550b57cec5SDimitry Andric //
560b57cec5SDimitry Andric // In order to do this, we need to reserve one value of the second (optional)
570b57cec5SDimitry Andric // allocsize argument to signify "not present."
580b57cec5SDimitry Andric static const unsigned AllocSizeNumElemsNotPresent = -1;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric static uint64_t packAllocSizeArgs(unsigned ElemSizeArg,
61bdd1243dSDimitry Andric                                   const std::optional<unsigned> &NumElemsArg) {
6281ad6265SDimitry Andric   assert((!NumElemsArg || *NumElemsArg != AllocSizeNumElemsNotPresent) &&
630b57cec5SDimitry Andric          "Attempting to pack a reserved value");
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   return uint64_t(ElemSizeArg) << 32 |
6681ad6265SDimitry Andric          NumElemsArg.value_or(AllocSizeNumElemsNotPresent);
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric 
69bdd1243dSDimitry Andric static std::pair<unsigned, std::optional<unsigned>>
700b57cec5SDimitry Andric unpackAllocSizeArgs(uint64_t Num) {
710b57cec5SDimitry Andric   unsigned NumElems = Num & std::numeric_limits<unsigned>::max();
720b57cec5SDimitry Andric   unsigned ElemSizeArg = Num >> 32;
730b57cec5SDimitry Andric 
74bdd1243dSDimitry Andric   std::optional<unsigned> NumElemsArg;
750b57cec5SDimitry Andric   if (NumElems != AllocSizeNumElemsNotPresent)
760b57cec5SDimitry Andric     NumElemsArg = NumElems;
770b57cec5SDimitry Andric   return std::make_pair(ElemSizeArg, NumElemsArg);
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric 
800eae32dcSDimitry Andric static uint64_t packVScaleRangeArgs(unsigned MinValue,
81bdd1243dSDimitry Andric                                     std::optional<unsigned> MaxValue) {
8281ad6265SDimitry Andric   return uint64_t(MinValue) << 32 | MaxValue.value_or(0);
83fe6060f1SDimitry Andric }
84fe6060f1SDimitry Andric 
85bdd1243dSDimitry Andric static std::pair<unsigned, std::optional<unsigned>>
860eae32dcSDimitry Andric unpackVScaleRangeArgs(uint64_t Value) {
87fe6060f1SDimitry Andric   unsigned MaxValue = Value & std::numeric_limits<unsigned>::max();
88fe6060f1SDimitry Andric   unsigned MinValue = Value >> 32;
89fe6060f1SDimitry Andric 
900eae32dcSDimitry Andric   return std::make_pair(MinValue,
91bdd1243dSDimitry Andric                         MaxValue > 0 ? MaxValue : std::optional<unsigned>());
92fe6060f1SDimitry Andric }
93fe6060f1SDimitry Andric 
940b57cec5SDimitry Andric Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
950b57cec5SDimitry Andric                          uint64_t Val) {
96bdd1243dSDimitry Andric   bool IsIntAttr = Attribute::isIntAttrKind(Kind);
97bdd1243dSDimitry Andric   assert((IsIntAttr || Attribute::isEnumAttrKind(Kind)) &&
98bdd1243dSDimitry Andric          "Not an enum or int attribute");
99fe6060f1SDimitry Andric 
1000b57cec5SDimitry Andric   LLVMContextImpl *pImpl = Context.pImpl;
1010b57cec5SDimitry Andric   FoldingSetNodeID ID;
1020b57cec5SDimitry Andric   ID.AddInteger(Kind);
103bdd1243dSDimitry Andric   if (IsIntAttr)
104bdd1243dSDimitry Andric     ID.AddInteger(Val);
105bdd1243dSDimitry Andric   else
106bdd1243dSDimitry Andric     assert(Val == 0 && "Value must be zero for enum attributes");
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   void *InsertPoint;
1090b57cec5SDimitry Andric   AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   if (!PA) {
1120b57cec5SDimitry Andric     // If we didn't find any existing attributes of the same shape then create a
1130b57cec5SDimitry Andric     // new one and insert it.
114bdd1243dSDimitry Andric     if (!IsIntAttr)
1155ffd83dbSDimitry Andric       PA = new (pImpl->Alloc) EnumAttributeImpl(Kind);
1160b57cec5SDimitry Andric     else
1175ffd83dbSDimitry Andric       PA = new (pImpl->Alloc) IntAttributeImpl(Kind, Val);
1180b57cec5SDimitry Andric     pImpl->AttrsSet.InsertNode(PA, InsertPoint);
1190b57cec5SDimitry Andric   }
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   // Return the Attribute that we found or created.
1220b57cec5SDimitry Andric   return Attribute(PA);
1230b57cec5SDimitry Andric }
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric Attribute Attribute::get(LLVMContext &Context, StringRef Kind, StringRef Val) {
1260b57cec5SDimitry Andric   LLVMContextImpl *pImpl = Context.pImpl;
1270b57cec5SDimitry Andric   FoldingSetNodeID ID;
1280b57cec5SDimitry Andric   ID.AddString(Kind);
1290b57cec5SDimitry Andric   if (!Val.empty()) ID.AddString(Val);
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   void *InsertPoint;
1320b57cec5SDimitry Andric   AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   if (!PA) {
1350b57cec5SDimitry Andric     // If we didn't find any existing attributes of the same shape then create a
1360b57cec5SDimitry Andric     // new one and insert it.
1375ffd83dbSDimitry Andric     void *Mem =
1385ffd83dbSDimitry Andric         pImpl->Alloc.Allocate(StringAttributeImpl::totalSizeToAlloc(Kind, Val),
1395ffd83dbSDimitry Andric                               alignof(StringAttributeImpl));
1405ffd83dbSDimitry Andric     PA = new (Mem) StringAttributeImpl(Kind, Val);
1410b57cec5SDimitry Andric     pImpl->AttrsSet.InsertNode(PA, InsertPoint);
1420b57cec5SDimitry Andric   }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   // Return the Attribute that we found or created.
1450b57cec5SDimitry Andric   return Attribute(PA);
1460b57cec5SDimitry Andric }
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
1490b57cec5SDimitry Andric                          Type *Ty) {
150fe6060f1SDimitry Andric   assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute");
1510b57cec5SDimitry Andric   LLVMContextImpl *pImpl = Context.pImpl;
1520b57cec5SDimitry Andric   FoldingSetNodeID ID;
1530b57cec5SDimitry Andric   ID.AddInteger(Kind);
1540b57cec5SDimitry Andric   ID.AddPointer(Ty);
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   void *InsertPoint;
1570b57cec5SDimitry Andric   AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   if (!PA) {
1600b57cec5SDimitry Andric     // If we didn't find any existing attributes of the same shape then create a
1610b57cec5SDimitry Andric     // new one and insert it.
1625ffd83dbSDimitry Andric     PA = new (pImpl->Alloc) TypeAttributeImpl(Kind, Ty);
1630b57cec5SDimitry Andric     pImpl->AttrsSet.InsertNode(PA, InsertPoint);
1640b57cec5SDimitry Andric   }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   // Return the Attribute that we found or created.
1670b57cec5SDimitry Andric   return Attribute(PA);
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
170*0fca6ea1SDimitry Andric Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
171*0fca6ea1SDimitry Andric                          const ConstantRange &CR) {
172*0fca6ea1SDimitry Andric   assert(Attribute::isConstantRangeAttrKind(Kind) &&
173*0fca6ea1SDimitry Andric          "Not a ConstantRange attribute");
174*0fca6ea1SDimitry Andric   LLVMContextImpl *pImpl = Context.pImpl;
175*0fca6ea1SDimitry Andric   FoldingSetNodeID ID;
176*0fca6ea1SDimitry Andric   ID.AddInteger(Kind);
177*0fca6ea1SDimitry Andric   CR.getLower().Profile(ID);
178*0fca6ea1SDimitry Andric   CR.getUpper().Profile(ID);
179*0fca6ea1SDimitry Andric 
180*0fca6ea1SDimitry Andric   void *InsertPoint;
181*0fca6ea1SDimitry Andric   AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
182*0fca6ea1SDimitry Andric 
183*0fca6ea1SDimitry Andric   if (!PA) {
184*0fca6ea1SDimitry Andric     // If we didn't find any existing attributes of the same shape then create a
185*0fca6ea1SDimitry Andric     // new one and insert it.
186*0fca6ea1SDimitry Andric     PA = new (pImpl->ConstantRangeAttributeAlloc.Allocate())
187*0fca6ea1SDimitry Andric         ConstantRangeAttributeImpl(Kind, CR);
188*0fca6ea1SDimitry Andric     pImpl->AttrsSet.InsertNode(PA, InsertPoint);
189*0fca6ea1SDimitry Andric   }
190*0fca6ea1SDimitry Andric 
191*0fca6ea1SDimitry Andric   // Return the Attribute that we found or created.
192*0fca6ea1SDimitry Andric   return Attribute(PA);
193*0fca6ea1SDimitry Andric }
194*0fca6ea1SDimitry Andric 
195*0fca6ea1SDimitry Andric Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,
196*0fca6ea1SDimitry Andric                          ArrayRef<ConstantRange> Val) {
197*0fca6ea1SDimitry Andric   assert(Attribute::isConstantRangeListAttrKind(Kind) &&
198*0fca6ea1SDimitry Andric          "Not a ConstantRangeList attribute");
199*0fca6ea1SDimitry Andric   LLVMContextImpl *pImpl = Context.pImpl;
200*0fca6ea1SDimitry Andric   FoldingSetNodeID ID;
201*0fca6ea1SDimitry Andric   ID.AddInteger(Kind);
202*0fca6ea1SDimitry Andric   ID.AddInteger(Val.size());
203*0fca6ea1SDimitry Andric   for (auto &CR : Val) {
204*0fca6ea1SDimitry Andric     CR.getLower().Profile(ID);
205*0fca6ea1SDimitry Andric     CR.getUpper().Profile(ID);
206*0fca6ea1SDimitry Andric   }
207*0fca6ea1SDimitry Andric 
208*0fca6ea1SDimitry Andric   void *InsertPoint;
209*0fca6ea1SDimitry Andric   AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);
210*0fca6ea1SDimitry Andric 
211*0fca6ea1SDimitry Andric   if (!PA) {
212*0fca6ea1SDimitry Andric     // If we didn't find any existing attributes of the same shape then create a
213*0fca6ea1SDimitry Andric     // new one and insert it.
214*0fca6ea1SDimitry Andric     // ConstantRangeListAttributeImpl is a dynamically sized class and cannot
215*0fca6ea1SDimitry Andric     // use SpecificBumpPtrAllocator. Instead, we use normal Alloc for
216*0fca6ea1SDimitry Andric     // allocation and record the allocated pointer in
217*0fca6ea1SDimitry Andric     // `ConstantRangeListAttributes`. LLVMContext destructor will call the
218*0fca6ea1SDimitry Andric     // destructor of the allocated pointer explicitly.
219*0fca6ea1SDimitry Andric     void *Mem = pImpl->Alloc.Allocate(
220*0fca6ea1SDimitry Andric         ConstantRangeListAttributeImpl::totalSizeToAlloc(Val),
221*0fca6ea1SDimitry Andric         alignof(ConstantRangeListAttributeImpl));
222*0fca6ea1SDimitry Andric     PA = new (Mem) ConstantRangeListAttributeImpl(Kind, Val);
223*0fca6ea1SDimitry Andric     pImpl->AttrsSet.InsertNode(PA, InsertPoint);
224*0fca6ea1SDimitry Andric     pImpl->ConstantRangeListAttributes.push_back(
225*0fca6ea1SDimitry Andric         reinterpret_cast<ConstantRangeListAttributeImpl *>(PA));
226*0fca6ea1SDimitry Andric   }
227*0fca6ea1SDimitry Andric 
228*0fca6ea1SDimitry Andric   // Return the Attribute that we found or created.
229*0fca6ea1SDimitry Andric   return Attribute(PA);
230*0fca6ea1SDimitry Andric }
231*0fca6ea1SDimitry Andric 
2328bcb0991SDimitry Andric Attribute Attribute::getWithAlignment(LLVMContext &Context, Align A) {
2335ffd83dbSDimitry Andric   assert(A <= llvm::Value::MaximumAlignment && "Alignment too large.");
2348bcb0991SDimitry Andric   return get(Context, Alignment, A.value());
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric 
2378bcb0991SDimitry Andric Attribute Attribute::getWithStackAlignment(LLVMContext &Context, Align A) {
2388bcb0991SDimitry Andric   assert(A <= 0x100 && "Alignment too large.");
2398bcb0991SDimitry Andric   return get(Context, StackAlignment, A.value());
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context,
2430b57cec5SDimitry Andric                                                 uint64_t Bytes) {
2440b57cec5SDimitry Andric   assert(Bytes && "Bytes must be non-zero.");
2450b57cec5SDimitry Andric   return get(Context, Dereferenceable, Bytes);
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context,
2490b57cec5SDimitry Andric                                                        uint64_t Bytes) {
2500b57cec5SDimitry Andric   assert(Bytes && "Bytes must be non-zero.");
2510b57cec5SDimitry Andric   return get(Context, DereferenceableOrNull, Bytes);
2520b57cec5SDimitry Andric }
2530b57cec5SDimitry Andric 
2540b57cec5SDimitry Andric Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) {
2550b57cec5SDimitry Andric   return get(Context, ByVal, Ty);
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric 
258e8d8bef9SDimitry Andric Attribute Attribute::getWithStructRetType(LLVMContext &Context, Type *Ty) {
259e8d8bef9SDimitry Andric   return get(Context, StructRet, Ty);
260e8d8bef9SDimitry Andric }
261e8d8bef9SDimitry Andric 
262e8d8bef9SDimitry Andric Attribute Attribute::getWithByRefType(LLVMContext &Context, Type *Ty) {
263e8d8bef9SDimitry Andric   return get(Context, ByRef, Ty);
264e8d8bef9SDimitry Andric }
265e8d8bef9SDimitry Andric 
2665ffd83dbSDimitry Andric Attribute Attribute::getWithPreallocatedType(LLVMContext &Context, Type *Ty) {
2675ffd83dbSDimitry Andric   return get(Context, Preallocated, Ty);
2685ffd83dbSDimitry Andric }
2695ffd83dbSDimitry Andric 
270fe6060f1SDimitry Andric Attribute Attribute::getWithInAllocaType(LLVMContext &Context, Type *Ty) {
271fe6060f1SDimitry Andric   return get(Context, InAlloca, Ty);
272fe6060f1SDimitry Andric }
273fe6060f1SDimitry Andric 
27481ad6265SDimitry Andric Attribute Attribute::getWithUWTableKind(LLVMContext &Context,
27581ad6265SDimitry Andric                                         UWTableKind Kind) {
27681ad6265SDimitry Andric   return get(Context, UWTable, uint64_t(Kind));
27781ad6265SDimitry Andric }
27881ad6265SDimitry Andric 
279bdd1243dSDimitry Andric Attribute Attribute::getWithMemoryEffects(LLVMContext &Context,
280bdd1243dSDimitry Andric                                           MemoryEffects ME) {
281bdd1243dSDimitry Andric   return get(Context, Memory, ME.toIntValue());
282bdd1243dSDimitry Andric }
283bdd1243dSDimitry Andric 
28406c3fb27SDimitry Andric Attribute Attribute::getWithNoFPClass(LLVMContext &Context,
28506c3fb27SDimitry Andric                                       FPClassTest ClassMask) {
28606c3fb27SDimitry Andric   return get(Context, NoFPClass, ClassMask);
28706c3fb27SDimitry Andric }
28806c3fb27SDimitry Andric 
2890b57cec5SDimitry Andric Attribute
2900b57cec5SDimitry Andric Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg,
291bdd1243dSDimitry Andric                                 const std::optional<unsigned> &NumElemsArg) {
2920b57cec5SDimitry Andric   assert(!(ElemSizeArg == 0 && NumElemsArg && *NumElemsArg == 0) &&
2930b57cec5SDimitry Andric          "Invalid allocsize arguments -- given allocsize(0, 0)");
2940b57cec5SDimitry Andric   return get(Context, AllocSize, packAllocSizeArgs(ElemSizeArg, NumElemsArg));
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric 
297fe6060f1SDimitry Andric Attribute Attribute::getWithVScaleRangeArgs(LLVMContext &Context,
298fe6060f1SDimitry Andric                                             unsigned MinValue,
299fe6060f1SDimitry Andric                                             unsigned MaxValue) {
300fe6060f1SDimitry Andric   return get(Context, VScaleRange, packVScaleRangeArgs(MinValue, MaxValue));
301fe6060f1SDimitry Andric }
302fe6060f1SDimitry Andric 
3035ffd83dbSDimitry Andric Attribute::AttrKind Attribute::getAttrKindFromName(StringRef AttrName) {
3045ffd83dbSDimitry Andric   return StringSwitch<Attribute::AttrKind>(AttrName)
3055ffd83dbSDimitry Andric #define GET_ATTR_NAMES
3065ffd83dbSDimitry Andric #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME)                                \
3075ffd83dbSDimitry Andric   .Case(#DISPLAY_NAME, Attribute::ENUM_NAME)
3085ffd83dbSDimitry Andric #include "llvm/IR/Attributes.inc"
3095ffd83dbSDimitry Andric       .Default(Attribute::None);
3105ffd83dbSDimitry Andric }
3115ffd83dbSDimitry Andric 
3125ffd83dbSDimitry Andric StringRef Attribute::getNameFromAttrKind(Attribute::AttrKind AttrKind) {
3135ffd83dbSDimitry Andric   switch (AttrKind) {
3145ffd83dbSDimitry Andric #define GET_ATTR_NAMES
3155ffd83dbSDimitry Andric #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME)                                \
3165ffd83dbSDimitry Andric   case Attribute::ENUM_NAME:                                                   \
3175ffd83dbSDimitry Andric     return #DISPLAY_NAME;
3185ffd83dbSDimitry Andric #include "llvm/IR/Attributes.inc"
3195ffd83dbSDimitry Andric   case Attribute::None:
3205ffd83dbSDimitry Andric     return "none";
3215ffd83dbSDimitry Andric   default:
3225ffd83dbSDimitry Andric     llvm_unreachable("invalid Kind");
3235ffd83dbSDimitry Andric   }
3245ffd83dbSDimitry Andric }
3255ffd83dbSDimitry Andric 
3265ffd83dbSDimitry Andric bool Attribute::isExistingAttribute(StringRef Name) {
3275ffd83dbSDimitry Andric   return StringSwitch<bool>(Name)
3285ffd83dbSDimitry Andric #define GET_ATTR_NAMES
3295ffd83dbSDimitry Andric #define ATTRIBUTE_ALL(ENUM_NAME, DISPLAY_NAME) .Case(#DISPLAY_NAME, true)
3305ffd83dbSDimitry Andric #include "llvm/IR/Attributes.inc"
3315ffd83dbSDimitry Andric       .Default(false);
3325ffd83dbSDimitry Andric }
3335ffd83dbSDimitry Andric 
3340b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3350b57cec5SDimitry Andric // Attribute Accessor Methods
3360b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric bool Attribute::isEnumAttribute() const {
3390b57cec5SDimitry Andric   return pImpl && pImpl->isEnumAttribute();
3400b57cec5SDimitry Andric }
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric bool Attribute::isIntAttribute() const {
3430b57cec5SDimitry Andric   return pImpl && pImpl->isIntAttribute();
3440b57cec5SDimitry Andric }
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric bool Attribute::isStringAttribute() const {
3470b57cec5SDimitry Andric   return pImpl && pImpl->isStringAttribute();
3480b57cec5SDimitry Andric }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric bool Attribute::isTypeAttribute() const {
3510b57cec5SDimitry Andric   return pImpl && pImpl->isTypeAttribute();
3520b57cec5SDimitry Andric }
3530b57cec5SDimitry Andric 
354*0fca6ea1SDimitry Andric bool Attribute::isConstantRangeAttribute() const {
355*0fca6ea1SDimitry Andric   return pImpl && pImpl->isConstantRangeAttribute();
356*0fca6ea1SDimitry Andric }
357*0fca6ea1SDimitry Andric 
358*0fca6ea1SDimitry Andric bool Attribute::isConstantRangeListAttribute() const {
359*0fca6ea1SDimitry Andric   return pImpl && pImpl->isConstantRangeListAttribute();
360*0fca6ea1SDimitry Andric }
361*0fca6ea1SDimitry Andric 
3620b57cec5SDimitry Andric Attribute::AttrKind Attribute::getKindAsEnum() const {
3630b57cec5SDimitry Andric   if (!pImpl) return None;
364*0fca6ea1SDimitry Andric   assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
365*0fca6ea1SDimitry Andric           isConstantRangeAttribute() || isConstantRangeListAttribute()) &&
3660b57cec5SDimitry Andric          "Invalid attribute type to get the kind as an enum!");
3670b57cec5SDimitry Andric   return pImpl->getKindAsEnum();
3680b57cec5SDimitry Andric }
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric uint64_t Attribute::getValueAsInt() const {
3710b57cec5SDimitry Andric   if (!pImpl) return 0;
3720b57cec5SDimitry Andric   assert(isIntAttribute() &&
3730b57cec5SDimitry Andric          "Expected the attribute to be an integer attribute!");
3740b57cec5SDimitry Andric   return pImpl->getValueAsInt();
3750b57cec5SDimitry Andric }
3760b57cec5SDimitry Andric 
377fe6060f1SDimitry Andric bool Attribute::getValueAsBool() const {
378fe6060f1SDimitry Andric   if (!pImpl) return false;
379fe6060f1SDimitry Andric   assert(isStringAttribute() &&
380fe6060f1SDimitry Andric          "Expected the attribute to be a string attribute!");
381fe6060f1SDimitry Andric   return pImpl->getValueAsBool();
382fe6060f1SDimitry Andric }
383fe6060f1SDimitry Andric 
3840b57cec5SDimitry Andric StringRef Attribute::getKindAsString() const {
3850b57cec5SDimitry Andric   if (!pImpl) return {};
3860b57cec5SDimitry Andric   assert(isStringAttribute() &&
3870b57cec5SDimitry Andric          "Invalid attribute type to get the kind as a string!");
3880b57cec5SDimitry Andric   return pImpl->getKindAsString();
3890b57cec5SDimitry Andric }
3900b57cec5SDimitry Andric 
3910b57cec5SDimitry Andric StringRef Attribute::getValueAsString() const {
3920b57cec5SDimitry Andric   if (!pImpl) return {};
3930b57cec5SDimitry Andric   assert(isStringAttribute() &&
3940b57cec5SDimitry Andric          "Invalid attribute type to get the value as a string!");
3950b57cec5SDimitry Andric   return pImpl->getValueAsString();
3960b57cec5SDimitry Andric }
3970b57cec5SDimitry Andric 
3980b57cec5SDimitry Andric Type *Attribute::getValueAsType() const {
3990b57cec5SDimitry Andric   if (!pImpl) return {};
4000b57cec5SDimitry Andric   assert(isTypeAttribute() &&
4010b57cec5SDimitry Andric          "Invalid attribute type to get the value as a type!");
4020b57cec5SDimitry Andric   return pImpl->getValueAsType();
4030b57cec5SDimitry Andric }
4040b57cec5SDimitry Andric 
405*0fca6ea1SDimitry Andric const ConstantRange &Attribute::getValueAsConstantRange() const {
406*0fca6ea1SDimitry Andric   assert(isConstantRangeAttribute() &&
407*0fca6ea1SDimitry Andric          "Invalid attribute type to get the value as a ConstantRange!");
408*0fca6ea1SDimitry Andric   return pImpl->getValueAsConstantRange();
409*0fca6ea1SDimitry Andric }
410*0fca6ea1SDimitry Andric 
411*0fca6ea1SDimitry Andric ArrayRef<ConstantRange> Attribute::getValueAsConstantRangeList() const {
412*0fca6ea1SDimitry Andric   assert(isConstantRangeListAttribute() &&
413*0fca6ea1SDimitry Andric          "Invalid attribute type to get the value as a ConstantRangeList!");
414*0fca6ea1SDimitry Andric   return pImpl->getValueAsConstantRangeList();
415*0fca6ea1SDimitry Andric }
4160b57cec5SDimitry Andric 
4170b57cec5SDimitry Andric bool Attribute::hasAttribute(AttrKind Kind) const {
4180b57cec5SDimitry Andric   return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None);
4190b57cec5SDimitry Andric }
4200b57cec5SDimitry Andric 
4210b57cec5SDimitry Andric bool Attribute::hasAttribute(StringRef Kind) const {
4220b57cec5SDimitry Andric   if (!isStringAttribute()) return false;
4230b57cec5SDimitry Andric   return pImpl && pImpl->hasAttribute(Kind);
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric 
4268bcb0991SDimitry Andric MaybeAlign Attribute::getAlignment() const {
4270b57cec5SDimitry Andric   assert(hasAttribute(Attribute::Alignment) &&
4280b57cec5SDimitry Andric          "Trying to get alignment from non-alignment attribute!");
4298bcb0991SDimitry Andric   return MaybeAlign(pImpl->getValueAsInt());
4300b57cec5SDimitry Andric }
4310b57cec5SDimitry Andric 
4328bcb0991SDimitry Andric MaybeAlign Attribute::getStackAlignment() const {
4330b57cec5SDimitry Andric   assert(hasAttribute(Attribute::StackAlignment) &&
4340b57cec5SDimitry Andric          "Trying to get alignment from non-alignment attribute!");
4358bcb0991SDimitry Andric   return MaybeAlign(pImpl->getValueAsInt());
4360b57cec5SDimitry Andric }
4370b57cec5SDimitry Andric 
4380b57cec5SDimitry Andric uint64_t Attribute::getDereferenceableBytes() const {
4390b57cec5SDimitry Andric   assert(hasAttribute(Attribute::Dereferenceable) &&
4400b57cec5SDimitry Andric          "Trying to get dereferenceable bytes from "
4410b57cec5SDimitry Andric          "non-dereferenceable attribute!");
4420b57cec5SDimitry Andric   return pImpl->getValueAsInt();
4430b57cec5SDimitry Andric }
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric uint64_t Attribute::getDereferenceableOrNullBytes() const {
4460b57cec5SDimitry Andric   assert(hasAttribute(Attribute::DereferenceableOrNull) &&
4470b57cec5SDimitry Andric          "Trying to get dereferenceable bytes from "
4480b57cec5SDimitry Andric          "non-dereferenceable attribute!");
4490b57cec5SDimitry Andric   return pImpl->getValueAsInt();
4500b57cec5SDimitry Andric }
4510b57cec5SDimitry Andric 
452bdd1243dSDimitry Andric std::pair<unsigned, std::optional<unsigned>>
453bdd1243dSDimitry Andric Attribute::getAllocSizeArgs() const {
4540b57cec5SDimitry Andric   assert(hasAttribute(Attribute::AllocSize) &&
4550b57cec5SDimitry Andric          "Trying to get allocsize args from non-allocsize attribute");
4560b57cec5SDimitry Andric   return unpackAllocSizeArgs(pImpl->getValueAsInt());
4570b57cec5SDimitry Andric }
4580b57cec5SDimitry Andric 
4590eae32dcSDimitry Andric unsigned Attribute::getVScaleRangeMin() const {
460fe6060f1SDimitry Andric   assert(hasAttribute(Attribute::VScaleRange) &&
461fe6060f1SDimitry Andric          "Trying to get vscale args from non-vscale attribute");
4620eae32dcSDimitry Andric   return unpackVScaleRangeArgs(pImpl->getValueAsInt()).first;
4630eae32dcSDimitry Andric }
4640eae32dcSDimitry Andric 
465bdd1243dSDimitry Andric std::optional<unsigned> Attribute::getVScaleRangeMax() const {
4660eae32dcSDimitry Andric   assert(hasAttribute(Attribute::VScaleRange) &&
4670eae32dcSDimitry Andric          "Trying to get vscale args from non-vscale attribute");
4680eae32dcSDimitry Andric   return unpackVScaleRangeArgs(pImpl->getValueAsInt()).second;
469fe6060f1SDimitry Andric }
470fe6060f1SDimitry Andric 
47181ad6265SDimitry Andric UWTableKind Attribute::getUWTableKind() const {
47281ad6265SDimitry Andric   assert(hasAttribute(Attribute::UWTable) &&
47381ad6265SDimitry Andric          "Trying to get unwind table kind from non-uwtable attribute");
47481ad6265SDimitry Andric   return UWTableKind(pImpl->getValueAsInt());
47581ad6265SDimitry Andric }
47681ad6265SDimitry Andric 
47781ad6265SDimitry Andric AllocFnKind Attribute::getAllocKind() const {
47881ad6265SDimitry Andric   assert(hasAttribute(Attribute::AllocKind) &&
47981ad6265SDimitry Andric          "Trying to get allockind value from non-allockind attribute");
48081ad6265SDimitry Andric   return AllocFnKind(pImpl->getValueAsInt());
48181ad6265SDimitry Andric }
48281ad6265SDimitry Andric 
483bdd1243dSDimitry Andric MemoryEffects Attribute::getMemoryEffects() const {
484bdd1243dSDimitry Andric   assert(hasAttribute(Attribute::Memory) &&
485bdd1243dSDimitry Andric          "Can only call getMemoryEffects() on memory attribute");
486bdd1243dSDimitry Andric   return MemoryEffects::createFromIntValue(pImpl->getValueAsInt());
487bdd1243dSDimitry Andric }
488bdd1243dSDimitry Andric 
48906c3fb27SDimitry Andric FPClassTest Attribute::getNoFPClass() const {
49006c3fb27SDimitry Andric   assert(hasAttribute(Attribute::NoFPClass) &&
49106c3fb27SDimitry Andric          "Can only call getNoFPClass() on nofpclass attribute");
49206c3fb27SDimitry Andric   return static_cast<FPClassTest>(pImpl->getValueAsInt());
49306c3fb27SDimitry Andric }
49406c3fb27SDimitry Andric 
495*0fca6ea1SDimitry Andric const ConstantRange &Attribute::getRange() const {
496*0fca6ea1SDimitry Andric   assert(hasAttribute(Attribute::Range) &&
497*0fca6ea1SDimitry Andric          "Trying to get range args from non-range attribute");
498*0fca6ea1SDimitry Andric   return pImpl->getValueAsConstantRange();
499*0fca6ea1SDimitry Andric }
500*0fca6ea1SDimitry Andric 
501*0fca6ea1SDimitry Andric ArrayRef<ConstantRange> Attribute::getInitializes() const {
502*0fca6ea1SDimitry Andric   assert(hasAttribute(Attribute::Initializes) &&
503*0fca6ea1SDimitry Andric          "Trying to get initializes attr from non-ConstantRangeList attribute");
504*0fca6ea1SDimitry Andric   return pImpl->getValueAsConstantRangeList();
505*0fca6ea1SDimitry Andric }
506*0fca6ea1SDimitry Andric 
507bdd1243dSDimitry Andric static const char *getModRefStr(ModRefInfo MR) {
508bdd1243dSDimitry Andric   switch (MR) {
509bdd1243dSDimitry Andric   case ModRefInfo::NoModRef:
510bdd1243dSDimitry Andric     return "none";
511bdd1243dSDimitry Andric   case ModRefInfo::Ref:
512bdd1243dSDimitry Andric     return "read";
513bdd1243dSDimitry Andric   case ModRefInfo::Mod:
514bdd1243dSDimitry Andric     return "write";
515bdd1243dSDimitry Andric   case ModRefInfo::ModRef:
516bdd1243dSDimitry Andric     return "readwrite";
517bdd1243dSDimitry Andric   }
518bdd1243dSDimitry Andric   llvm_unreachable("Invalid ModRefInfo");
519bdd1243dSDimitry Andric }
520bdd1243dSDimitry Andric 
5210b57cec5SDimitry Andric std::string Attribute::getAsString(bool InAttrGrp) const {
5220b57cec5SDimitry Andric   if (!pImpl) return {};
5230b57cec5SDimitry Andric 
524fe6060f1SDimitry Andric   if (isEnumAttribute())
525fe6060f1SDimitry Andric     return getNameFromAttrKind(getKindAsEnum()).str();
5260b57cec5SDimitry Andric 
527fe6060f1SDimitry Andric   if (isTypeAttribute()) {
528fe6060f1SDimitry Andric     std::string Result = getNameFromAttrKind(getKindAsEnum()).str();
5290b57cec5SDimitry Andric     Result += '(';
5305ffd83dbSDimitry Andric     raw_string_ostream OS(Result);
5315ffd83dbSDimitry Andric     getValueAsType()->print(OS, false, true);
5325ffd83dbSDimitry Andric     OS.flush();
5335ffd83dbSDimitry Andric     Result += ')';
5345ffd83dbSDimitry Andric     return Result;
5355ffd83dbSDimitry Andric   }
5365ffd83dbSDimitry Andric 
5370b57cec5SDimitry Andric   // FIXME: These should be output like this:
5380b57cec5SDimitry Andric   //
5390b57cec5SDimitry Andric   //   align=4
5400b57cec5SDimitry Andric   //   alignstack=8
5410b57cec5SDimitry Andric   //
5421fd87a68SDimitry Andric   if (hasAttribute(Attribute::Alignment))
5431fd87a68SDimitry Andric     return (InAttrGrp ? "align=" + Twine(getValueAsInt())
5441fd87a68SDimitry Andric                       : "align " + Twine(getValueAsInt()))
5451fd87a68SDimitry Andric         .str();
5460b57cec5SDimitry Andric 
5470b57cec5SDimitry Andric   auto AttrWithBytesToString = [&](const char *Name) {
5481fd87a68SDimitry Andric     return (InAttrGrp ? Name + ("=" + Twine(getValueAsInt()))
5491fd87a68SDimitry Andric                       : Name + ("(" + Twine(getValueAsInt())) + ")")
5501fd87a68SDimitry Andric         .str();
5510b57cec5SDimitry Andric   };
5520b57cec5SDimitry Andric 
5530b57cec5SDimitry Andric   if (hasAttribute(Attribute::StackAlignment))
5540b57cec5SDimitry Andric     return AttrWithBytesToString("alignstack");
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric   if (hasAttribute(Attribute::Dereferenceable))
5570b57cec5SDimitry Andric     return AttrWithBytesToString("dereferenceable");
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric   if (hasAttribute(Attribute::DereferenceableOrNull))
5600b57cec5SDimitry Andric     return AttrWithBytesToString("dereferenceable_or_null");
5610b57cec5SDimitry Andric 
5620b57cec5SDimitry Andric   if (hasAttribute(Attribute::AllocSize)) {
5630b57cec5SDimitry Andric     unsigned ElemSize;
564bdd1243dSDimitry Andric     std::optional<unsigned> NumElems;
5650b57cec5SDimitry Andric     std::tie(ElemSize, NumElems) = getAllocSizeArgs();
5660b57cec5SDimitry Andric 
5671fd87a68SDimitry Andric     return (NumElems
5681fd87a68SDimitry Andric                 ? "allocsize(" + Twine(ElemSize) + "," + Twine(*NumElems) + ")"
5691fd87a68SDimitry Andric                 : "allocsize(" + Twine(ElemSize) + ")")
5701fd87a68SDimitry Andric         .str();
5710b57cec5SDimitry Andric   }
5720b57cec5SDimitry Andric 
573fe6060f1SDimitry Andric   if (hasAttribute(Attribute::VScaleRange)) {
5740eae32dcSDimitry Andric     unsigned MinValue = getVScaleRangeMin();
575bdd1243dSDimitry Andric     std::optional<unsigned> MaxValue = getVScaleRangeMax();
5761fd87a68SDimitry Andric     return ("vscale_range(" + Twine(MinValue) + "," +
57781ad6265SDimitry Andric             Twine(MaxValue.value_or(0)) + ")")
57881ad6265SDimitry Andric         .str();
57981ad6265SDimitry Andric   }
58081ad6265SDimitry Andric 
58181ad6265SDimitry Andric   if (hasAttribute(Attribute::UWTable)) {
58281ad6265SDimitry Andric     UWTableKind Kind = getUWTableKind();
583*0fca6ea1SDimitry Andric     assert(Kind != UWTableKind::None && "uwtable attribute should not be none");
584*0fca6ea1SDimitry Andric     return Kind == UWTableKind::Default ? "uwtable" : "uwtable(sync)";
58581ad6265SDimitry Andric   }
58681ad6265SDimitry Andric 
58781ad6265SDimitry Andric   if (hasAttribute(Attribute::AllocKind)) {
58881ad6265SDimitry Andric     AllocFnKind Kind = getAllocKind();
58981ad6265SDimitry Andric     SmallVector<StringRef> parts;
59081ad6265SDimitry Andric     if ((Kind & AllocFnKind::Alloc) != AllocFnKind::Unknown)
59181ad6265SDimitry Andric       parts.push_back("alloc");
59281ad6265SDimitry Andric     if ((Kind & AllocFnKind::Realloc) != AllocFnKind::Unknown)
59381ad6265SDimitry Andric       parts.push_back("realloc");
59481ad6265SDimitry Andric     if ((Kind & AllocFnKind::Free) != AllocFnKind::Unknown)
59581ad6265SDimitry Andric       parts.push_back("free");
59681ad6265SDimitry Andric     if ((Kind & AllocFnKind::Uninitialized) != AllocFnKind::Unknown)
59781ad6265SDimitry Andric       parts.push_back("uninitialized");
59881ad6265SDimitry Andric     if ((Kind & AllocFnKind::Zeroed) != AllocFnKind::Unknown)
59981ad6265SDimitry Andric       parts.push_back("zeroed");
60081ad6265SDimitry Andric     if ((Kind & AllocFnKind::Aligned) != AllocFnKind::Unknown)
60181ad6265SDimitry Andric       parts.push_back("aligned");
60281ad6265SDimitry Andric     return ("allockind(\"" +
60381ad6265SDimitry Andric             Twine(llvm::join(parts.begin(), parts.end(), ",")) + "\")")
6041fd87a68SDimitry Andric         .str();
605fe6060f1SDimitry Andric   }
606fe6060f1SDimitry Andric 
607bdd1243dSDimitry Andric   if (hasAttribute(Attribute::Memory)) {
608bdd1243dSDimitry Andric     std::string Result;
609bdd1243dSDimitry Andric     raw_string_ostream OS(Result);
610bdd1243dSDimitry Andric     bool First = true;
611bdd1243dSDimitry Andric     OS << "memory(";
612bdd1243dSDimitry Andric 
613bdd1243dSDimitry Andric     MemoryEffects ME = getMemoryEffects();
614bdd1243dSDimitry Andric 
615bdd1243dSDimitry Andric     // Print access kind for "other" as the default access kind. This way it
616bdd1243dSDimitry Andric     // will apply to any new location kinds that get split out of "other".
61706c3fb27SDimitry Andric     ModRefInfo OtherMR = ME.getModRef(IRMemLocation::Other);
618bdd1243dSDimitry Andric     if (OtherMR != ModRefInfo::NoModRef || ME.getModRef() == OtherMR) {
619bdd1243dSDimitry Andric       First = false;
620bdd1243dSDimitry Andric       OS << getModRefStr(OtherMR);
621bdd1243dSDimitry Andric     }
622bdd1243dSDimitry Andric 
623bdd1243dSDimitry Andric     for (auto Loc : MemoryEffects::locations()) {
624bdd1243dSDimitry Andric       ModRefInfo MR = ME.getModRef(Loc);
625bdd1243dSDimitry Andric       if (MR == OtherMR)
626bdd1243dSDimitry Andric         continue;
627bdd1243dSDimitry Andric 
628bdd1243dSDimitry Andric       if (!First)
629bdd1243dSDimitry Andric         OS << ", ";
630bdd1243dSDimitry Andric       First = false;
631bdd1243dSDimitry Andric 
632bdd1243dSDimitry Andric       switch (Loc) {
63306c3fb27SDimitry Andric       case IRMemLocation::ArgMem:
634bdd1243dSDimitry Andric         OS << "argmem: ";
635bdd1243dSDimitry Andric         break;
63606c3fb27SDimitry Andric       case IRMemLocation::InaccessibleMem:
637bdd1243dSDimitry Andric         OS << "inaccessiblemem: ";
638bdd1243dSDimitry Andric         break;
63906c3fb27SDimitry Andric       case IRMemLocation::Other:
640bdd1243dSDimitry Andric         llvm_unreachable("This is represented as the default access kind");
641bdd1243dSDimitry Andric       }
642bdd1243dSDimitry Andric       OS << getModRefStr(MR);
643bdd1243dSDimitry Andric     }
644bdd1243dSDimitry Andric     OS << ")";
645bdd1243dSDimitry Andric     OS.flush();
646bdd1243dSDimitry Andric     return Result;
647bdd1243dSDimitry Andric   }
648bdd1243dSDimitry Andric 
64906c3fb27SDimitry Andric   if (hasAttribute(Attribute::NoFPClass)) {
65006c3fb27SDimitry Andric     std::string Result = "nofpclass";
65106c3fb27SDimitry Andric     raw_string_ostream OS(Result);
65206c3fb27SDimitry Andric     OS << getNoFPClass();
65306c3fb27SDimitry Andric     return Result;
65406c3fb27SDimitry Andric   }
65506c3fb27SDimitry Andric 
656*0fca6ea1SDimitry Andric   if (hasAttribute(Attribute::Range)) {
657*0fca6ea1SDimitry Andric     std::string Result;
658*0fca6ea1SDimitry Andric     raw_string_ostream OS(Result);
659*0fca6ea1SDimitry Andric     const ConstantRange &CR = getValueAsConstantRange();
660*0fca6ea1SDimitry Andric     OS << "range(";
661*0fca6ea1SDimitry Andric     OS << "i" << CR.getBitWidth() << " ";
662*0fca6ea1SDimitry Andric     OS << CR.getLower() << ", " << CR.getUpper();
663*0fca6ea1SDimitry Andric     OS << ")";
664*0fca6ea1SDimitry Andric     OS.flush();
665*0fca6ea1SDimitry Andric     return Result;
666*0fca6ea1SDimitry Andric   }
667*0fca6ea1SDimitry Andric 
668*0fca6ea1SDimitry Andric   if (hasAttribute(Attribute::Initializes)) {
669*0fca6ea1SDimitry Andric     std::string Result;
670*0fca6ea1SDimitry Andric     raw_string_ostream OS(Result);
671*0fca6ea1SDimitry Andric     ConstantRangeList CRL = getInitializes();
672*0fca6ea1SDimitry Andric     OS << "initializes(";
673*0fca6ea1SDimitry Andric     CRL.print(OS);
674*0fca6ea1SDimitry Andric     OS << ")";
675*0fca6ea1SDimitry Andric     OS.flush();
676*0fca6ea1SDimitry Andric     return Result;
677*0fca6ea1SDimitry Andric   }
678*0fca6ea1SDimitry Andric 
6790b57cec5SDimitry Andric   // Convert target-dependent attributes to strings of the form:
6800b57cec5SDimitry Andric   //
6810b57cec5SDimitry Andric   //   "kind"
6820b57cec5SDimitry Andric   //   "kind" = "value"
6830b57cec5SDimitry Andric   //
6840b57cec5SDimitry Andric   if (isStringAttribute()) {
6850b57cec5SDimitry Andric     std::string Result;
6860b57cec5SDimitry Andric     {
6870b57cec5SDimitry Andric       raw_string_ostream OS(Result);
6885ffd83dbSDimitry Andric       OS << '"' << getKindAsString() << '"';
6895ffd83dbSDimitry Andric 
6905ffd83dbSDimitry Andric       // Since some attribute strings contain special characters that cannot be
6915ffd83dbSDimitry Andric       // printable, those have to be escaped to make the attribute value
6925ffd83dbSDimitry Andric       // printable as is.  e.g. "\01__gnu_mcount_nc"
6935ffd83dbSDimitry Andric       const auto &AttrVal = pImpl->getValueAsString();
6945ffd83dbSDimitry Andric       if (!AttrVal.empty()) {
6950b57cec5SDimitry Andric         OS << "=\"";
6960b57cec5SDimitry Andric         printEscapedString(AttrVal, OS);
6970b57cec5SDimitry Andric         OS << "\"";
6980b57cec5SDimitry Andric       }
6995ffd83dbSDimitry Andric     }
7000b57cec5SDimitry Andric     return Result;
7010b57cec5SDimitry Andric   }
7020b57cec5SDimitry Andric 
7030b57cec5SDimitry Andric   llvm_unreachable("Unknown attribute");
7040b57cec5SDimitry Andric }
7050b57cec5SDimitry Andric 
706fe6060f1SDimitry Andric bool Attribute::hasParentContext(LLVMContext &C) const {
707fe6060f1SDimitry Andric   assert(isValid() && "invalid Attribute doesn't refer to any context");
708fe6060f1SDimitry Andric   FoldingSetNodeID ID;
709fe6060f1SDimitry Andric   pImpl->Profile(ID);
710fe6060f1SDimitry Andric   void *Unused;
711fe6060f1SDimitry Andric   return C.pImpl->AttrsSet.FindNodeOrInsertPos(ID, Unused) == pImpl;
712fe6060f1SDimitry Andric }
713fe6060f1SDimitry Andric 
7140b57cec5SDimitry Andric bool Attribute::operator<(Attribute A) const {
7150b57cec5SDimitry Andric   if (!pImpl && !A.pImpl) return false;
7160b57cec5SDimitry Andric   if (!pImpl) return true;
7170b57cec5SDimitry Andric   if (!A.pImpl) return false;
7180b57cec5SDimitry Andric   return *pImpl < *A.pImpl;
7190b57cec5SDimitry Andric }
7200b57cec5SDimitry Andric 
7215ffd83dbSDimitry Andric void Attribute::Profile(FoldingSetNodeID &ID) const {
7225ffd83dbSDimitry Andric   ID.AddPointer(pImpl);
7235ffd83dbSDimitry Andric }
7245ffd83dbSDimitry Andric 
725fe6060f1SDimitry Andric enum AttributeProperty {
726fe6060f1SDimitry Andric   FnAttr = (1 << 0),
727fe6060f1SDimitry Andric   ParamAttr = (1 << 1),
728fe6060f1SDimitry Andric   RetAttr = (1 << 2),
729fe6060f1SDimitry Andric };
730fe6060f1SDimitry Andric 
731fe6060f1SDimitry Andric #define GET_ATTR_PROP_TABLE
732fe6060f1SDimitry Andric #include "llvm/IR/Attributes.inc"
733fe6060f1SDimitry Andric 
734fe6060f1SDimitry Andric static bool hasAttributeProperty(Attribute::AttrKind Kind,
735fe6060f1SDimitry Andric                                  AttributeProperty Prop) {
736fe6060f1SDimitry Andric   unsigned Index = Kind - 1;
737bdd1243dSDimitry Andric   assert(Index < std::size(AttrPropTable) && "Invalid attribute kind");
738fe6060f1SDimitry Andric   return AttrPropTable[Index] & Prop;
739fe6060f1SDimitry Andric }
740fe6060f1SDimitry Andric 
741fe6060f1SDimitry Andric bool Attribute::canUseAsFnAttr(AttrKind Kind) {
742fe6060f1SDimitry Andric   return hasAttributeProperty(Kind, AttributeProperty::FnAttr);
743fe6060f1SDimitry Andric }
744fe6060f1SDimitry Andric 
745fe6060f1SDimitry Andric bool Attribute::canUseAsParamAttr(AttrKind Kind) {
746fe6060f1SDimitry Andric   return hasAttributeProperty(Kind, AttributeProperty::ParamAttr);
747fe6060f1SDimitry Andric }
748fe6060f1SDimitry Andric 
749fe6060f1SDimitry Andric bool Attribute::canUseAsRetAttr(AttrKind Kind) {
750fe6060f1SDimitry Andric   return hasAttributeProperty(Kind, AttributeProperty::RetAttr);
751fe6060f1SDimitry Andric }
752fe6060f1SDimitry Andric 
7530b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7540b57cec5SDimitry Andric // AttributeImpl Definition
7550b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7560b57cec5SDimitry Andric 
7570b57cec5SDimitry Andric bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const {
7580b57cec5SDimitry Andric   if (isStringAttribute()) return false;
7590b57cec5SDimitry Andric   return getKindAsEnum() == A;
7600b57cec5SDimitry Andric }
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric bool AttributeImpl::hasAttribute(StringRef Kind) const {
7630b57cec5SDimitry Andric   if (!isStringAttribute()) return false;
7640b57cec5SDimitry Andric   return getKindAsString() == Kind;
7650b57cec5SDimitry Andric }
7660b57cec5SDimitry Andric 
7670b57cec5SDimitry Andric Attribute::AttrKind AttributeImpl::getKindAsEnum() const {
768*0fca6ea1SDimitry Andric   assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||
769*0fca6ea1SDimitry Andric          isConstantRangeAttribute() || isConstantRangeListAttribute());
7700b57cec5SDimitry Andric   return static_cast<const EnumAttributeImpl *>(this)->getEnumKind();
7710b57cec5SDimitry Andric }
7720b57cec5SDimitry Andric 
7730b57cec5SDimitry Andric uint64_t AttributeImpl::getValueAsInt() const {
7740b57cec5SDimitry Andric   assert(isIntAttribute());
7750b57cec5SDimitry Andric   return static_cast<const IntAttributeImpl *>(this)->getValue();
7760b57cec5SDimitry Andric }
7770b57cec5SDimitry Andric 
778fe6060f1SDimitry Andric bool AttributeImpl::getValueAsBool() const {
779fe6060f1SDimitry Andric   assert(getValueAsString().empty() || getValueAsString() == "false" || getValueAsString() == "true");
780fe6060f1SDimitry Andric   return getValueAsString() == "true";
781fe6060f1SDimitry Andric }
782fe6060f1SDimitry Andric 
7830b57cec5SDimitry Andric StringRef AttributeImpl::getKindAsString() const {
7840b57cec5SDimitry Andric   assert(isStringAttribute());
7850b57cec5SDimitry Andric   return static_cast<const StringAttributeImpl *>(this)->getStringKind();
7860b57cec5SDimitry Andric }
7870b57cec5SDimitry Andric 
7880b57cec5SDimitry Andric StringRef AttributeImpl::getValueAsString() const {
7890b57cec5SDimitry Andric   assert(isStringAttribute());
7900b57cec5SDimitry Andric   return static_cast<const StringAttributeImpl *>(this)->getStringValue();
7910b57cec5SDimitry Andric }
7920b57cec5SDimitry Andric 
7930b57cec5SDimitry Andric Type *AttributeImpl::getValueAsType() const {
7940b57cec5SDimitry Andric   assert(isTypeAttribute());
7950b57cec5SDimitry Andric   return static_cast<const TypeAttributeImpl *>(this)->getTypeValue();
7960b57cec5SDimitry Andric }
7970b57cec5SDimitry Andric 
798*0fca6ea1SDimitry Andric const ConstantRange &AttributeImpl::getValueAsConstantRange() const {
799*0fca6ea1SDimitry Andric   assert(isConstantRangeAttribute());
800*0fca6ea1SDimitry Andric   return static_cast<const ConstantRangeAttributeImpl *>(this)
801*0fca6ea1SDimitry Andric       ->getConstantRangeValue();
802*0fca6ea1SDimitry Andric }
803*0fca6ea1SDimitry Andric 
804*0fca6ea1SDimitry Andric ArrayRef<ConstantRange> AttributeImpl::getValueAsConstantRangeList() const {
805*0fca6ea1SDimitry Andric   assert(isConstantRangeListAttribute());
806*0fca6ea1SDimitry Andric   return static_cast<const ConstantRangeListAttributeImpl *>(this)
807*0fca6ea1SDimitry Andric       ->getConstantRangeListValue();
808*0fca6ea1SDimitry Andric }
809*0fca6ea1SDimitry Andric 
8100b57cec5SDimitry Andric bool AttributeImpl::operator<(const AttributeImpl &AI) const {
8115ffd83dbSDimitry Andric   if (this == &AI)
8125ffd83dbSDimitry Andric     return false;
813fe6060f1SDimitry Andric 
8140b57cec5SDimitry Andric   // This sorts the attributes with Attribute::AttrKinds coming first (sorted
8150b57cec5SDimitry Andric   // relative to their enum value) and then strings.
816fe6060f1SDimitry Andric   if (!isStringAttribute()) {
817fe6060f1SDimitry Andric     if (AI.isStringAttribute())
818fe6060f1SDimitry Andric       return true;
819fe6060f1SDimitry Andric     if (getKindAsEnum() != AI.getKindAsEnum())
8200b57cec5SDimitry Andric       return getKindAsEnum() < AI.getKindAsEnum();
821fe6060f1SDimitry Andric     assert(!AI.isEnumAttribute() && "Non-unique attribute");
822fe6060f1SDimitry Andric     assert(!AI.isTypeAttribute() && "Comparison of types would be unstable");
823*0fca6ea1SDimitry Andric     assert(!AI.isConstantRangeAttribute() && "Unclear how to compare ranges");
824*0fca6ea1SDimitry Andric     assert(!AI.isConstantRangeListAttribute() &&
825*0fca6ea1SDimitry Andric            "Unclear how to compare range list");
826fe6060f1SDimitry Andric     // TODO: Is this actually needed?
827fe6060f1SDimitry Andric     assert(AI.isIntAttribute() && "Only possibility left");
8280b57cec5SDimitry Andric     return getValueAsInt() < AI.getValueAsInt();
8290b57cec5SDimitry Andric   }
8300b57cec5SDimitry Andric 
831fe6060f1SDimitry Andric   if (!AI.isStringAttribute())
832fe6060f1SDimitry Andric     return false;
8330b57cec5SDimitry Andric   if (getKindAsString() == AI.getKindAsString())
8340b57cec5SDimitry Andric     return getValueAsString() < AI.getValueAsString();
8350b57cec5SDimitry Andric   return getKindAsString() < AI.getKindAsString();
8360b57cec5SDimitry Andric }
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8390b57cec5SDimitry Andric // AttributeSet Definition
8400b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8410b57cec5SDimitry Andric 
8420b57cec5SDimitry Andric AttributeSet AttributeSet::get(LLVMContext &C, const AttrBuilder &B) {
8430b57cec5SDimitry Andric   return AttributeSet(AttributeSetNode::get(C, B));
8440b57cec5SDimitry Andric }
8450b57cec5SDimitry Andric 
8460b57cec5SDimitry Andric AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef<Attribute> Attrs) {
8470b57cec5SDimitry Andric   return AttributeSet(AttributeSetNode::get(C, Attrs));
8480b57cec5SDimitry Andric }
8490b57cec5SDimitry Andric 
8500b57cec5SDimitry Andric AttributeSet AttributeSet::addAttribute(LLVMContext &C,
8510b57cec5SDimitry Andric                                         Attribute::AttrKind Kind) const {
8520b57cec5SDimitry Andric   if (hasAttribute(Kind)) return *this;
85304eeddc0SDimitry Andric   AttrBuilder B(C);
8540b57cec5SDimitry Andric   B.addAttribute(Kind);
8550b57cec5SDimitry Andric   return addAttributes(C, AttributeSet::get(C, B));
8560b57cec5SDimitry Andric }
8570b57cec5SDimitry Andric 
8580b57cec5SDimitry Andric AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind,
8590b57cec5SDimitry Andric                                         StringRef Value) const {
86004eeddc0SDimitry Andric   AttrBuilder B(C);
8610b57cec5SDimitry Andric   B.addAttribute(Kind, Value);
8620b57cec5SDimitry Andric   return addAttributes(C, AttributeSet::get(C, B));
8630b57cec5SDimitry Andric }
8640b57cec5SDimitry Andric 
8650b57cec5SDimitry Andric AttributeSet AttributeSet::addAttributes(LLVMContext &C,
8660b57cec5SDimitry Andric                                          const AttributeSet AS) const {
8670b57cec5SDimitry Andric   if (!hasAttributes())
8680b57cec5SDimitry Andric     return AS;
8690b57cec5SDimitry Andric 
8700b57cec5SDimitry Andric   if (!AS.hasAttributes())
8710b57cec5SDimitry Andric     return *this;
8720b57cec5SDimitry Andric 
87304eeddc0SDimitry Andric   AttrBuilder B(C, *this);
87404eeddc0SDimitry Andric   B.merge(AttrBuilder(C, AS));
8750b57cec5SDimitry Andric   return get(C, B);
8760b57cec5SDimitry Andric }
8770b57cec5SDimitry Andric 
8780b57cec5SDimitry Andric AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
8790b57cec5SDimitry Andric                                              Attribute::AttrKind Kind) const {
8800b57cec5SDimitry Andric   if (!hasAttribute(Kind)) return *this;
88104eeddc0SDimitry Andric   AttrBuilder B(C, *this);
8820b57cec5SDimitry Andric   B.removeAttribute(Kind);
8830b57cec5SDimitry Andric   return get(C, B);
8840b57cec5SDimitry Andric }
8850b57cec5SDimitry Andric 
8860b57cec5SDimitry Andric AttributeSet AttributeSet::removeAttribute(LLVMContext &C,
8870b57cec5SDimitry Andric                                              StringRef Kind) const {
8880b57cec5SDimitry Andric   if (!hasAttribute(Kind)) return *this;
88904eeddc0SDimitry Andric   AttrBuilder B(C, *this);
8900b57cec5SDimitry Andric   B.removeAttribute(Kind);
8910b57cec5SDimitry Andric   return get(C, B);
8920b57cec5SDimitry Andric }
8930b57cec5SDimitry Andric 
8940b57cec5SDimitry Andric AttributeSet AttributeSet::removeAttributes(LLVMContext &C,
89504eeddc0SDimitry Andric                                             const AttributeMask &Attrs) const {
89604eeddc0SDimitry Andric   AttrBuilder B(C, *this);
897fe6060f1SDimitry Andric   // If there is nothing to remove, directly return the original set.
898fe6060f1SDimitry Andric   if (!B.overlaps(Attrs))
899fe6060f1SDimitry Andric     return *this;
900fe6060f1SDimitry Andric 
9010b57cec5SDimitry Andric   B.remove(Attrs);
9020b57cec5SDimitry Andric   return get(C, B);
9030b57cec5SDimitry Andric }
9040b57cec5SDimitry Andric 
9050b57cec5SDimitry Andric unsigned AttributeSet::getNumAttributes() const {
9060b57cec5SDimitry Andric   return SetNode ? SetNode->getNumAttributes() : 0;
9070b57cec5SDimitry Andric }
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric bool AttributeSet::hasAttribute(Attribute::AttrKind Kind) const {
9100b57cec5SDimitry Andric   return SetNode ? SetNode->hasAttribute(Kind) : false;
9110b57cec5SDimitry Andric }
9120b57cec5SDimitry Andric 
9130b57cec5SDimitry Andric bool AttributeSet::hasAttribute(StringRef Kind) const {
9140b57cec5SDimitry Andric   return SetNode ? SetNode->hasAttribute(Kind) : false;
9150b57cec5SDimitry Andric }
9160b57cec5SDimitry Andric 
9170b57cec5SDimitry Andric Attribute AttributeSet::getAttribute(Attribute::AttrKind Kind) const {
9180b57cec5SDimitry Andric   return SetNode ? SetNode->getAttribute(Kind) : Attribute();
9190b57cec5SDimitry Andric }
9200b57cec5SDimitry Andric 
9210b57cec5SDimitry Andric Attribute AttributeSet::getAttribute(StringRef Kind) const {
9220b57cec5SDimitry Andric   return SetNode ? SetNode->getAttribute(Kind) : Attribute();
9230b57cec5SDimitry Andric }
9240b57cec5SDimitry Andric 
9258bcb0991SDimitry Andric MaybeAlign AttributeSet::getAlignment() const {
926bdd1243dSDimitry Andric   return SetNode ? SetNode->getAlignment() : std::nullopt;
9270b57cec5SDimitry Andric }
9280b57cec5SDimitry Andric 
9298bcb0991SDimitry Andric MaybeAlign AttributeSet::getStackAlignment() const {
930bdd1243dSDimitry Andric   return SetNode ? SetNode->getStackAlignment() : std::nullopt;
9310b57cec5SDimitry Andric }
9320b57cec5SDimitry Andric 
9330b57cec5SDimitry Andric uint64_t AttributeSet::getDereferenceableBytes() const {
9340b57cec5SDimitry Andric   return SetNode ? SetNode->getDereferenceableBytes() : 0;
9350b57cec5SDimitry Andric }
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric uint64_t AttributeSet::getDereferenceableOrNullBytes() const {
9380b57cec5SDimitry Andric   return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0;
9390b57cec5SDimitry Andric }
9400b57cec5SDimitry Andric 
941e8d8bef9SDimitry Andric Type *AttributeSet::getByRefType() const {
942fe6060f1SDimitry Andric   return SetNode ? SetNode->getAttributeType(Attribute::ByRef) : nullptr;
943e8d8bef9SDimitry Andric }
944e8d8bef9SDimitry Andric 
9450b57cec5SDimitry Andric Type *AttributeSet::getByValType() const {
946fe6060f1SDimitry Andric   return SetNode ? SetNode->getAttributeType(Attribute::ByVal) : nullptr;
9470b57cec5SDimitry Andric }
9480b57cec5SDimitry Andric 
949e8d8bef9SDimitry Andric Type *AttributeSet::getStructRetType() const {
950fe6060f1SDimitry Andric   return SetNode ? SetNode->getAttributeType(Attribute::StructRet) : nullptr;
951e8d8bef9SDimitry Andric }
952e8d8bef9SDimitry Andric 
9535ffd83dbSDimitry Andric Type *AttributeSet::getPreallocatedType() const {
954fe6060f1SDimitry Andric   return SetNode ? SetNode->getAttributeType(Attribute::Preallocated) : nullptr;
955fe6060f1SDimitry Andric }
956fe6060f1SDimitry Andric 
957fe6060f1SDimitry Andric Type *AttributeSet::getInAllocaType() const {
958fe6060f1SDimitry Andric   return SetNode ? SetNode->getAttributeType(Attribute::InAlloca) : nullptr;
959fe6060f1SDimitry Andric }
960fe6060f1SDimitry Andric 
961fe6060f1SDimitry Andric Type *AttributeSet::getElementType() const {
962fe6060f1SDimitry Andric   return SetNode ? SetNode->getAttributeType(Attribute::ElementType) : nullptr;
9635ffd83dbSDimitry Andric }
9645ffd83dbSDimitry Andric 
965bdd1243dSDimitry Andric std::optional<std::pair<unsigned, std::optional<unsigned>>>
966bdd1243dSDimitry Andric AttributeSet::getAllocSizeArgs() const {
967bdd1243dSDimitry Andric   if (SetNode)
968bdd1243dSDimitry Andric     return SetNode->getAllocSizeArgs();
969bdd1243dSDimitry Andric   return std::nullopt;
9700b57cec5SDimitry Andric }
9710b57cec5SDimitry Andric 
9720eae32dcSDimitry Andric unsigned AttributeSet::getVScaleRangeMin() const {
9730eae32dcSDimitry Andric   return SetNode ? SetNode->getVScaleRangeMin() : 1;
9740eae32dcSDimitry Andric }
9750eae32dcSDimitry Andric 
976bdd1243dSDimitry Andric std::optional<unsigned> AttributeSet::getVScaleRangeMax() const {
977bdd1243dSDimitry Andric   return SetNode ? SetNode->getVScaleRangeMax() : std::nullopt;
978fe6060f1SDimitry Andric }
979fe6060f1SDimitry Andric 
98081ad6265SDimitry Andric UWTableKind AttributeSet::getUWTableKind() const {
98181ad6265SDimitry Andric   return SetNode ? SetNode->getUWTableKind() : UWTableKind::None;
98281ad6265SDimitry Andric }
98381ad6265SDimitry Andric 
98481ad6265SDimitry Andric AllocFnKind AttributeSet::getAllocKind() const {
98581ad6265SDimitry Andric   return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown;
98681ad6265SDimitry Andric }
98781ad6265SDimitry Andric 
988bdd1243dSDimitry Andric MemoryEffects AttributeSet::getMemoryEffects() const {
989bdd1243dSDimitry Andric   return SetNode ? SetNode->getMemoryEffects() : MemoryEffects::unknown();
990bdd1243dSDimitry Andric }
991bdd1243dSDimitry Andric 
99206c3fb27SDimitry Andric FPClassTest AttributeSet::getNoFPClass() const {
99306c3fb27SDimitry Andric   return SetNode ? SetNode->getNoFPClass() : fcNone;
99406c3fb27SDimitry Andric }
99506c3fb27SDimitry Andric 
9960b57cec5SDimitry Andric std::string AttributeSet::getAsString(bool InAttrGrp) const {
9970b57cec5SDimitry Andric   return SetNode ? SetNode->getAsString(InAttrGrp) : "";
9980b57cec5SDimitry Andric }
9990b57cec5SDimitry Andric 
1000fe6060f1SDimitry Andric bool AttributeSet::hasParentContext(LLVMContext &C) const {
1001fe6060f1SDimitry Andric   assert(hasAttributes() && "empty AttributeSet doesn't refer to any context");
1002fe6060f1SDimitry Andric   FoldingSetNodeID ID;
1003fe6060f1SDimitry Andric   SetNode->Profile(ID);
1004fe6060f1SDimitry Andric   void *Unused;
1005fe6060f1SDimitry Andric   return C.pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, Unused) == SetNode;
1006fe6060f1SDimitry Andric }
1007fe6060f1SDimitry Andric 
10080b57cec5SDimitry Andric AttributeSet::iterator AttributeSet::begin() const {
10090b57cec5SDimitry Andric   return SetNode ? SetNode->begin() : nullptr;
10100b57cec5SDimitry Andric }
10110b57cec5SDimitry Andric 
10120b57cec5SDimitry Andric AttributeSet::iterator AttributeSet::end() const {
10130b57cec5SDimitry Andric   return SetNode ? SetNode->end() : nullptr;
10140b57cec5SDimitry Andric }
10150b57cec5SDimitry Andric 
10160b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
10170b57cec5SDimitry Andric LLVM_DUMP_METHOD void AttributeSet::dump() const {
10180b57cec5SDimitry Andric   dbgs() << "AS =\n";
10190b57cec5SDimitry Andric     dbgs() << "  { ";
10200b57cec5SDimitry Andric     dbgs() << getAsString(true) << " }\n";
10210b57cec5SDimitry Andric }
10220b57cec5SDimitry Andric #endif
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
10250b57cec5SDimitry Andric // AttributeSetNode Definition
10260b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
10270b57cec5SDimitry Andric 
10280b57cec5SDimitry Andric AttributeSetNode::AttributeSetNode(ArrayRef<Attribute> Attrs)
10290b57cec5SDimitry Andric     : NumAttrs(Attrs.size()) {
10300b57cec5SDimitry Andric   // There's memory after the node where we can store the entries in.
10310b57cec5SDimitry Andric   llvm::copy(Attrs, getTrailingObjects<Attribute>());
10320b57cec5SDimitry Andric 
1033480093f4SDimitry Andric   for (const auto &I : *this) {
10345ffd83dbSDimitry Andric     if (I.isStringAttribute())
10355ffd83dbSDimitry Andric       StringAttrs.insert({ I.getKindAsString(), I });
10365ffd83dbSDimitry Andric     else
10375ffd83dbSDimitry Andric       AvailableAttrs.addAttribute(I.getKindAsEnum());
10380b57cec5SDimitry Andric   }
10390b57cec5SDimitry Andric }
10400b57cec5SDimitry Andric 
10410b57cec5SDimitry Andric AttributeSetNode *AttributeSetNode::get(LLVMContext &C,
10420b57cec5SDimitry Andric                                         ArrayRef<Attribute> Attrs) {
10435ffd83dbSDimitry Andric   SmallVector<Attribute, 8> SortedAttrs(Attrs.begin(), Attrs.end());
10445ffd83dbSDimitry Andric   llvm::sort(SortedAttrs);
10455ffd83dbSDimitry Andric   return getSorted(C, SortedAttrs);
10465ffd83dbSDimitry Andric }
10475ffd83dbSDimitry Andric 
10485ffd83dbSDimitry Andric AttributeSetNode *AttributeSetNode::getSorted(LLVMContext &C,
10495ffd83dbSDimitry Andric                                               ArrayRef<Attribute> SortedAttrs) {
10505ffd83dbSDimitry Andric   if (SortedAttrs.empty())
10510b57cec5SDimitry Andric     return nullptr;
10520b57cec5SDimitry Andric 
10535ffd83dbSDimitry Andric   // Build a key to look up the existing attributes.
10540b57cec5SDimitry Andric   LLVMContextImpl *pImpl = C.pImpl;
10550b57cec5SDimitry Andric   FoldingSetNodeID ID;
10560b57cec5SDimitry Andric 
10575ffd83dbSDimitry Andric   assert(llvm::is_sorted(SortedAttrs) && "Expected sorted attributes!");
1058480093f4SDimitry Andric   for (const auto &Attr : SortedAttrs)
10590b57cec5SDimitry Andric     Attr.Profile(ID);
10600b57cec5SDimitry Andric 
10610b57cec5SDimitry Andric   void *InsertPoint;
10620b57cec5SDimitry Andric   AttributeSetNode *PA =
10630b57cec5SDimitry Andric     pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, InsertPoint);
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric   // If we didn't find any existing attributes of the same shape then create a
10660b57cec5SDimitry Andric   // new one and insert it.
10670b57cec5SDimitry Andric   if (!PA) {
10680b57cec5SDimitry Andric     // Coallocate entries after the AttributeSetNode itself.
10690b57cec5SDimitry Andric     void *Mem = ::operator new(totalSizeToAlloc<Attribute>(SortedAttrs.size()));
10700b57cec5SDimitry Andric     PA = new (Mem) AttributeSetNode(SortedAttrs);
10710b57cec5SDimitry Andric     pImpl->AttrsSetNodes.InsertNode(PA, InsertPoint);
10720b57cec5SDimitry Andric   }
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric   // Return the AttributeSetNode that we found or created.
10750b57cec5SDimitry Andric   return PA;
10760b57cec5SDimitry Andric }
10770b57cec5SDimitry Andric 
10780b57cec5SDimitry Andric AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) {
107904eeddc0SDimitry Andric   return getSorted(C, B.attrs());
10800b57cec5SDimitry Andric }
10810b57cec5SDimitry Andric 
10820b57cec5SDimitry Andric bool AttributeSetNode::hasAttribute(StringRef Kind) const {
10835ffd83dbSDimitry Andric   return StringAttrs.count(Kind);
10845ffd83dbSDimitry Andric }
10855ffd83dbSDimitry Andric 
1086bdd1243dSDimitry Andric std::optional<Attribute>
10875ffd83dbSDimitry Andric AttributeSetNode::findEnumAttribute(Attribute::AttrKind Kind) const {
10885ffd83dbSDimitry Andric   // Do a quick presence check.
10895ffd83dbSDimitry Andric   if (!hasAttribute(Kind))
1090bdd1243dSDimitry Andric     return std::nullopt;
10915ffd83dbSDimitry Andric 
10925ffd83dbSDimitry Andric   // Attributes in a set are sorted by enum value, followed by string
10935ffd83dbSDimitry Andric   // attributes. Binary search the one we want.
10945ffd83dbSDimitry Andric   const Attribute *I =
10955ffd83dbSDimitry Andric       std::lower_bound(begin(), end() - StringAttrs.size(), Kind,
10965ffd83dbSDimitry Andric                        [](Attribute A, Attribute::AttrKind Kind) {
10975ffd83dbSDimitry Andric                          return A.getKindAsEnum() < Kind;
10985ffd83dbSDimitry Andric                        });
10995ffd83dbSDimitry Andric   assert(I != end() && I->hasAttribute(Kind) && "Presence check failed?");
11005ffd83dbSDimitry Andric   return *I;
11010b57cec5SDimitry Andric }
11020b57cec5SDimitry Andric 
11030b57cec5SDimitry Andric Attribute AttributeSetNode::getAttribute(Attribute::AttrKind Kind) const {
11045ffd83dbSDimitry Andric   if (auto A = findEnumAttribute(Kind))
11055ffd83dbSDimitry Andric     return *A;
11060b57cec5SDimitry Andric   return {};
11070b57cec5SDimitry Andric }
11080b57cec5SDimitry Andric 
11090b57cec5SDimitry Andric Attribute AttributeSetNode::getAttribute(StringRef Kind) const {
11105ffd83dbSDimitry Andric   return StringAttrs.lookup(Kind);
11110b57cec5SDimitry Andric }
11120b57cec5SDimitry Andric 
11138bcb0991SDimitry Andric MaybeAlign AttributeSetNode::getAlignment() const {
11145ffd83dbSDimitry Andric   if (auto A = findEnumAttribute(Attribute::Alignment))
11155ffd83dbSDimitry Andric     return A->getAlignment();
1116bdd1243dSDimitry Andric   return std::nullopt;
11170b57cec5SDimitry Andric }
11180b57cec5SDimitry Andric 
11198bcb0991SDimitry Andric MaybeAlign AttributeSetNode::getStackAlignment() const {
11205ffd83dbSDimitry Andric   if (auto A = findEnumAttribute(Attribute::StackAlignment))
11215ffd83dbSDimitry Andric     return A->getStackAlignment();
1122bdd1243dSDimitry Andric   return std::nullopt;
11230b57cec5SDimitry Andric }
11240b57cec5SDimitry Andric 
1125fe6060f1SDimitry Andric Type *AttributeSetNode::getAttributeType(Attribute::AttrKind Kind) const {
1126fe6060f1SDimitry Andric   if (auto A = findEnumAttribute(Kind))
1127e8d8bef9SDimitry Andric     return A->getValueAsType();
1128e8d8bef9SDimitry Andric   return nullptr;
11290b57cec5SDimitry Andric }
11300b57cec5SDimitry Andric 
11310b57cec5SDimitry Andric uint64_t AttributeSetNode::getDereferenceableBytes() const {
11325ffd83dbSDimitry Andric   if (auto A = findEnumAttribute(Attribute::Dereferenceable))
11335ffd83dbSDimitry Andric     return A->getDereferenceableBytes();
11340b57cec5SDimitry Andric   return 0;
11350b57cec5SDimitry Andric }
11360b57cec5SDimitry Andric 
11370b57cec5SDimitry Andric uint64_t AttributeSetNode::getDereferenceableOrNullBytes() const {
11385ffd83dbSDimitry Andric   if (auto A = findEnumAttribute(Attribute::DereferenceableOrNull))
11395ffd83dbSDimitry Andric     return A->getDereferenceableOrNullBytes();
11400b57cec5SDimitry Andric   return 0;
11410b57cec5SDimitry Andric }
11420b57cec5SDimitry Andric 
1143bdd1243dSDimitry Andric std::optional<std::pair<unsigned, std::optional<unsigned>>>
11440b57cec5SDimitry Andric AttributeSetNode::getAllocSizeArgs() const {
11455ffd83dbSDimitry Andric   if (auto A = findEnumAttribute(Attribute::AllocSize))
11465ffd83dbSDimitry Andric     return A->getAllocSizeArgs();
1147bdd1243dSDimitry Andric   return std::nullopt;
11480b57cec5SDimitry Andric }
11490b57cec5SDimitry Andric 
11500eae32dcSDimitry Andric unsigned AttributeSetNode::getVScaleRangeMin() const {
1151fe6060f1SDimitry Andric   if (auto A = findEnumAttribute(Attribute::VScaleRange))
11520eae32dcSDimitry Andric     return A->getVScaleRangeMin();
11530eae32dcSDimitry Andric   return 1;
11540eae32dcSDimitry Andric }
11550eae32dcSDimitry Andric 
1156bdd1243dSDimitry Andric std::optional<unsigned> AttributeSetNode::getVScaleRangeMax() const {
11570eae32dcSDimitry Andric   if (auto A = findEnumAttribute(Attribute::VScaleRange))
11580eae32dcSDimitry Andric     return A->getVScaleRangeMax();
1159bdd1243dSDimitry Andric   return std::nullopt;
1160fe6060f1SDimitry Andric }
1161fe6060f1SDimitry Andric 
116281ad6265SDimitry Andric UWTableKind AttributeSetNode::getUWTableKind() const {
116381ad6265SDimitry Andric   if (auto A = findEnumAttribute(Attribute::UWTable))
116481ad6265SDimitry Andric     return A->getUWTableKind();
116581ad6265SDimitry Andric   return UWTableKind::None;
116681ad6265SDimitry Andric }
116781ad6265SDimitry Andric 
116881ad6265SDimitry Andric AllocFnKind AttributeSetNode::getAllocKind() const {
116981ad6265SDimitry Andric   if (auto A = findEnumAttribute(Attribute::AllocKind))
117081ad6265SDimitry Andric     return A->getAllocKind();
117181ad6265SDimitry Andric   return AllocFnKind::Unknown;
117281ad6265SDimitry Andric }
117381ad6265SDimitry Andric 
1174bdd1243dSDimitry Andric MemoryEffects AttributeSetNode::getMemoryEffects() const {
1175bdd1243dSDimitry Andric   if (auto A = findEnumAttribute(Attribute::Memory))
1176bdd1243dSDimitry Andric     return A->getMemoryEffects();
1177bdd1243dSDimitry Andric   return MemoryEffects::unknown();
1178bdd1243dSDimitry Andric }
1179bdd1243dSDimitry Andric 
118006c3fb27SDimitry Andric FPClassTest AttributeSetNode::getNoFPClass() const {
118106c3fb27SDimitry Andric   if (auto A = findEnumAttribute(Attribute::NoFPClass))
118206c3fb27SDimitry Andric     return A->getNoFPClass();
118306c3fb27SDimitry Andric   return fcNone;
118406c3fb27SDimitry Andric }
118506c3fb27SDimitry Andric 
11860b57cec5SDimitry Andric std::string AttributeSetNode::getAsString(bool InAttrGrp) const {
11870b57cec5SDimitry Andric   std::string Str;
11880b57cec5SDimitry Andric   for (iterator I = begin(), E = end(); I != E; ++I) {
11890b57cec5SDimitry Andric     if (I != begin())
11900b57cec5SDimitry Andric       Str += ' ';
11910b57cec5SDimitry Andric     Str += I->getAsString(InAttrGrp);
11920b57cec5SDimitry Andric   }
11930b57cec5SDimitry Andric   return Str;
11940b57cec5SDimitry Andric }
11950b57cec5SDimitry Andric 
11960b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11970b57cec5SDimitry Andric // AttributeListImpl Definition
11980b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11990b57cec5SDimitry Andric 
12000b57cec5SDimitry Andric /// Map from AttributeList index to the internal array index. Adding one happens
12015ffd83dbSDimitry Andric /// to work, because -1 wraps around to 0.
1202e8d8bef9SDimitry Andric static unsigned attrIdxToArrayIdx(unsigned Index) {
12035ffd83dbSDimitry Andric   return Index + 1;
12040b57cec5SDimitry Andric }
12050b57cec5SDimitry Andric 
12065ffd83dbSDimitry Andric AttributeListImpl::AttributeListImpl(ArrayRef<AttributeSet> Sets)
12075ffd83dbSDimitry Andric     : NumAttrSets(Sets.size()) {
12080b57cec5SDimitry Andric   assert(!Sets.empty() && "pointless AttributeListImpl");
12090b57cec5SDimitry Andric 
12100b57cec5SDimitry Andric   // There's memory after the node where we can store the entries in.
12110b57cec5SDimitry Andric   llvm::copy(Sets, getTrailingObjects<AttributeSet>());
12120b57cec5SDimitry Andric 
12135ffd83dbSDimitry Andric   // Initialize AvailableFunctionAttrs and AvailableSomewhereAttrs
12145ffd83dbSDimitry Andric   // summary bitsets.
1215e8d8bef9SDimitry Andric   for (const auto &I : Sets[attrIdxToArrayIdx(AttributeList::FunctionIndex)])
12165ffd83dbSDimitry Andric     if (!I.isStringAttribute())
12175ffd83dbSDimitry Andric       AvailableFunctionAttrs.addAttribute(I.getKindAsEnum());
12185ffd83dbSDimitry Andric 
12195ffd83dbSDimitry Andric   for (const auto &Set : Sets)
12205ffd83dbSDimitry Andric     for (const auto &I : Set)
12215ffd83dbSDimitry Andric       if (!I.isStringAttribute())
12225ffd83dbSDimitry Andric         AvailableSomewhereAttrs.addAttribute(I.getKindAsEnum());
12230b57cec5SDimitry Andric }
12240b57cec5SDimitry Andric 
12250b57cec5SDimitry Andric void AttributeListImpl::Profile(FoldingSetNodeID &ID) const {
1226bdd1243dSDimitry Andric   Profile(ID, ArrayRef(begin(), end()));
12270b57cec5SDimitry Andric }
12280b57cec5SDimitry Andric 
12290b57cec5SDimitry Andric void AttributeListImpl::Profile(FoldingSetNodeID &ID,
12300b57cec5SDimitry Andric                                 ArrayRef<AttributeSet> Sets) {
12310b57cec5SDimitry Andric   for (const auto &Set : Sets)
12320b57cec5SDimitry Andric     ID.AddPointer(Set.SetNode);
12330b57cec5SDimitry Andric }
12340b57cec5SDimitry Andric 
12355ffd83dbSDimitry Andric bool AttributeListImpl::hasAttrSomewhere(Attribute::AttrKind Kind,
12365ffd83dbSDimitry Andric                                         unsigned *Index) const {
12375ffd83dbSDimitry Andric   if (!AvailableSomewhereAttrs.hasAttribute(Kind))
12385ffd83dbSDimitry Andric     return false;
12395ffd83dbSDimitry Andric 
12405ffd83dbSDimitry Andric   if (Index) {
12415ffd83dbSDimitry Andric     for (unsigned I = 0, E = NumAttrSets; I != E; ++I) {
12425ffd83dbSDimitry Andric       if (begin()[I].hasAttribute(Kind)) {
12435ffd83dbSDimitry Andric         *Index = I - 1;
12445ffd83dbSDimitry Andric         break;
12455ffd83dbSDimitry Andric       }
12465ffd83dbSDimitry Andric     }
12475ffd83dbSDimitry Andric   }
12485ffd83dbSDimitry Andric 
12495ffd83dbSDimitry Andric   return true;
12505ffd83dbSDimitry Andric }
12515ffd83dbSDimitry Andric 
12525ffd83dbSDimitry Andric 
12530b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
12540b57cec5SDimitry Andric LLVM_DUMP_METHOD void AttributeListImpl::dump() const {
12550b57cec5SDimitry Andric   AttributeList(const_cast<AttributeListImpl *>(this)).dump();
12560b57cec5SDimitry Andric }
12570b57cec5SDimitry Andric #endif
12580b57cec5SDimitry Andric 
12590b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12600b57cec5SDimitry Andric // AttributeList Construction and Mutation Methods
12610b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric AttributeList AttributeList::getImpl(LLVMContext &C,
12640b57cec5SDimitry Andric                                      ArrayRef<AttributeSet> AttrSets) {
12650b57cec5SDimitry Andric   assert(!AttrSets.empty() && "pointless AttributeListImpl");
12660b57cec5SDimitry Andric 
12670b57cec5SDimitry Andric   LLVMContextImpl *pImpl = C.pImpl;
12680b57cec5SDimitry Andric   FoldingSetNodeID ID;
12690b57cec5SDimitry Andric   AttributeListImpl::Profile(ID, AttrSets);
12700b57cec5SDimitry Andric 
12710b57cec5SDimitry Andric   void *InsertPoint;
12720b57cec5SDimitry Andric   AttributeListImpl *PA =
12730b57cec5SDimitry Andric       pImpl->AttrsLists.FindNodeOrInsertPos(ID, InsertPoint);
12740b57cec5SDimitry Andric 
12750b57cec5SDimitry Andric   // If we didn't find any existing attributes of the same shape then
12760b57cec5SDimitry Andric   // create a new one and insert it.
12770b57cec5SDimitry Andric   if (!PA) {
12780b57cec5SDimitry Andric     // Coallocate entries after the AttributeListImpl itself.
12795ffd83dbSDimitry Andric     void *Mem = pImpl->Alloc.Allocate(
12805ffd83dbSDimitry Andric         AttributeListImpl::totalSizeToAlloc<AttributeSet>(AttrSets.size()),
12815ffd83dbSDimitry Andric         alignof(AttributeListImpl));
12825ffd83dbSDimitry Andric     PA = new (Mem) AttributeListImpl(AttrSets);
12830b57cec5SDimitry Andric     pImpl->AttrsLists.InsertNode(PA, InsertPoint);
12840b57cec5SDimitry Andric   }
12850b57cec5SDimitry Andric 
12860b57cec5SDimitry Andric   // Return the AttributesList that we found or created.
12870b57cec5SDimitry Andric   return AttributeList(PA);
12880b57cec5SDimitry Andric }
12890b57cec5SDimitry Andric 
12900b57cec5SDimitry Andric AttributeList
12910b57cec5SDimitry Andric AttributeList::get(LLVMContext &C,
12920b57cec5SDimitry Andric                    ArrayRef<std::pair<unsigned, Attribute>> Attrs) {
12930b57cec5SDimitry Andric   // If there are no attributes then return a null AttributesList pointer.
12940b57cec5SDimitry Andric   if (Attrs.empty())
12950b57cec5SDimitry Andric     return {};
12960b57cec5SDimitry Andric 
129781ad6265SDimitry Andric   assert(llvm::is_sorted(Attrs, llvm::less_first()) &&
12985ffd83dbSDimitry Andric          "Misordered Attributes list!");
1299e8d8bef9SDimitry Andric   assert(llvm::all_of(Attrs,
13000b57cec5SDimitry Andric                       [](const std::pair<unsigned, Attribute> &Pair) {
1301e8d8bef9SDimitry Andric                         return Pair.second.isValid();
13020b57cec5SDimitry Andric                       }) &&
13030b57cec5SDimitry Andric          "Pointless attribute!");
13040b57cec5SDimitry Andric 
13050b57cec5SDimitry Andric   // Create a vector if (unsigned, AttributeSetNode*) pairs from the attributes
13060b57cec5SDimitry Andric   // list.
13070b57cec5SDimitry Andric   SmallVector<std::pair<unsigned, AttributeSet>, 8> AttrPairVec;
13080b57cec5SDimitry Andric   for (ArrayRef<std::pair<unsigned, Attribute>>::iterator I = Attrs.begin(),
13090b57cec5SDimitry Andric          E = Attrs.end(); I != E; ) {
13100b57cec5SDimitry Andric     unsigned Index = I->first;
13110b57cec5SDimitry Andric     SmallVector<Attribute, 4> AttrVec;
13120b57cec5SDimitry Andric     while (I != E && I->first == Index) {
13130b57cec5SDimitry Andric       AttrVec.push_back(I->second);
13140b57cec5SDimitry Andric       ++I;
13150b57cec5SDimitry Andric     }
13160b57cec5SDimitry Andric 
13170b57cec5SDimitry Andric     AttrPairVec.emplace_back(Index, AttributeSet::get(C, AttrVec));
13180b57cec5SDimitry Andric   }
13190b57cec5SDimitry Andric 
13200b57cec5SDimitry Andric   return get(C, AttrPairVec);
13210b57cec5SDimitry Andric }
13220b57cec5SDimitry Andric 
13230b57cec5SDimitry Andric AttributeList
13240b57cec5SDimitry Andric AttributeList::get(LLVMContext &C,
13250b57cec5SDimitry Andric                    ArrayRef<std::pair<unsigned, AttributeSet>> Attrs) {
13260b57cec5SDimitry Andric   // If there are no attributes then return a null AttributesList pointer.
13270b57cec5SDimitry Andric   if (Attrs.empty())
13280b57cec5SDimitry Andric     return {};
13290b57cec5SDimitry Andric 
133081ad6265SDimitry Andric   assert(llvm::is_sorted(Attrs, llvm::less_first()) &&
13310b57cec5SDimitry Andric          "Misordered Attributes list!");
13320b57cec5SDimitry Andric   assert(llvm::none_of(Attrs,
13330b57cec5SDimitry Andric                        [](const std::pair<unsigned, AttributeSet> &Pair) {
13340b57cec5SDimitry Andric                          return !Pair.second.hasAttributes();
13350b57cec5SDimitry Andric                        }) &&
13360b57cec5SDimitry Andric          "Pointless attribute!");
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric   unsigned MaxIndex = Attrs.back().first;
13390b57cec5SDimitry Andric   // If the MaxIndex is FunctionIndex and there are other indices in front
13400b57cec5SDimitry Andric   // of it, we need to use the largest of those to get the right size.
13410b57cec5SDimitry Andric   if (MaxIndex == FunctionIndex && Attrs.size() > 1)
13420b57cec5SDimitry Andric     MaxIndex = Attrs[Attrs.size() - 2].first;
13430b57cec5SDimitry Andric 
13440b57cec5SDimitry Andric   SmallVector<AttributeSet, 4> AttrVec(attrIdxToArrayIdx(MaxIndex) + 1);
1345480093f4SDimitry Andric   for (const auto &Pair : Attrs)
13460b57cec5SDimitry Andric     AttrVec[attrIdxToArrayIdx(Pair.first)] = Pair.second;
13470b57cec5SDimitry Andric 
13480b57cec5SDimitry Andric   return getImpl(C, AttrVec);
13490b57cec5SDimitry Andric }
13500b57cec5SDimitry Andric 
13510b57cec5SDimitry Andric AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs,
13520b57cec5SDimitry Andric                                  AttributeSet RetAttrs,
13530b57cec5SDimitry Andric                                  ArrayRef<AttributeSet> ArgAttrs) {
13540b57cec5SDimitry Andric   // Scan from the end to find the last argument with attributes.  Most
13550b57cec5SDimitry Andric   // arguments don't have attributes, so it's nice if we can have fewer unique
13560b57cec5SDimitry Andric   // AttributeListImpls by dropping empty attribute sets at the end of the list.
13570b57cec5SDimitry Andric   unsigned NumSets = 0;
13580b57cec5SDimitry Andric   for (size_t I = ArgAttrs.size(); I != 0; --I) {
13590b57cec5SDimitry Andric     if (ArgAttrs[I - 1].hasAttributes()) {
13600b57cec5SDimitry Andric       NumSets = I + 2;
13610b57cec5SDimitry Andric       break;
13620b57cec5SDimitry Andric     }
13630b57cec5SDimitry Andric   }
13640b57cec5SDimitry Andric   if (NumSets == 0) {
13650b57cec5SDimitry Andric     // Check function and return attributes if we didn't have argument
13660b57cec5SDimitry Andric     // attributes.
13670b57cec5SDimitry Andric     if (RetAttrs.hasAttributes())
13680b57cec5SDimitry Andric       NumSets = 2;
13690b57cec5SDimitry Andric     else if (FnAttrs.hasAttributes())
13700b57cec5SDimitry Andric       NumSets = 1;
13710b57cec5SDimitry Andric   }
13720b57cec5SDimitry Andric 
13730b57cec5SDimitry Andric   // If all attribute sets were empty, we can use the empty attribute list.
13740b57cec5SDimitry Andric   if (NumSets == 0)
13750b57cec5SDimitry Andric     return {};
13760b57cec5SDimitry Andric 
13770b57cec5SDimitry Andric   SmallVector<AttributeSet, 8> AttrSets;
13780b57cec5SDimitry Andric   AttrSets.reserve(NumSets);
13790b57cec5SDimitry Andric   // If we have any attributes, we always have function attributes.
13800b57cec5SDimitry Andric   AttrSets.push_back(FnAttrs);
13810b57cec5SDimitry Andric   if (NumSets > 1)
13820b57cec5SDimitry Andric     AttrSets.push_back(RetAttrs);
13830b57cec5SDimitry Andric   if (NumSets > 2) {
13840b57cec5SDimitry Andric     // Drop the empty argument attribute sets at the end.
13850b57cec5SDimitry Andric     ArgAttrs = ArgAttrs.take_front(NumSets - 2);
1386e8d8bef9SDimitry Andric     llvm::append_range(AttrSets, ArgAttrs);
13870b57cec5SDimitry Andric   }
13880b57cec5SDimitry Andric 
13890b57cec5SDimitry Andric   return getImpl(C, AttrSets);
13900b57cec5SDimitry Andric }
13910b57cec5SDimitry Andric 
13920b57cec5SDimitry Andric AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
13930eae32dcSDimitry Andric                                  AttributeSet Attrs) {
13940eae32dcSDimitry Andric   if (!Attrs.hasAttributes())
13950b57cec5SDimitry Andric     return {};
13960b57cec5SDimitry Andric   Index = attrIdxToArrayIdx(Index);
13970b57cec5SDimitry Andric   SmallVector<AttributeSet, 8> AttrSets(Index + 1);
13980eae32dcSDimitry Andric   AttrSets[Index] = Attrs;
13990b57cec5SDimitry Andric   return getImpl(C, AttrSets);
14000b57cec5SDimitry Andric }
14010b57cec5SDimitry Andric 
14020b57cec5SDimitry Andric AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
14030eae32dcSDimitry Andric                                  const AttrBuilder &B) {
14040eae32dcSDimitry Andric   return get(C, Index, AttributeSet::get(C, B));
14050eae32dcSDimitry Andric }
14060eae32dcSDimitry Andric 
14070eae32dcSDimitry Andric AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
14080b57cec5SDimitry Andric                                  ArrayRef<Attribute::AttrKind> Kinds) {
14090b57cec5SDimitry Andric   SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;
14100b57cec5SDimitry Andric   for (const auto K : Kinds)
14110b57cec5SDimitry Andric     Attrs.emplace_back(Index, Attribute::get(C, K));
14120b57cec5SDimitry Andric   return get(C, Attrs);
14130b57cec5SDimitry Andric }
14140b57cec5SDimitry Andric 
14150b57cec5SDimitry Andric AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
14165ffd83dbSDimitry Andric                                  ArrayRef<Attribute::AttrKind> Kinds,
14175ffd83dbSDimitry Andric                                  ArrayRef<uint64_t> Values) {
14185ffd83dbSDimitry Andric   assert(Kinds.size() == Values.size() && "Mismatched attribute values.");
14195ffd83dbSDimitry Andric   SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;
14205ffd83dbSDimitry Andric   auto VI = Values.begin();
14215ffd83dbSDimitry Andric   for (const auto K : Kinds)
14225ffd83dbSDimitry Andric     Attrs.emplace_back(Index, Attribute::get(C, K, *VI++));
14235ffd83dbSDimitry Andric   return get(C, Attrs);
14245ffd83dbSDimitry Andric }
14255ffd83dbSDimitry Andric 
14265ffd83dbSDimitry Andric AttributeList AttributeList::get(LLVMContext &C, unsigned Index,
14270b57cec5SDimitry Andric                                  ArrayRef<StringRef> Kinds) {
14280b57cec5SDimitry Andric   SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;
1429480093f4SDimitry Andric   for (const auto &K : Kinds)
14300b57cec5SDimitry Andric     Attrs.emplace_back(Index, Attribute::get(C, K));
14310b57cec5SDimitry Andric   return get(C, Attrs);
14320b57cec5SDimitry Andric }
14330b57cec5SDimitry Andric 
14340b57cec5SDimitry Andric AttributeList AttributeList::get(LLVMContext &C,
14350b57cec5SDimitry Andric                                  ArrayRef<AttributeList> Attrs) {
14360b57cec5SDimitry Andric   if (Attrs.empty())
14370b57cec5SDimitry Andric     return {};
14380b57cec5SDimitry Andric   if (Attrs.size() == 1)
14390b57cec5SDimitry Andric     return Attrs[0];
14400b57cec5SDimitry Andric 
14410b57cec5SDimitry Andric   unsigned MaxSize = 0;
1442480093f4SDimitry Andric   for (const auto &List : Attrs)
14430b57cec5SDimitry Andric     MaxSize = std::max(MaxSize, List.getNumAttrSets());
14440b57cec5SDimitry Andric 
14450b57cec5SDimitry Andric   // If every list was empty, there is no point in merging the lists.
14460b57cec5SDimitry Andric   if (MaxSize == 0)
14470b57cec5SDimitry Andric     return {};
14480b57cec5SDimitry Andric 
14490b57cec5SDimitry Andric   SmallVector<AttributeSet, 8> NewAttrSets(MaxSize);
14500b57cec5SDimitry Andric   for (unsigned I = 0; I < MaxSize; ++I) {
145104eeddc0SDimitry Andric     AttrBuilder CurBuilder(C);
1452480093f4SDimitry Andric     for (const auto &List : Attrs)
145304eeddc0SDimitry Andric       CurBuilder.merge(AttrBuilder(C, List.getAttributes(I - 1)));
14540b57cec5SDimitry Andric     NewAttrSets[I] = AttributeSet::get(C, CurBuilder);
14550b57cec5SDimitry Andric   }
14560b57cec5SDimitry Andric 
14570b57cec5SDimitry Andric   return getImpl(C, NewAttrSets);
14580b57cec5SDimitry Andric }
14590b57cec5SDimitry Andric 
1460349cc55cSDimitry Andric AttributeList
1461349cc55cSDimitry Andric AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,
14620b57cec5SDimitry Andric                                    Attribute::AttrKind Kind) const {
1463e8d8bef9SDimitry Andric   AttributeSet Attrs = getAttributes(Index);
1464bdd1243dSDimitry Andric   if (Attrs.hasAttribute(Kind))
1465bdd1243dSDimitry Andric     return *this;
1466e8d8bef9SDimitry Andric   // TODO: Insert at correct position and avoid sort.
1467e8d8bef9SDimitry Andric   SmallVector<Attribute, 8> NewAttrs(Attrs.begin(), Attrs.end());
1468e8d8bef9SDimitry Andric   NewAttrs.push_back(Attribute::get(C, Kind));
1469349cc55cSDimitry Andric   return setAttributesAtIndex(C, Index, AttributeSet::get(C, NewAttrs));
14700b57cec5SDimitry Andric }
14710b57cec5SDimitry Andric 
1472349cc55cSDimitry Andric AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,
14730b57cec5SDimitry Andric                                                  StringRef Kind,
14740b57cec5SDimitry Andric                                                  StringRef Value) const {
147504eeddc0SDimitry Andric   AttrBuilder B(C);
14760b57cec5SDimitry Andric   B.addAttribute(Kind, Value);
1477349cc55cSDimitry Andric   return addAttributesAtIndex(C, Index, B);
14780b57cec5SDimitry Andric }
14790b57cec5SDimitry Andric 
1480349cc55cSDimitry Andric AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,
14810b57cec5SDimitry Andric                                                  Attribute A) const {
148204eeddc0SDimitry Andric   AttrBuilder B(C);
14830b57cec5SDimitry Andric   B.addAttribute(A);
1484349cc55cSDimitry Andric   return addAttributesAtIndex(C, Index, B);
14850b57cec5SDimitry Andric }
14860b57cec5SDimitry Andric 
1487349cc55cSDimitry Andric AttributeList AttributeList::setAttributesAtIndex(LLVMContext &C,
1488349cc55cSDimitry Andric                                                   unsigned Index,
1489e8d8bef9SDimitry Andric                                                   AttributeSet Attrs) const {
1490e8d8bef9SDimitry Andric   Index = attrIdxToArrayIdx(Index);
1491e8d8bef9SDimitry Andric   SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
1492e8d8bef9SDimitry Andric   if (Index >= AttrSets.size())
1493e8d8bef9SDimitry Andric     AttrSets.resize(Index + 1);
1494e8d8bef9SDimitry Andric   AttrSets[Index] = Attrs;
1495bdd1243dSDimitry Andric 
1496bdd1243dSDimitry Andric   // Remove trailing empty attribute sets.
1497bdd1243dSDimitry Andric   while (!AttrSets.empty() && !AttrSets.back().hasAttributes())
1498bdd1243dSDimitry Andric     AttrSets.pop_back();
1499bdd1243dSDimitry Andric   if (AttrSets.empty())
1500bdd1243dSDimitry Andric     return {};
1501e8d8bef9SDimitry Andric   return AttributeList::getImpl(C, AttrSets);
1502e8d8bef9SDimitry Andric }
1503e8d8bef9SDimitry Andric 
1504349cc55cSDimitry Andric AttributeList AttributeList::addAttributesAtIndex(LLVMContext &C,
1505349cc55cSDimitry Andric                                                   unsigned Index,
15060b57cec5SDimitry Andric                                                   const AttrBuilder &B) const {
15070b57cec5SDimitry Andric   if (!B.hasAttributes())
15080b57cec5SDimitry Andric     return *this;
15090b57cec5SDimitry Andric 
15100b57cec5SDimitry Andric   if (!pImpl)
15110b57cec5SDimitry Andric     return AttributeList::get(C, {{Index, AttributeSet::get(C, B)}});
15120b57cec5SDimitry Andric 
151304eeddc0SDimitry Andric   AttrBuilder Merged(C, getAttributes(Index));
15140b57cec5SDimitry Andric   Merged.merge(B);
1515349cc55cSDimitry Andric   return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged));
15160b57cec5SDimitry Andric }
15170b57cec5SDimitry Andric 
15180b57cec5SDimitry Andric AttributeList AttributeList::addParamAttribute(LLVMContext &C,
15190b57cec5SDimitry Andric                                                ArrayRef<unsigned> ArgNos,
15200b57cec5SDimitry Andric                                                Attribute A) const {
15215ffd83dbSDimitry Andric   assert(llvm::is_sorted(ArgNos));
15220b57cec5SDimitry Andric 
15230b57cec5SDimitry Andric   SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());
15240b57cec5SDimitry Andric   unsigned MaxIndex = attrIdxToArrayIdx(ArgNos.back() + FirstArgIndex);
15250b57cec5SDimitry Andric   if (MaxIndex >= AttrSets.size())
15260b57cec5SDimitry Andric     AttrSets.resize(MaxIndex + 1);
15270b57cec5SDimitry Andric 
15280b57cec5SDimitry Andric   for (unsigned ArgNo : ArgNos) {
15290b57cec5SDimitry Andric     unsigned Index = attrIdxToArrayIdx(ArgNo + FirstArgIndex);
153004eeddc0SDimitry Andric     AttrBuilder B(C, AttrSets[Index]);
15310b57cec5SDimitry Andric     B.addAttribute(A);
15320b57cec5SDimitry Andric     AttrSets[Index] = AttributeSet::get(C, B);
15330b57cec5SDimitry Andric   }
15340b57cec5SDimitry Andric 
15350b57cec5SDimitry Andric   return getImpl(C, AttrSets);
15360b57cec5SDimitry Andric }
15370b57cec5SDimitry Andric 
1538349cc55cSDimitry Andric AttributeList
1539349cc55cSDimitry Andric AttributeList::removeAttributeAtIndex(LLVMContext &C, unsigned Index,
15400b57cec5SDimitry Andric                                       Attribute::AttrKind Kind) const {
1541bdd1243dSDimitry Andric   AttributeSet Attrs = getAttributes(Index);
1542bdd1243dSDimitry Andric   AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind);
1543bdd1243dSDimitry Andric   if (Attrs == NewAttrs)
1544349cc55cSDimitry Andric     return *this;
1545bdd1243dSDimitry Andric   return setAttributesAtIndex(C, Index, NewAttrs);
15460b57cec5SDimitry Andric }
15470b57cec5SDimitry Andric 
1548349cc55cSDimitry Andric AttributeList AttributeList::removeAttributeAtIndex(LLVMContext &C,
1549349cc55cSDimitry Andric                                                     unsigned Index,
15500b57cec5SDimitry Andric                                                     StringRef Kind) const {
1551bdd1243dSDimitry Andric   AttributeSet Attrs = getAttributes(Index);
1552bdd1243dSDimitry Andric   AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind);
1553bdd1243dSDimitry Andric   if (Attrs == NewAttrs)
1554349cc55cSDimitry Andric     return *this;
1555bdd1243dSDimitry Andric   return setAttributesAtIndex(C, Index, NewAttrs);
15560b57cec5SDimitry Andric }
15570b57cec5SDimitry Andric 
155804eeddc0SDimitry Andric AttributeList AttributeList::removeAttributesAtIndex(
155904eeddc0SDimitry Andric     LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const {
1560fe6060f1SDimitry Andric   AttributeSet Attrs = getAttributes(Index);
1561fe6060f1SDimitry Andric   AttributeSet NewAttrs = Attrs.removeAttributes(C, AttrsToRemove);
1562fe6060f1SDimitry Andric   // If nothing was removed, return the original list.
1563fe6060f1SDimitry Andric   if (Attrs == NewAttrs)
1564fe6060f1SDimitry Andric     return *this;
1565349cc55cSDimitry Andric   return setAttributesAtIndex(C, Index, NewAttrs);
15660b57cec5SDimitry Andric }
15670b57cec5SDimitry Andric 
1568349cc55cSDimitry Andric AttributeList
1569349cc55cSDimitry Andric AttributeList::removeAttributesAtIndex(LLVMContext &C,
15700b57cec5SDimitry Andric                                        unsigned WithoutIndex) const {
15710b57cec5SDimitry Andric   if (!pImpl)
15720b57cec5SDimitry Andric     return {};
1573bdd1243dSDimitry Andric   if (attrIdxToArrayIdx(WithoutIndex) >= getNumAttrSets())
15740b57cec5SDimitry Andric     return *this;
1575bdd1243dSDimitry Andric   return setAttributesAtIndex(C, WithoutIndex, AttributeSet());
15760b57cec5SDimitry Andric }
15770b57cec5SDimitry Andric 
1578349cc55cSDimitry Andric AttributeList AttributeList::addDereferenceableRetAttr(LLVMContext &C,
1579349cc55cSDimitry Andric                                                        uint64_t Bytes) const {
158004eeddc0SDimitry Andric   AttrBuilder B(C);
1581349cc55cSDimitry Andric   B.addDereferenceableAttr(Bytes);
1582349cc55cSDimitry Andric   return addRetAttributes(C, B);
1583349cc55cSDimitry Andric }
1584349cc55cSDimitry Andric 
1585349cc55cSDimitry Andric AttributeList AttributeList::addDereferenceableParamAttr(LLVMContext &C,
15860b57cec5SDimitry Andric                                                          unsigned Index,
15870b57cec5SDimitry Andric                                                          uint64_t Bytes) const {
158804eeddc0SDimitry Andric   AttrBuilder B(C);
15890b57cec5SDimitry Andric   B.addDereferenceableAttr(Bytes);
1590349cc55cSDimitry Andric   return addParamAttributes(C, Index, B);
15910b57cec5SDimitry Andric }
15920b57cec5SDimitry Andric 
15930b57cec5SDimitry Andric AttributeList
1594349cc55cSDimitry Andric AttributeList::addDereferenceableOrNullParamAttr(LLVMContext &C, unsigned Index,
15950b57cec5SDimitry Andric                                                  uint64_t Bytes) const {
159604eeddc0SDimitry Andric   AttrBuilder B(C);
15970b57cec5SDimitry Andric   B.addDereferenceableOrNullAttr(Bytes);
1598349cc55cSDimitry Andric   return addParamAttributes(C, Index, B);
15990b57cec5SDimitry Andric }
16000b57cec5SDimitry Andric 
1601*0fca6ea1SDimitry Andric AttributeList AttributeList::addRangeRetAttr(LLVMContext &C,
1602*0fca6ea1SDimitry Andric                                              const ConstantRange &CR) const {
1603*0fca6ea1SDimitry Andric   AttrBuilder B(C);
1604*0fca6ea1SDimitry Andric   B.addRangeAttr(CR);
1605*0fca6ea1SDimitry Andric   return addRetAttributes(C, B);
1606*0fca6ea1SDimitry Andric }
1607*0fca6ea1SDimitry Andric 
1608bdd1243dSDimitry Andric AttributeList AttributeList::addAllocSizeParamAttr(
1609bdd1243dSDimitry Andric     LLVMContext &C, unsigned Index, unsigned ElemSizeArg,
1610bdd1243dSDimitry Andric     const std::optional<unsigned> &NumElemsArg) {
161104eeddc0SDimitry Andric   AttrBuilder B(C);
16120b57cec5SDimitry Andric   B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);
1613349cc55cSDimitry Andric   return addParamAttributes(C, Index, B);
1614fe6060f1SDimitry Andric }
1615fe6060f1SDimitry Andric 
16160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16170b57cec5SDimitry Andric // AttributeList Accessor Methods
16180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16190b57cec5SDimitry Andric 
1620349cc55cSDimitry Andric AttributeSet AttributeList::getParamAttrs(unsigned ArgNo) const {
16210b57cec5SDimitry Andric   return getAttributes(ArgNo + FirstArgIndex);
16220b57cec5SDimitry Andric }
16230b57cec5SDimitry Andric 
1624349cc55cSDimitry Andric AttributeSet AttributeList::getRetAttrs() const {
16250b57cec5SDimitry Andric   return getAttributes(ReturnIndex);
16260b57cec5SDimitry Andric }
16270b57cec5SDimitry Andric 
1628349cc55cSDimitry Andric AttributeSet AttributeList::getFnAttrs() const {
16290b57cec5SDimitry Andric   return getAttributes(FunctionIndex);
16300b57cec5SDimitry Andric }
16310b57cec5SDimitry Andric 
1632349cc55cSDimitry Andric bool AttributeList::hasAttributeAtIndex(unsigned Index,
16330b57cec5SDimitry Andric                                         Attribute::AttrKind Kind) const {
16340b57cec5SDimitry Andric   return getAttributes(Index).hasAttribute(Kind);
16350b57cec5SDimitry Andric }
16360b57cec5SDimitry Andric 
1637349cc55cSDimitry Andric bool AttributeList::hasAttributeAtIndex(unsigned Index, StringRef Kind) const {
16380b57cec5SDimitry Andric   return getAttributes(Index).hasAttribute(Kind);
16390b57cec5SDimitry Andric }
16400b57cec5SDimitry Andric 
1641349cc55cSDimitry Andric bool AttributeList::hasAttributesAtIndex(unsigned Index) const {
16420b57cec5SDimitry Andric   return getAttributes(Index).hasAttributes();
16430b57cec5SDimitry Andric }
16440b57cec5SDimitry Andric 
1645349cc55cSDimitry Andric bool AttributeList::hasFnAttr(Attribute::AttrKind Kind) const {
16460b57cec5SDimitry Andric   return pImpl && pImpl->hasFnAttribute(Kind);
16470b57cec5SDimitry Andric }
16480b57cec5SDimitry Andric 
1649349cc55cSDimitry Andric bool AttributeList::hasFnAttr(StringRef Kind) const {
1650349cc55cSDimitry Andric   return hasAttributeAtIndex(AttributeList::FunctionIndex, Kind);
16510b57cec5SDimitry Andric }
16520b57cec5SDimitry Andric 
16530b57cec5SDimitry Andric bool AttributeList::hasAttrSomewhere(Attribute::AttrKind Attr,
16540b57cec5SDimitry Andric                                      unsigned *Index) const {
16555ffd83dbSDimitry Andric   return pImpl && pImpl->hasAttrSomewhere(Attr, Index);
16560b57cec5SDimitry Andric }
16570b57cec5SDimitry Andric 
1658349cc55cSDimitry Andric Attribute AttributeList::getAttributeAtIndex(unsigned Index,
16590b57cec5SDimitry Andric                                              Attribute::AttrKind Kind) const {
16600b57cec5SDimitry Andric   return getAttributes(Index).getAttribute(Kind);
16610b57cec5SDimitry Andric }
16620b57cec5SDimitry Andric 
1663349cc55cSDimitry Andric Attribute AttributeList::getAttributeAtIndex(unsigned Index,
1664349cc55cSDimitry Andric                                              StringRef Kind) const {
16650b57cec5SDimitry Andric   return getAttributes(Index).getAttribute(Kind);
16660b57cec5SDimitry Andric }
16670b57cec5SDimitry Andric 
16688bcb0991SDimitry Andric MaybeAlign AttributeList::getRetAlignment() const {
16690b57cec5SDimitry Andric   return getAttributes(ReturnIndex).getAlignment();
16700b57cec5SDimitry Andric }
16710b57cec5SDimitry Andric 
16728bcb0991SDimitry Andric MaybeAlign AttributeList::getParamAlignment(unsigned ArgNo) const {
16730b57cec5SDimitry Andric   return getAttributes(ArgNo + FirstArgIndex).getAlignment();
16740b57cec5SDimitry Andric }
16750b57cec5SDimitry Andric 
1676fe6060f1SDimitry Andric MaybeAlign AttributeList::getParamStackAlignment(unsigned ArgNo) const {
1677fe6060f1SDimitry Andric   return getAttributes(ArgNo + FirstArgIndex).getStackAlignment();
1678fe6060f1SDimitry Andric }
1679fe6060f1SDimitry Andric 
16800b57cec5SDimitry Andric Type *AttributeList::getParamByValType(unsigned Index) const {
16810b57cec5SDimitry Andric   return getAttributes(Index+FirstArgIndex).getByValType();
16820b57cec5SDimitry Andric }
16830b57cec5SDimitry Andric 
1684e8d8bef9SDimitry Andric Type *AttributeList::getParamStructRetType(unsigned Index) const {
1685e8d8bef9SDimitry Andric   return getAttributes(Index + FirstArgIndex).getStructRetType();
1686e8d8bef9SDimitry Andric }
1687e8d8bef9SDimitry Andric 
1688e8d8bef9SDimitry Andric Type *AttributeList::getParamByRefType(unsigned Index) const {
1689e8d8bef9SDimitry Andric   return getAttributes(Index + FirstArgIndex).getByRefType();
1690e8d8bef9SDimitry Andric }
1691e8d8bef9SDimitry Andric 
16925ffd83dbSDimitry Andric Type *AttributeList::getParamPreallocatedType(unsigned Index) const {
16935ffd83dbSDimitry Andric   return getAttributes(Index + FirstArgIndex).getPreallocatedType();
16945ffd83dbSDimitry Andric }
16955ffd83dbSDimitry Andric 
1696fe6060f1SDimitry Andric Type *AttributeList::getParamInAllocaType(unsigned Index) const {
1697fe6060f1SDimitry Andric   return getAttributes(Index + FirstArgIndex).getInAllocaType();
1698fe6060f1SDimitry Andric }
1699fe6060f1SDimitry Andric 
1700fe6060f1SDimitry Andric Type *AttributeList::getParamElementType(unsigned Index) const {
1701fe6060f1SDimitry Andric   return getAttributes(Index + FirstArgIndex).getElementType();
1702fe6060f1SDimitry Andric }
1703fe6060f1SDimitry Andric 
1704349cc55cSDimitry Andric MaybeAlign AttributeList::getFnStackAlignment() const {
1705349cc55cSDimitry Andric   return getFnAttrs().getStackAlignment();
17060b57cec5SDimitry Andric }
17070b57cec5SDimitry Andric 
1708349cc55cSDimitry Andric MaybeAlign AttributeList::getRetStackAlignment() const {
1709349cc55cSDimitry Andric   return getRetAttrs().getStackAlignment();
17100b57cec5SDimitry Andric }
17110b57cec5SDimitry Andric 
1712349cc55cSDimitry Andric uint64_t AttributeList::getRetDereferenceableBytes() const {
1713349cc55cSDimitry Andric   return getRetAttrs().getDereferenceableBytes();
17140b57cec5SDimitry Andric }
17150b57cec5SDimitry Andric 
1716349cc55cSDimitry Andric uint64_t AttributeList::getParamDereferenceableBytes(unsigned Index) const {
1717349cc55cSDimitry Andric   return getParamAttrs(Index).getDereferenceableBytes();
17180b57cec5SDimitry Andric }
17190b57cec5SDimitry Andric 
1720349cc55cSDimitry Andric uint64_t AttributeList::getRetDereferenceableOrNullBytes() const {
1721349cc55cSDimitry Andric   return getRetAttrs().getDereferenceableOrNullBytes();
1722349cc55cSDimitry Andric }
1723349cc55cSDimitry Andric 
1724349cc55cSDimitry Andric uint64_t
1725349cc55cSDimitry Andric AttributeList::getParamDereferenceableOrNullBytes(unsigned Index) const {
1726349cc55cSDimitry Andric   return getParamAttrs(Index).getDereferenceableOrNullBytes();
1727fe6060f1SDimitry Andric }
1728fe6060f1SDimitry Andric 
172906c3fb27SDimitry Andric FPClassTest AttributeList::getRetNoFPClass() const {
173006c3fb27SDimitry Andric   return getRetAttrs().getNoFPClass();
173106c3fb27SDimitry Andric }
173206c3fb27SDimitry Andric 
173306c3fb27SDimitry Andric FPClassTest AttributeList::getParamNoFPClass(unsigned Index) const {
173406c3fb27SDimitry Andric   return getParamAttrs(Index).getNoFPClass();
173506c3fb27SDimitry Andric }
173606c3fb27SDimitry Andric 
173781ad6265SDimitry Andric UWTableKind AttributeList::getUWTableKind() const {
173881ad6265SDimitry Andric   return getFnAttrs().getUWTableKind();
173981ad6265SDimitry Andric }
174081ad6265SDimitry Andric 
174181ad6265SDimitry Andric AllocFnKind AttributeList::getAllocKind() const {
174281ad6265SDimitry Andric   return getFnAttrs().getAllocKind();
174381ad6265SDimitry Andric }
174481ad6265SDimitry Andric 
1745bdd1243dSDimitry Andric MemoryEffects AttributeList::getMemoryEffects() const {
1746bdd1243dSDimitry Andric   return getFnAttrs().getMemoryEffects();
1747bdd1243dSDimitry Andric }
1748bdd1243dSDimitry Andric 
17490b57cec5SDimitry Andric std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const {
17500b57cec5SDimitry Andric   return getAttributes(Index).getAsString(InAttrGrp);
17510b57cec5SDimitry Andric }
17520b57cec5SDimitry Andric 
17530b57cec5SDimitry Andric AttributeSet AttributeList::getAttributes(unsigned Index) const {
17540b57cec5SDimitry Andric   Index = attrIdxToArrayIdx(Index);
17550b57cec5SDimitry Andric   if (!pImpl || Index >= getNumAttrSets())
17560b57cec5SDimitry Andric     return {};
17570b57cec5SDimitry Andric   return pImpl->begin()[Index];
17580b57cec5SDimitry Andric }
17590b57cec5SDimitry Andric 
1760fe6060f1SDimitry Andric bool AttributeList::hasParentContext(LLVMContext &C) const {
1761fe6060f1SDimitry Andric   assert(!isEmpty() && "an empty attribute list has no parent context");
1762fe6060f1SDimitry Andric   FoldingSetNodeID ID;
1763fe6060f1SDimitry Andric   pImpl->Profile(ID);
1764fe6060f1SDimitry Andric   void *Unused;
1765fe6060f1SDimitry Andric   return C.pImpl->AttrsLists.FindNodeOrInsertPos(ID, Unused) == pImpl;
1766fe6060f1SDimitry Andric }
1767fe6060f1SDimitry Andric 
17680b57cec5SDimitry Andric AttributeList::iterator AttributeList::begin() const {
17690b57cec5SDimitry Andric   return pImpl ? pImpl->begin() : nullptr;
17700b57cec5SDimitry Andric }
17710b57cec5SDimitry Andric 
17720b57cec5SDimitry Andric AttributeList::iterator AttributeList::end() const {
17730b57cec5SDimitry Andric   return pImpl ? pImpl->end() : nullptr;
17740b57cec5SDimitry Andric }
17750b57cec5SDimitry Andric 
17760b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17770b57cec5SDimitry Andric // AttributeList Introspection Methods
17780b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
17790b57cec5SDimitry Andric 
17800b57cec5SDimitry Andric unsigned AttributeList::getNumAttrSets() const {
17810b57cec5SDimitry Andric   return pImpl ? pImpl->NumAttrSets : 0;
17820b57cec5SDimitry Andric }
17830b57cec5SDimitry Andric 
1784fe6060f1SDimitry Andric void AttributeList::print(raw_ostream &O) const {
1785fe6060f1SDimitry Andric   O << "AttributeList[\n";
17860b57cec5SDimitry Andric 
1787349cc55cSDimitry Andric   for (unsigned i : indexes()) {
1788fe6060f1SDimitry Andric     if (!getAttributes(i).hasAttributes())
1789fe6060f1SDimitry Andric       continue;
1790fe6060f1SDimitry Andric     O << "  { ";
1791fe6060f1SDimitry Andric     switch (i) {
1792fe6060f1SDimitry Andric     case AttrIndex::ReturnIndex:
1793fe6060f1SDimitry Andric       O << "return";
1794fe6060f1SDimitry Andric       break;
1795fe6060f1SDimitry Andric     case AttrIndex::FunctionIndex:
1796fe6060f1SDimitry Andric       O << "function";
1797fe6060f1SDimitry Andric       break;
1798fe6060f1SDimitry Andric     default:
1799fe6060f1SDimitry Andric       O << "arg(" << i - AttrIndex::FirstArgIndex << ")";
1800fe6060f1SDimitry Andric     }
1801fe6060f1SDimitry Andric     O << " => " << getAsString(i) << " }\n";
18020b57cec5SDimitry Andric   }
18030b57cec5SDimitry Andric 
1804fe6060f1SDimitry Andric   O << "]\n";
18050b57cec5SDimitry Andric }
1806fe6060f1SDimitry Andric 
1807fe6060f1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1808fe6060f1SDimitry Andric LLVM_DUMP_METHOD void AttributeList::dump() const { print(dbgs()); }
18090b57cec5SDimitry Andric #endif
18100b57cec5SDimitry Andric 
18110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
18120b57cec5SDimitry Andric // AttrBuilder Method Implementations
18130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
18140b57cec5SDimitry Andric 
181504eeddc0SDimitry Andric AttrBuilder::AttrBuilder(LLVMContext &Ctx, AttributeSet AS) : Ctx(Ctx) {
181604eeddc0SDimitry Andric   append_range(Attrs, AS);
181704eeddc0SDimitry Andric   assert(is_sorted(Attrs) && "AttributeSet should be sorted");
18180b57cec5SDimitry Andric }
18190b57cec5SDimitry Andric 
182004eeddc0SDimitry Andric void AttrBuilder::clear() { Attrs.clear(); }
18210b57cec5SDimitry Andric 
182204eeddc0SDimitry Andric /// Attribute comparator that only compares attribute keys. Enum attributes are
182304eeddc0SDimitry Andric /// sorted before string attributes.
182404eeddc0SDimitry Andric struct AttributeComparator {
182504eeddc0SDimitry Andric   bool operator()(Attribute A0, Attribute A1) const {
182604eeddc0SDimitry Andric     bool A0IsString = A0.isStringAttribute();
182704eeddc0SDimitry Andric     bool A1IsString = A1.isStringAttribute();
182804eeddc0SDimitry Andric     if (A0IsString) {
182904eeddc0SDimitry Andric       if (A1IsString)
183004eeddc0SDimitry Andric         return A0.getKindAsString() < A1.getKindAsString();
183104eeddc0SDimitry Andric       else
183204eeddc0SDimitry Andric         return false;
1833fe6060f1SDimitry Andric     }
183404eeddc0SDimitry Andric     if (A1IsString)
183504eeddc0SDimitry Andric       return true;
183604eeddc0SDimitry Andric     return A0.getKindAsEnum() < A1.getKindAsEnum();
1837349cc55cSDimitry Andric   }
183804eeddc0SDimitry Andric   bool operator()(Attribute A0, Attribute::AttrKind Kind) const {
183904eeddc0SDimitry Andric     if (A0.isStringAttribute())
184004eeddc0SDimitry Andric       return false;
184104eeddc0SDimitry Andric     return A0.getKindAsEnum() < Kind;
184204eeddc0SDimitry Andric   }
184304eeddc0SDimitry Andric   bool operator()(Attribute A0, StringRef Kind) const {
184404eeddc0SDimitry Andric     if (A0.isStringAttribute())
184504eeddc0SDimitry Andric       return A0.getKindAsString() < Kind;
184604eeddc0SDimitry Andric     return true;
184704eeddc0SDimitry Andric   }
184804eeddc0SDimitry Andric };
1849349cc55cSDimitry Andric 
185004eeddc0SDimitry Andric template <typename K>
185104eeddc0SDimitry Andric static void addAttributeImpl(SmallVectorImpl<Attribute> &Attrs, K Kind,
185204eeddc0SDimitry Andric                              Attribute Attr) {
185304eeddc0SDimitry Andric   auto It = lower_bound(Attrs, Kind, AttributeComparator());
185404eeddc0SDimitry Andric   if (It != Attrs.end() && It->hasAttribute(Kind))
185504eeddc0SDimitry Andric     std::swap(*It, Attr);
185604eeddc0SDimitry Andric   else
185704eeddc0SDimitry Andric     Attrs.insert(It, Attr);
18580b57cec5SDimitry Andric }
18590b57cec5SDimitry Andric 
18600b57cec5SDimitry Andric AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {
186104eeddc0SDimitry Andric   if (Attr.isStringAttribute())
186204eeddc0SDimitry Andric     addAttributeImpl(Attrs, Attr.getKindAsString(), Attr);
186304eeddc0SDimitry Andric   else
186404eeddc0SDimitry Andric     addAttributeImpl(Attrs, Attr.getKindAsEnum(), Attr);
18650b57cec5SDimitry Andric   return *this;
18660b57cec5SDimitry Andric }
18670b57cec5SDimitry Andric 
186804eeddc0SDimitry Andric AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Kind) {
186904eeddc0SDimitry Andric   addAttributeImpl(Attrs, Kind, Attribute::get(Ctx, Kind));
18700b57cec5SDimitry Andric   return *this;
18710b57cec5SDimitry Andric }
18720b57cec5SDimitry Andric 
18730b57cec5SDimitry Andric AttrBuilder &AttrBuilder::addAttribute(StringRef A, StringRef V) {
187404eeddc0SDimitry Andric   addAttributeImpl(Attrs, A, Attribute::get(Ctx, A, V));
18750b57cec5SDimitry Andric   return *this;
18760b57cec5SDimitry Andric }
18770b57cec5SDimitry Andric 
18780b57cec5SDimitry Andric AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {
18790b57cec5SDimitry Andric   assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");
188004eeddc0SDimitry Andric   auto It = lower_bound(Attrs, Val, AttributeComparator());
188104eeddc0SDimitry Andric   if (It != Attrs.end() && It->hasAttribute(Val))
188204eeddc0SDimitry Andric     Attrs.erase(It);
18830b57cec5SDimitry Andric   return *this;
18840b57cec5SDimitry Andric }
18850b57cec5SDimitry Andric 
18860b57cec5SDimitry Andric AttrBuilder &AttrBuilder::removeAttribute(StringRef A) {
188704eeddc0SDimitry Andric   auto It = lower_bound(Attrs, A, AttributeComparator());
188804eeddc0SDimitry Andric   if (It != Attrs.end() && It->hasAttribute(A))
188904eeddc0SDimitry Andric     Attrs.erase(It);
1890349cc55cSDimitry Andric   return *this;
1891349cc55cSDimitry Andric }
1892349cc55cSDimitry Andric 
1893bdd1243dSDimitry Andric std::optional<uint64_t>
1894bdd1243dSDimitry Andric AttrBuilder::getRawIntAttr(Attribute::AttrKind Kind) const {
189504eeddc0SDimitry Andric   assert(Attribute::isIntAttrKind(Kind) && "Not an int attribute");
189604eeddc0SDimitry Andric   Attribute A = getAttribute(Kind);
1897bdd1243dSDimitry Andric   if (A.isValid())
1898bdd1243dSDimitry Andric     return A.getValueAsInt();
1899bdd1243dSDimitry Andric   return std::nullopt;
1900349cc55cSDimitry Andric }
1901349cc55cSDimitry Andric 
1902349cc55cSDimitry Andric AttrBuilder &AttrBuilder::addRawIntAttr(Attribute::AttrKind Kind,
1903349cc55cSDimitry Andric                                         uint64_t Value) {
190404eeddc0SDimitry Andric   return addAttribute(Attribute::get(Ctx, Kind, Value));
19050b57cec5SDimitry Andric }
19060b57cec5SDimitry Andric 
1907bdd1243dSDimitry Andric std::optional<std::pair<unsigned, std::optional<unsigned>>>
1908bdd1243dSDimitry Andric AttrBuilder::getAllocSizeArgs() const {
1909bdd1243dSDimitry Andric   Attribute A = getAttribute(Attribute::AllocSize);
1910bdd1243dSDimitry Andric   if (A.isValid())
1911bdd1243dSDimitry Andric     return A.getAllocSizeArgs();
1912bdd1243dSDimitry Andric   return std::nullopt;
1913fe6060f1SDimitry Andric }
1914fe6060f1SDimitry Andric 
19158bcb0991SDimitry Andric AttrBuilder &AttrBuilder::addAlignmentAttr(MaybeAlign Align) {
19168bcb0991SDimitry Andric   if (!Align)
19178bcb0991SDimitry Andric     return *this;
19180b57cec5SDimitry Andric 
19195ffd83dbSDimitry Andric   assert(*Align <= llvm::Value::MaximumAlignment && "Alignment too large.");
1920349cc55cSDimitry Andric   return addRawIntAttr(Attribute::Alignment, Align->value());
19210b57cec5SDimitry Andric }
19220b57cec5SDimitry Andric 
19238bcb0991SDimitry Andric AttrBuilder &AttrBuilder::addStackAlignmentAttr(MaybeAlign Align) {
19240b57cec5SDimitry Andric   // Default alignment, allow the target to define how to align it.
19258bcb0991SDimitry Andric   if (!Align)
19268bcb0991SDimitry Andric     return *this;
19270b57cec5SDimitry Andric 
19288bcb0991SDimitry Andric   assert(*Align <= 0x100 && "Alignment too large.");
1929349cc55cSDimitry Andric   return addRawIntAttr(Attribute::StackAlignment, Align->value());
19300b57cec5SDimitry Andric }
19310b57cec5SDimitry Andric 
19320b57cec5SDimitry Andric AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {
19330b57cec5SDimitry Andric   if (Bytes == 0) return *this;
19340b57cec5SDimitry Andric 
1935349cc55cSDimitry Andric   return addRawIntAttr(Attribute::Dereferenceable, Bytes);
19360b57cec5SDimitry Andric }
19370b57cec5SDimitry Andric 
19380b57cec5SDimitry Andric AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) {
19390b57cec5SDimitry Andric   if (Bytes == 0)
19400b57cec5SDimitry Andric     return *this;
19410b57cec5SDimitry Andric 
1942349cc55cSDimitry Andric   return addRawIntAttr(Attribute::DereferenceableOrNull, Bytes);
19430b57cec5SDimitry Andric }
19440b57cec5SDimitry Andric 
1945bdd1243dSDimitry Andric AttrBuilder &
1946bdd1243dSDimitry Andric AttrBuilder::addAllocSizeAttr(unsigned ElemSize,
1947bdd1243dSDimitry Andric                               const std::optional<unsigned> &NumElems) {
19480b57cec5SDimitry Andric   return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems));
19490b57cec5SDimitry Andric }
19500b57cec5SDimitry Andric 
19510b57cec5SDimitry Andric AttrBuilder &AttrBuilder::addAllocSizeAttrFromRawRepr(uint64_t RawArgs) {
19520b57cec5SDimitry Andric   // (0, 0) is our "not present" value, so we need to check for it here.
19530b57cec5SDimitry Andric   assert(RawArgs && "Invalid allocsize arguments -- given allocsize(0, 0)");
1954349cc55cSDimitry Andric   return addRawIntAttr(Attribute::AllocSize, RawArgs);
19550b57cec5SDimitry Andric }
19560b57cec5SDimitry Andric 
1957fe6060f1SDimitry Andric AttrBuilder &AttrBuilder::addVScaleRangeAttr(unsigned MinValue,
1958bdd1243dSDimitry Andric                                              std::optional<unsigned> MaxValue) {
1959fe6060f1SDimitry Andric   return addVScaleRangeAttrFromRawRepr(packVScaleRangeArgs(MinValue, MaxValue));
1960fe6060f1SDimitry Andric }
1961fe6060f1SDimitry Andric 
1962fe6060f1SDimitry Andric AttrBuilder &AttrBuilder::addVScaleRangeAttrFromRawRepr(uint64_t RawArgs) {
1963fe6060f1SDimitry Andric   // (0, 0) is not present hence ignore this case
1964fe6060f1SDimitry Andric   if (RawArgs == 0)
19650b57cec5SDimitry Andric     return *this;
1966fe6060f1SDimitry Andric 
1967349cc55cSDimitry Andric   return addRawIntAttr(Attribute::VScaleRange, RawArgs);
1968fe6060f1SDimitry Andric }
1969fe6060f1SDimitry Andric 
197081ad6265SDimitry Andric AttrBuilder &AttrBuilder::addUWTableAttr(UWTableKind Kind) {
197181ad6265SDimitry Andric   if (Kind == UWTableKind::None)
197281ad6265SDimitry Andric     return *this;
197381ad6265SDimitry Andric   return addRawIntAttr(Attribute::UWTable, uint64_t(Kind));
197481ad6265SDimitry Andric }
197581ad6265SDimitry Andric 
1976bdd1243dSDimitry Andric AttrBuilder &AttrBuilder::addMemoryAttr(MemoryEffects ME) {
1977bdd1243dSDimitry Andric   return addRawIntAttr(Attribute::Memory, ME.toIntValue());
1978bdd1243dSDimitry Andric }
1979bdd1243dSDimitry Andric 
198006c3fb27SDimitry Andric AttrBuilder &AttrBuilder::addNoFPClassAttr(FPClassTest Mask) {
198106c3fb27SDimitry Andric   if (Mask == fcNone)
198206c3fb27SDimitry Andric     return *this;
198306c3fb27SDimitry Andric 
198406c3fb27SDimitry Andric   return addRawIntAttr(Attribute::NoFPClass, Mask);
198506c3fb27SDimitry Andric }
198606c3fb27SDimitry Andric 
198781ad6265SDimitry Andric AttrBuilder &AttrBuilder::addAllocKindAttr(AllocFnKind Kind) {
198881ad6265SDimitry Andric   return addRawIntAttr(Attribute::AllocKind, static_cast<uint64_t>(Kind));
198981ad6265SDimitry Andric }
199081ad6265SDimitry Andric 
1991fe6060f1SDimitry Andric Type *AttrBuilder::getTypeAttr(Attribute::AttrKind Kind) const {
199204eeddc0SDimitry Andric   assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute");
199304eeddc0SDimitry Andric   Attribute A = getAttribute(Kind);
199404eeddc0SDimitry Andric   return A.isValid() ? A.getValueAsType() : nullptr;
1995fe6060f1SDimitry Andric }
1996fe6060f1SDimitry Andric 
1997fe6060f1SDimitry Andric AttrBuilder &AttrBuilder::addTypeAttr(Attribute::AttrKind Kind, Type *Ty) {
199804eeddc0SDimitry Andric   return addAttribute(Attribute::get(Ctx, Kind, Ty));
1999fe6060f1SDimitry Andric }
2000fe6060f1SDimitry Andric 
2001fe6060f1SDimitry Andric AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) {
2002fe6060f1SDimitry Andric   return addTypeAttr(Attribute::ByVal, Ty);
20030b57cec5SDimitry Andric }
20040b57cec5SDimitry Andric 
2005e8d8bef9SDimitry Andric AttrBuilder &AttrBuilder::addStructRetAttr(Type *Ty) {
2006fe6060f1SDimitry Andric   return addTypeAttr(Attribute::StructRet, Ty);
2007e8d8bef9SDimitry Andric }
2008e8d8bef9SDimitry Andric 
2009e8d8bef9SDimitry Andric AttrBuilder &AttrBuilder::addByRefAttr(Type *Ty) {
2010fe6060f1SDimitry Andric   return addTypeAttr(Attribute::ByRef, Ty);
2011e8d8bef9SDimitry Andric }
2012e8d8bef9SDimitry Andric 
20135ffd83dbSDimitry Andric AttrBuilder &AttrBuilder::addPreallocatedAttr(Type *Ty) {
2014fe6060f1SDimitry Andric   return addTypeAttr(Attribute::Preallocated, Ty);
2015fe6060f1SDimitry Andric }
2016fe6060f1SDimitry Andric 
2017fe6060f1SDimitry Andric AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) {
2018fe6060f1SDimitry Andric   return addTypeAttr(Attribute::InAlloca, Ty);
20195ffd83dbSDimitry Andric }
20205ffd83dbSDimitry Andric 
2021*0fca6ea1SDimitry Andric AttrBuilder &AttrBuilder::addConstantRangeAttr(Attribute::AttrKind Kind,
2022*0fca6ea1SDimitry Andric                                                const ConstantRange &CR) {
2023*0fca6ea1SDimitry Andric   return addAttribute(Attribute::get(Ctx, Kind, CR));
2024*0fca6ea1SDimitry Andric }
2025*0fca6ea1SDimitry Andric 
2026*0fca6ea1SDimitry Andric AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {
2027*0fca6ea1SDimitry Andric   return addConstantRangeAttr(Attribute::Range, CR);
2028*0fca6ea1SDimitry Andric }
2029*0fca6ea1SDimitry Andric 
2030*0fca6ea1SDimitry Andric AttrBuilder &
2031*0fca6ea1SDimitry Andric AttrBuilder::addConstantRangeListAttr(Attribute::AttrKind Kind,
2032*0fca6ea1SDimitry Andric                                       ArrayRef<ConstantRange> Val) {
2033*0fca6ea1SDimitry Andric   return addAttribute(Attribute::get(Ctx, Kind, Val));
2034*0fca6ea1SDimitry Andric }
2035*0fca6ea1SDimitry Andric 
2036*0fca6ea1SDimitry Andric AttrBuilder &AttrBuilder::addInitializesAttr(const ConstantRangeList &CRL) {
2037*0fca6ea1SDimitry Andric   return addConstantRangeListAttr(Attribute::Initializes, CRL.rangesRef());
2038*0fca6ea1SDimitry Andric }
2039*0fca6ea1SDimitry Andric 
20400b57cec5SDimitry Andric AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
204104eeddc0SDimitry Andric   // TODO: Could make this O(n) as we're merging two sorted lists.
204204eeddc0SDimitry Andric   for (const auto &I : B.attrs())
204304eeddc0SDimitry Andric     addAttribute(I);
20440b57cec5SDimitry Andric 
20450b57cec5SDimitry Andric   return *this;
20460b57cec5SDimitry Andric }
20470b57cec5SDimitry Andric 
204804eeddc0SDimitry Andric AttrBuilder &AttrBuilder::remove(const AttributeMask &AM) {
204904eeddc0SDimitry Andric   erase_if(Attrs, [&](Attribute A) { return AM.contains(A); });
20500b57cec5SDimitry Andric   return *this;
20510b57cec5SDimitry Andric }
20520b57cec5SDimitry Andric 
205304eeddc0SDimitry Andric bool AttrBuilder::overlaps(const AttributeMask &AM) const {
205404eeddc0SDimitry Andric   return any_of(Attrs, [&](Attribute A) { return AM.contains(A); });
205504eeddc0SDimitry Andric }
20560b57cec5SDimitry Andric 
205704eeddc0SDimitry Andric Attribute AttrBuilder::getAttribute(Attribute::AttrKind A) const {
205804eeddc0SDimitry Andric   assert((unsigned)A < Attribute::EndAttrKinds && "Attribute out of range!");
205904eeddc0SDimitry Andric   auto It = lower_bound(Attrs, A, AttributeComparator());
206004eeddc0SDimitry Andric   if (It != Attrs.end() && It->hasAttribute(A))
206104eeddc0SDimitry Andric     return *It;
206204eeddc0SDimitry Andric   return {};
206304eeddc0SDimitry Andric }
20640b57cec5SDimitry Andric 
206504eeddc0SDimitry Andric Attribute AttrBuilder::getAttribute(StringRef A) const {
206604eeddc0SDimitry Andric   auto It = lower_bound(Attrs, A, AttributeComparator());
206704eeddc0SDimitry Andric   if (It != Attrs.end() && It->hasAttribute(A))
206804eeddc0SDimitry Andric     return *It;
206904eeddc0SDimitry Andric   return {};
207004eeddc0SDimitry Andric }
207104eeddc0SDimitry Andric 
207204eeddc0SDimitry Andric bool AttrBuilder::contains(Attribute::AttrKind A) const {
207304eeddc0SDimitry Andric   return getAttribute(A).isValid();
20740b57cec5SDimitry Andric }
20750b57cec5SDimitry Andric 
20760b57cec5SDimitry Andric bool AttrBuilder::contains(StringRef A) const {
207704eeddc0SDimitry Andric   return getAttribute(A).isValid();
20780b57cec5SDimitry Andric }
20790b57cec5SDimitry Andric 
2080e8d8bef9SDimitry Andric bool AttrBuilder::operator==(const AttrBuilder &B) const {
208104eeddc0SDimitry Andric   return Attrs == B.Attrs;
20820b57cec5SDimitry Andric }
20830b57cec5SDimitry Andric 
20840b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
20850b57cec5SDimitry Andric // AttributeFuncs Function Defintions
20860b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
20870b57cec5SDimitry Andric 
208806c3fb27SDimitry Andric /// Returns true if this is a type legal for the 'nofpclass' attribute. This
208906c3fb27SDimitry Andric /// follows the same type rules as FPMathOperator.
209006c3fb27SDimitry Andric ///
209106c3fb27SDimitry Andric /// TODO: Consider relaxing to any FP type struct fields.
209206c3fb27SDimitry Andric bool AttributeFuncs::isNoFPClassCompatibleType(Type *Ty) {
209306c3fb27SDimitry Andric   while (ArrayType *ArrTy = dyn_cast<ArrayType>(Ty))
209406c3fb27SDimitry Andric     Ty = ArrTy->getElementType();
209506c3fb27SDimitry Andric   return Ty->isFPOrFPVectorTy();
209606c3fb27SDimitry Andric }
209706c3fb27SDimitry Andric 
20980b57cec5SDimitry Andric /// Which attributes cannot be applied to a type.
209981ad6265SDimitry Andric AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,
210081ad6265SDimitry Andric                                                AttributeSafetyKind ASK) {
210104eeddc0SDimitry Andric   AttributeMask Incompatible;
21020b57cec5SDimitry Andric 
210381ad6265SDimitry Andric   if (!Ty->isIntegerTy()) {
210404eeddc0SDimitry Andric     // Attributes that only apply to integers.
210581ad6265SDimitry Andric     if (ASK & ASK_SAFE_TO_DROP)
210681ad6265SDimitry Andric       Incompatible.addAttribute(Attribute::AllocAlign);
210781ad6265SDimitry Andric     if (ASK & ASK_UNSAFE_TO_DROP)
210881ad6265SDimitry Andric       Incompatible.addAttribute(Attribute::SExt).addAttribute(Attribute::ZExt);
210981ad6265SDimitry Andric   }
21100b57cec5SDimitry Andric 
2111*0fca6ea1SDimitry Andric   if (!Ty->isIntOrIntVectorTy()) {
2112*0fca6ea1SDimitry Andric     // Attributes that only apply to integers or vector of integers.
2113*0fca6ea1SDimitry Andric     if (ASK & ASK_SAFE_TO_DROP)
2114*0fca6ea1SDimitry Andric       Incompatible.addAttribute(Attribute::Range);
2115*0fca6ea1SDimitry Andric   }
2116*0fca6ea1SDimitry Andric 
211781ad6265SDimitry Andric   if (!Ty->isPointerTy()) {
211804eeddc0SDimitry Andric     // Attributes that only apply to pointers.
211981ad6265SDimitry Andric     if (ASK & ASK_SAFE_TO_DROP)
212081ad6265SDimitry Andric       Incompatible.addAttribute(Attribute::NoAlias)
21210b57cec5SDimitry Andric           .addAttribute(Attribute::NoCapture)
21220b57cec5SDimitry Andric           .addAttribute(Attribute::NonNull)
2123fe6060f1SDimitry Andric           .addAttribute(Attribute::ReadNone)
2124fe6060f1SDimitry Andric           .addAttribute(Attribute::ReadOnly)
212504eeddc0SDimitry Andric           .addAttribute(Attribute::Dereferenceable)
21265f757f3fSDimitry Andric           .addAttribute(Attribute::DereferenceableOrNull)
21275f757f3fSDimitry Andric           .addAttribute(Attribute::Writable)
2128*0fca6ea1SDimitry Andric           .addAttribute(Attribute::DeadOnUnwind)
2129*0fca6ea1SDimitry Andric           .addAttribute(Attribute::Initializes);
213081ad6265SDimitry Andric     if (ASK & ASK_UNSAFE_TO_DROP)
213181ad6265SDimitry Andric       Incompatible.addAttribute(Attribute::Nest)
213281ad6265SDimitry Andric           .addAttribute(Attribute::SwiftError)
213304eeddc0SDimitry Andric           .addAttribute(Attribute::Preallocated)
213404eeddc0SDimitry Andric           .addAttribute(Attribute::InAlloca)
213504eeddc0SDimitry Andric           .addAttribute(Attribute::ByVal)
213604eeddc0SDimitry Andric           .addAttribute(Attribute::StructRet)
213704eeddc0SDimitry Andric           .addAttribute(Attribute::ByRef)
213881ad6265SDimitry Andric           .addAttribute(Attribute::ElementType)
213981ad6265SDimitry Andric           .addAttribute(Attribute::AllocatedPointer);
214081ad6265SDimitry Andric   }
214104eeddc0SDimitry Andric 
214204eeddc0SDimitry Andric     // Attributes that only apply to pointers or vectors of pointers.
214381ad6265SDimitry Andric   if (!Ty->isPtrOrPtrVectorTy()) {
214481ad6265SDimitry Andric     if (ASK & ASK_SAFE_TO_DROP)
214504eeddc0SDimitry Andric       Incompatible.addAttribute(Attribute::Alignment);
214681ad6265SDimitry Andric   }
2147e8d8bef9SDimitry Andric 
214806c3fb27SDimitry Andric   if (ASK & ASK_SAFE_TO_DROP) {
214906c3fb27SDimitry Andric     if (!isNoFPClassCompatibleType(Ty))
215006c3fb27SDimitry Andric       Incompatible.addAttribute(Attribute::NoFPClass);
215106c3fb27SDimitry Andric   }
215206c3fb27SDimitry Andric 
2153e8d8bef9SDimitry Andric   // Some attributes can apply to all "values" but there are no `void` values.
215481ad6265SDimitry Andric   if (Ty->isVoidTy()) {
215581ad6265SDimitry Andric     if (ASK & ASK_SAFE_TO_DROP)
2156e8d8bef9SDimitry Andric       Incompatible.addAttribute(Attribute::NoUndef);
215781ad6265SDimitry Andric   }
21580b57cec5SDimitry Andric 
21590b57cec5SDimitry Andric   return Incompatible;
21600b57cec5SDimitry Andric }
21610b57cec5SDimitry Andric 
216204eeddc0SDimitry Andric AttributeMask AttributeFuncs::getUBImplyingAttributes() {
216304eeddc0SDimitry Andric   AttributeMask AM;
216404eeddc0SDimitry Andric   AM.addAttribute(Attribute::NoUndef);
216504eeddc0SDimitry Andric   AM.addAttribute(Attribute::Dereferenceable);
216604eeddc0SDimitry Andric   AM.addAttribute(Attribute::DereferenceableOrNull);
216704eeddc0SDimitry Andric   return AM;
2168fe6060f1SDimitry Andric }
2169fe6060f1SDimitry Andric 
217006c3fb27SDimitry Andric /// Callees with dynamic denormal modes are compatible with any caller mode.
217106c3fb27SDimitry Andric static bool denormModeCompatible(DenormalMode CallerMode,
217206c3fb27SDimitry Andric                                  DenormalMode CalleeMode) {
217306c3fb27SDimitry Andric   if (CallerMode == CalleeMode || CalleeMode == DenormalMode::getDynamic())
217406c3fb27SDimitry Andric     return true;
217506c3fb27SDimitry Andric 
217606c3fb27SDimitry Andric   // If they don't exactly match, it's OK if the mismatched component is
217706c3fb27SDimitry Andric   // dynamic.
217806c3fb27SDimitry Andric   if (CalleeMode.Input == CallerMode.Input &&
217906c3fb27SDimitry Andric       CalleeMode.Output == DenormalMode::Dynamic)
218006c3fb27SDimitry Andric     return true;
218106c3fb27SDimitry Andric 
218206c3fb27SDimitry Andric   if (CalleeMode.Output == CallerMode.Output &&
218306c3fb27SDimitry Andric       CalleeMode.Input == DenormalMode::Dynamic)
218406c3fb27SDimitry Andric     return true;
218506c3fb27SDimitry Andric   return false;
218606c3fb27SDimitry Andric }
218706c3fb27SDimitry Andric 
218806c3fb27SDimitry Andric static bool checkDenormMode(const Function &Caller, const Function &Callee) {
218906c3fb27SDimitry Andric   DenormalMode CallerMode = Caller.getDenormalModeRaw();
219006c3fb27SDimitry Andric   DenormalMode CalleeMode = Callee.getDenormalModeRaw();
219106c3fb27SDimitry Andric 
219206c3fb27SDimitry Andric   if (denormModeCompatible(CallerMode, CalleeMode)) {
219306c3fb27SDimitry Andric     DenormalMode CallerModeF32 = Caller.getDenormalModeF32Raw();
219406c3fb27SDimitry Andric     DenormalMode CalleeModeF32 = Callee.getDenormalModeF32Raw();
219506c3fb27SDimitry Andric     if (CallerModeF32 == DenormalMode::getInvalid())
219606c3fb27SDimitry Andric       CallerModeF32 = CallerMode;
219706c3fb27SDimitry Andric     if (CalleeModeF32 == DenormalMode::getInvalid())
219806c3fb27SDimitry Andric       CalleeModeF32 = CalleeMode;
219906c3fb27SDimitry Andric     return denormModeCompatible(CallerModeF32, CalleeModeF32);
220006c3fb27SDimitry Andric   }
220106c3fb27SDimitry Andric 
220206c3fb27SDimitry Andric   return false;
220306c3fb27SDimitry Andric }
220406c3fb27SDimitry Andric 
2205*0fca6ea1SDimitry Andric static bool checkStrictFP(const Function &Caller, const Function &Callee) {
2206*0fca6ea1SDimitry Andric   // Do not inline strictfp function into non-strictfp one. It would require
2207*0fca6ea1SDimitry Andric   // conversion of all FP operations in host function to constrained intrinsics.
2208*0fca6ea1SDimitry Andric   return !Callee.getAttributes().hasFnAttr(Attribute::StrictFP) ||
2209*0fca6ea1SDimitry Andric          Caller.getAttributes().hasFnAttr(Attribute::StrictFP);
2210*0fca6ea1SDimitry Andric }
2211*0fca6ea1SDimitry Andric 
22120b57cec5SDimitry Andric template<typename AttrClass>
22130b57cec5SDimitry Andric static bool isEqual(const Function &Caller, const Function &Callee) {
22140b57cec5SDimitry Andric   return Caller.getFnAttribute(AttrClass::getKind()) ==
22150b57cec5SDimitry Andric          Callee.getFnAttribute(AttrClass::getKind());
22160b57cec5SDimitry Andric }
22170b57cec5SDimitry Andric 
22184c2d3b02SDimitry Andric static bool isEqual(const Function &Caller, const Function &Callee,
22194c2d3b02SDimitry Andric                     const StringRef &AttrName) {
22204c2d3b02SDimitry Andric   return Caller.getFnAttribute(AttrName) == Callee.getFnAttribute(AttrName);
22214c2d3b02SDimitry Andric }
22224c2d3b02SDimitry Andric 
22230b57cec5SDimitry Andric /// Compute the logical AND of the attributes of the caller and the
22240b57cec5SDimitry Andric /// callee.
22250b57cec5SDimitry Andric ///
22260b57cec5SDimitry Andric /// This function sets the caller's attribute to false if the callee's attribute
22270b57cec5SDimitry Andric /// is false.
22280b57cec5SDimitry Andric template<typename AttrClass>
22290b57cec5SDimitry Andric static void setAND(Function &Caller, const Function &Callee) {
22300b57cec5SDimitry Andric   if (AttrClass::isSet(Caller, AttrClass::getKind()) &&
22310b57cec5SDimitry Andric       !AttrClass::isSet(Callee, AttrClass::getKind()))
22320b57cec5SDimitry Andric     AttrClass::set(Caller, AttrClass::getKind(), false);
22330b57cec5SDimitry Andric }
22340b57cec5SDimitry Andric 
22350b57cec5SDimitry Andric /// Compute the logical OR of the attributes of the caller and the
22360b57cec5SDimitry Andric /// callee.
22370b57cec5SDimitry Andric ///
22380b57cec5SDimitry Andric /// This function sets the caller's attribute to true if the callee's attribute
22390b57cec5SDimitry Andric /// is true.
22400b57cec5SDimitry Andric template<typename AttrClass>
22410b57cec5SDimitry Andric static void setOR(Function &Caller, const Function &Callee) {
22420b57cec5SDimitry Andric   if (!AttrClass::isSet(Caller, AttrClass::getKind()) &&
22430b57cec5SDimitry Andric       AttrClass::isSet(Callee, AttrClass::getKind()))
22440b57cec5SDimitry Andric     AttrClass::set(Caller, AttrClass::getKind(), true);
22450b57cec5SDimitry Andric }
22460b57cec5SDimitry Andric 
22470b57cec5SDimitry Andric /// If the inlined function had a higher stack protection level than the
22480b57cec5SDimitry Andric /// calling function, then bump up the caller's stack protection level.
22490b57cec5SDimitry Andric static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) {
225004eeddc0SDimitry Andric   // If the calling function has *no* stack protection level (e.g. it was built
225104eeddc0SDimitry Andric   // with Clang's -fno-stack-protector or no_stack_protector attribute), don't
225204eeddc0SDimitry Andric   // change it as that could change the program's semantics.
225304eeddc0SDimitry Andric   if (!Caller.hasStackProtectorFnAttr())
225404eeddc0SDimitry Andric     return;
225504eeddc0SDimitry Andric 
22560b57cec5SDimitry Andric   // If upgrading the SSP attribute, clear out the old SSP Attributes first.
22570b57cec5SDimitry Andric   // Having multiple SSP attributes doesn't actually hurt, but it adds useless
22580b57cec5SDimitry Andric   // clutter to the IR.
225904eeddc0SDimitry Andric   AttributeMask OldSSPAttr;
22600b57cec5SDimitry Andric   OldSSPAttr.addAttribute(Attribute::StackProtect)
22610b57cec5SDimitry Andric       .addAttribute(Attribute::StackProtectStrong)
22620b57cec5SDimitry Andric       .addAttribute(Attribute::StackProtectReq);
22630b57cec5SDimitry Andric 
22640b57cec5SDimitry Andric   if (Callee.hasFnAttribute(Attribute::StackProtectReq)) {
2265349cc55cSDimitry Andric     Caller.removeFnAttrs(OldSSPAttr);
22660b57cec5SDimitry Andric     Caller.addFnAttr(Attribute::StackProtectReq);
22670b57cec5SDimitry Andric   } else if (Callee.hasFnAttribute(Attribute::StackProtectStrong) &&
22680b57cec5SDimitry Andric              !Caller.hasFnAttribute(Attribute::StackProtectReq)) {
2269349cc55cSDimitry Andric     Caller.removeFnAttrs(OldSSPAttr);
22700b57cec5SDimitry Andric     Caller.addFnAttr(Attribute::StackProtectStrong);
22710b57cec5SDimitry Andric   } else if (Callee.hasFnAttribute(Attribute::StackProtect) &&
22720b57cec5SDimitry Andric              !Caller.hasFnAttribute(Attribute::StackProtectReq) &&
22730b57cec5SDimitry Andric              !Caller.hasFnAttribute(Attribute::StackProtectStrong))
22740b57cec5SDimitry Andric     Caller.addFnAttr(Attribute::StackProtect);
22750b57cec5SDimitry Andric }
22760b57cec5SDimitry Andric 
22770b57cec5SDimitry Andric /// If the inlined function required stack probes, then ensure that
22780b57cec5SDimitry Andric /// the calling function has those too.
22790b57cec5SDimitry Andric static void adjustCallerStackProbes(Function &Caller, const Function &Callee) {
22800b57cec5SDimitry Andric   if (!Caller.hasFnAttribute("probe-stack") &&
22810b57cec5SDimitry Andric       Callee.hasFnAttribute("probe-stack")) {
22820b57cec5SDimitry Andric     Caller.addFnAttr(Callee.getFnAttribute("probe-stack"));
22830b57cec5SDimitry Andric   }
22840b57cec5SDimitry Andric }
22850b57cec5SDimitry Andric 
22860b57cec5SDimitry Andric /// If the inlined function defines the size of guard region
22870b57cec5SDimitry Andric /// on the stack, then ensure that the calling function defines a guard region
22880b57cec5SDimitry Andric /// that is no larger.
22890b57cec5SDimitry Andric static void
22900b57cec5SDimitry Andric adjustCallerStackProbeSize(Function &Caller, const Function &Callee) {
2291e8d8bef9SDimitry Andric   Attribute CalleeAttr = Callee.getFnAttribute("stack-probe-size");
2292e8d8bef9SDimitry Andric   if (CalleeAttr.isValid()) {
2293e8d8bef9SDimitry Andric     Attribute CallerAttr = Caller.getFnAttribute("stack-probe-size");
2294e8d8bef9SDimitry Andric     if (CallerAttr.isValid()) {
2295e8d8bef9SDimitry Andric       uint64_t CallerStackProbeSize, CalleeStackProbeSize;
2296e8d8bef9SDimitry Andric       CallerAttr.getValueAsString().getAsInteger(0, CallerStackProbeSize);
2297e8d8bef9SDimitry Andric       CalleeAttr.getValueAsString().getAsInteger(0, CalleeStackProbeSize);
2298e8d8bef9SDimitry Andric 
22990b57cec5SDimitry Andric       if (CallerStackProbeSize > CalleeStackProbeSize) {
2300e8d8bef9SDimitry Andric         Caller.addFnAttr(CalleeAttr);
23010b57cec5SDimitry Andric       }
23020b57cec5SDimitry Andric     } else {
2303e8d8bef9SDimitry Andric       Caller.addFnAttr(CalleeAttr);
23040b57cec5SDimitry Andric     }
23050b57cec5SDimitry Andric   }
23060b57cec5SDimitry Andric }
23070b57cec5SDimitry Andric 
23080b57cec5SDimitry Andric /// If the inlined function defines a min legal vector width, then ensure
23090b57cec5SDimitry Andric /// the calling function has the same or larger min legal vector width. If the
23100b57cec5SDimitry Andric /// caller has the attribute, but the callee doesn't, we need to remove the
23110b57cec5SDimitry Andric /// attribute from the caller since we can't make any guarantees about the
23120b57cec5SDimitry Andric /// caller's requirements.
23130b57cec5SDimitry Andric /// This function is called after the inlining decision has been made so we have
23140b57cec5SDimitry Andric /// to merge the attribute this way. Heuristics that would use
23150b57cec5SDimitry Andric /// min-legal-vector-width to determine inline compatibility would need to be
23160b57cec5SDimitry Andric /// handled as part of inline cost analysis.
23170b57cec5SDimitry Andric static void
23180b57cec5SDimitry Andric adjustMinLegalVectorWidth(Function &Caller, const Function &Callee) {
2319e8d8bef9SDimitry Andric   Attribute CallerAttr = Caller.getFnAttribute("min-legal-vector-width");
2320e8d8bef9SDimitry Andric   if (CallerAttr.isValid()) {
2321e8d8bef9SDimitry Andric     Attribute CalleeAttr = Callee.getFnAttribute("min-legal-vector-width");
2322e8d8bef9SDimitry Andric     if (CalleeAttr.isValid()) {
2323e8d8bef9SDimitry Andric       uint64_t CallerVectorWidth, CalleeVectorWidth;
2324e8d8bef9SDimitry Andric       CallerAttr.getValueAsString().getAsInteger(0, CallerVectorWidth);
2325e8d8bef9SDimitry Andric       CalleeAttr.getValueAsString().getAsInteger(0, CalleeVectorWidth);
23260b57cec5SDimitry Andric       if (CallerVectorWidth < CalleeVectorWidth)
2327e8d8bef9SDimitry Andric         Caller.addFnAttr(CalleeAttr);
23280b57cec5SDimitry Andric     } else {
23290b57cec5SDimitry Andric       // If the callee doesn't have the attribute then we don't know anything
23300b57cec5SDimitry Andric       // and must drop the attribute from the caller.
23310b57cec5SDimitry Andric       Caller.removeFnAttr("min-legal-vector-width");
23320b57cec5SDimitry Andric     }
23330b57cec5SDimitry Andric   }
23340b57cec5SDimitry Andric }
23350b57cec5SDimitry Andric 
23365ffd83dbSDimitry Andric /// If the inlined function has null_pointer_is_valid attribute,
23370b57cec5SDimitry Andric /// set this attribute in the caller post inlining.
23380b57cec5SDimitry Andric static void
23390b57cec5SDimitry Andric adjustNullPointerValidAttr(Function &Caller, const Function &Callee) {
23400b57cec5SDimitry Andric   if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) {
23415ffd83dbSDimitry Andric     Caller.addFnAttr(Attribute::NullPointerIsValid);
23420b57cec5SDimitry Andric   }
23430b57cec5SDimitry Andric }
23440b57cec5SDimitry Andric 
23455ffd83dbSDimitry Andric struct EnumAttr {
23465ffd83dbSDimitry Andric   static bool isSet(const Function &Fn,
23475ffd83dbSDimitry Andric                     Attribute::AttrKind Kind) {
23485ffd83dbSDimitry Andric     return Fn.hasFnAttribute(Kind);
23495ffd83dbSDimitry Andric   }
23505ffd83dbSDimitry Andric 
23515ffd83dbSDimitry Andric   static void set(Function &Fn,
23525ffd83dbSDimitry Andric                   Attribute::AttrKind Kind, bool Val) {
23535ffd83dbSDimitry Andric     if (Val)
23545ffd83dbSDimitry Andric       Fn.addFnAttr(Kind);
23555ffd83dbSDimitry Andric     else
23565ffd83dbSDimitry Andric       Fn.removeFnAttr(Kind);
23575ffd83dbSDimitry Andric   }
23585ffd83dbSDimitry Andric };
23595ffd83dbSDimitry Andric 
23605ffd83dbSDimitry Andric struct StrBoolAttr {
23615ffd83dbSDimitry Andric   static bool isSet(const Function &Fn,
23625ffd83dbSDimitry Andric                     StringRef Kind) {
23635ffd83dbSDimitry Andric     auto A = Fn.getFnAttribute(Kind);
2364*0fca6ea1SDimitry Andric     return A.getValueAsString() == "true";
23655ffd83dbSDimitry Andric   }
23665ffd83dbSDimitry Andric 
23675ffd83dbSDimitry Andric   static void set(Function &Fn,
23685ffd83dbSDimitry Andric                   StringRef Kind, bool Val) {
23695ffd83dbSDimitry Andric     Fn.addFnAttr(Kind, Val ? "true" : "false");
23705ffd83dbSDimitry Andric   }
23715ffd83dbSDimitry Andric };
23725ffd83dbSDimitry Andric 
23735ffd83dbSDimitry Andric #define GET_ATTR_NAMES
23745ffd83dbSDimitry Andric #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME)                                \
23755ffd83dbSDimitry Andric   struct ENUM_NAME##Attr : EnumAttr {                                          \
23765ffd83dbSDimitry Andric     static enum Attribute::AttrKind getKind() {                                \
23775ffd83dbSDimitry Andric       return llvm::Attribute::ENUM_NAME;                                       \
23785ffd83dbSDimitry Andric     }                                                                          \
23795ffd83dbSDimitry Andric   };
23805ffd83dbSDimitry Andric #define ATTRIBUTE_STRBOOL(ENUM_NAME, DISPLAY_NAME)                             \
23815ffd83dbSDimitry Andric   struct ENUM_NAME##Attr : StrBoolAttr {                                       \
23825ffd83dbSDimitry Andric     static StringRef getKind() { return #DISPLAY_NAME; }                       \
23835ffd83dbSDimitry Andric   };
23845ffd83dbSDimitry Andric #include "llvm/IR/Attributes.inc"
23855ffd83dbSDimitry Andric 
23860b57cec5SDimitry Andric #define GET_ATTR_COMPAT_FUNC
23875ffd83dbSDimitry Andric #include "llvm/IR/Attributes.inc"
23880b57cec5SDimitry Andric 
23890b57cec5SDimitry Andric bool AttributeFuncs::areInlineCompatible(const Function &Caller,
23900b57cec5SDimitry Andric                                          const Function &Callee) {
23910b57cec5SDimitry Andric   return hasCompatibleFnAttrs(Caller, Callee);
23920b57cec5SDimitry Andric }
23930b57cec5SDimitry Andric 
2394e8d8bef9SDimitry Andric bool AttributeFuncs::areOutlineCompatible(const Function &A,
2395e8d8bef9SDimitry Andric                                           const Function &B) {
2396e8d8bef9SDimitry Andric   return hasCompatibleFnAttrs(A, B);
2397e8d8bef9SDimitry Andric }
2398e8d8bef9SDimitry Andric 
23990b57cec5SDimitry Andric void AttributeFuncs::mergeAttributesForInlining(Function &Caller,
24000b57cec5SDimitry Andric                                                 const Function &Callee) {
24010b57cec5SDimitry Andric   mergeFnAttrs(Caller, Callee);
24020b57cec5SDimitry Andric }
2403e8d8bef9SDimitry Andric 
2404e8d8bef9SDimitry Andric void AttributeFuncs::mergeAttributesForOutlining(Function &Base,
2405e8d8bef9SDimitry Andric                                                 const Function &ToMerge) {
2406e8d8bef9SDimitry Andric 
2407e8d8bef9SDimitry Andric   // We merge functions so that they meet the most general case.
2408e8d8bef9SDimitry Andric   // For example, if the NoNansFPMathAttr is set in one function, but not in
2409e8d8bef9SDimitry Andric   // the other, in the merged function we can say that the NoNansFPMathAttr
2410e8d8bef9SDimitry Andric   // is not set.
2411e8d8bef9SDimitry Andric   // However if we have the SpeculativeLoadHardeningAttr set true in one
2412e8d8bef9SDimitry Andric   // function, but not the other, we make sure that the function retains
2413e8d8bef9SDimitry Andric   // that aspect in the merged function.
2414e8d8bef9SDimitry Andric   mergeFnAttrs(Base, ToMerge);
2415e8d8bef9SDimitry Andric }
241681ad6265SDimitry Andric 
241781ad6265SDimitry Andric void AttributeFuncs::updateMinLegalVectorWidthAttr(Function &Fn,
241881ad6265SDimitry Andric                                                    uint64_t Width) {
241981ad6265SDimitry Andric   Attribute Attr = Fn.getFnAttribute("min-legal-vector-width");
242081ad6265SDimitry Andric   if (Attr.isValid()) {
242181ad6265SDimitry Andric     uint64_t OldWidth;
242281ad6265SDimitry Andric     Attr.getValueAsString().getAsInteger(0, OldWidth);
242381ad6265SDimitry Andric     if (Width > OldWidth)
242481ad6265SDimitry Andric       Fn.addFnAttr("min-legal-vector-width", llvm::utostr(Width));
242581ad6265SDimitry Andric   }
242681ad6265SDimitry Andric }
2427