| //===- Attributes.cpp - Implement AttributesList --------------------------===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 | // | 
 | // \file | 
 | // This file implements the Attribute, AttributeImpl, AttrBuilder, | 
 | // AttributeListImpl, and AttributeList classes. | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "llvm/IR/Attributes.h" | 
 | #include "AttributeImpl.h" | 
 | #include "LLVMContextImpl.h" | 
 | #include "llvm/ADT/ArrayRef.h" | 
 | #include "llvm/ADT/FoldingSet.h" | 
 | #include "llvm/ADT/STLExtras.h" | 
 | #include "llvm/ADT/SmallVector.h" | 
 | #include "llvm/ADT/StringExtras.h" | 
 | #include "llvm/ADT/StringRef.h" | 
 | #include "llvm/ADT/StringSwitch.h" | 
 | #include "llvm/Config/llvm-config.h" | 
 | #include "llvm/IR/AttributeMask.h" | 
 | #include "llvm/IR/Function.h" | 
 | #include "llvm/IR/LLVMContext.h" | 
 | #include "llvm/IR/Type.h" | 
 | #include "llvm/Support/Compiler.h" | 
 | #include "llvm/Support/ErrorHandling.h" | 
 | #include "llvm/Support/ModRef.h" | 
 | #include "llvm/Support/raw_ostream.h" | 
 | #include <algorithm> | 
 | #include <cassert> | 
 | #include <cstddef> | 
 | #include <cstdint> | 
 | #include <limits> | 
 | #include <optional> | 
 | #include <string> | 
 | #include <tuple> | 
 | #include <utility> | 
 |  | 
 | using namespace llvm; | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Attribute Construction Methods | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | // allocsize has two integer arguments, but because they're both 32 bits, we can | 
 | // pack them into one 64-bit value, at the cost of making said value | 
 | // nonsensical. | 
 | // | 
 | // In order to do this, we need to reserve one value of the second (optional) | 
 | // allocsize argument to signify "not present." | 
 | static const unsigned AllocSizeNumElemsNotPresent = -1; | 
 |  | 
 | static uint64_t packAllocSizeArgs(unsigned ElemSizeArg, | 
 |                                   const std::optional<unsigned> &NumElemsArg) { | 
 |   assert((!NumElemsArg || *NumElemsArg != AllocSizeNumElemsNotPresent) && | 
 |          "Attempting to pack a reserved value"); | 
 |  | 
 |   return uint64_t(ElemSizeArg) << 32 | | 
 |          NumElemsArg.value_or(AllocSizeNumElemsNotPresent); | 
 | } | 
 |  | 
 | static std::pair<unsigned, std::optional<unsigned>> | 
 | unpackAllocSizeArgs(uint64_t Num) { | 
 |   unsigned NumElems = Num & std::numeric_limits<unsigned>::max(); | 
 |   unsigned ElemSizeArg = Num >> 32; | 
 |  | 
 |   std::optional<unsigned> NumElemsArg; | 
 |   if (NumElems != AllocSizeNumElemsNotPresent) | 
 |     NumElemsArg = NumElems; | 
 |   return std::make_pair(ElemSizeArg, NumElemsArg); | 
 | } | 
 |  | 
 | static uint64_t packVScaleRangeArgs(unsigned MinValue, | 
 |                                     std::optional<unsigned> MaxValue) { | 
 |   return uint64_t(MinValue) << 32 | MaxValue.value_or(0); | 
 | } | 
 |  | 
 | static std::pair<unsigned, std::optional<unsigned>> | 
 | unpackVScaleRangeArgs(uint64_t Value) { | 
 |   unsigned MaxValue = Value & std::numeric_limits<unsigned>::max(); | 
 |   unsigned MinValue = Value >> 32; | 
 |  | 
 |   return std::make_pair(MinValue, | 
 |                         MaxValue > 0 ? MaxValue : std::optional<unsigned>()); | 
 | } | 
 |  | 
 | Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, | 
 |                          uint64_t Val) { | 
 |   bool IsIntAttr = Attribute::isIntAttrKind(Kind); | 
 |   assert((IsIntAttr || Attribute::isEnumAttrKind(Kind)) && | 
 |          "Not an enum or int attribute"); | 
 |  | 
 |   LLVMContextImpl *pImpl = Context.pImpl; | 
 |   FoldingSetNodeID ID; | 
 |   ID.AddInteger(Kind); | 
 |   if (IsIntAttr) | 
 |     ID.AddInteger(Val); | 
 |   else | 
 |     assert(Val == 0 && "Value must be zero for enum attributes"); | 
 |  | 
 |   void *InsertPoint; | 
 |   AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); | 
 |  | 
 |   if (!PA) { | 
 |     // If we didn't find any existing attributes of the same shape then create a | 
 |     // new one and insert it. | 
 |     if (!IsIntAttr) | 
 |       PA = new (pImpl->Alloc) EnumAttributeImpl(Kind); | 
 |     else | 
 |       PA = new (pImpl->Alloc) IntAttributeImpl(Kind, Val); | 
 |     pImpl->AttrsSet.InsertNode(PA, InsertPoint); | 
 |   } | 
 |  | 
 |   // Return the Attribute that we found or created. | 
 |   return Attribute(PA); | 
 | } | 
 |  | 
 | Attribute Attribute::get(LLVMContext &Context, StringRef Kind, StringRef Val) { | 
 |   LLVMContextImpl *pImpl = Context.pImpl; | 
 |   FoldingSetNodeID ID; | 
 |   ID.AddString(Kind); | 
 |   if (!Val.empty()) ID.AddString(Val); | 
 |  | 
 |   void *InsertPoint; | 
 |   AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); | 
 |  | 
 |   if (!PA) { | 
 |     // If we didn't find any existing attributes of the same shape then create a | 
 |     // new one and insert it. | 
 |     void *Mem = | 
 |         pImpl->Alloc.Allocate(StringAttributeImpl::totalSizeToAlloc(Kind, Val), | 
 |                               alignof(StringAttributeImpl)); | 
 |     PA = new (Mem) StringAttributeImpl(Kind, Val); | 
 |     pImpl->AttrsSet.InsertNode(PA, InsertPoint); | 
 |   } | 
 |  | 
 |   // Return the Attribute that we found or created. | 
 |   return Attribute(PA); | 
 | } | 
 |  | 
 | Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind, | 
 |                          Type *Ty) { | 
 |   assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute"); | 
 |   LLVMContextImpl *pImpl = Context.pImpl; | 
 |   FoldingSetNodeID ID; | 
 |   ID.AddInteger(Kind); | 
 |   ID.AddPointer(Ty); | 
 |  | 
 |   void *InsertPoint; | 
 |   AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint); | 
 |  | 
 |   if (!PA) { | 
 |     // If we didn't find any existing attributes of the same shape then create a | 
 |     // new one and insert it. | 
 |     PA = new (pImpl->Alloc) TypeAttributeImpl(Kind, Ty); | 
 |     pImpl->AttrsSet.InsertNode(PA, InsertPoint); | 
 |   } | 
 |  | 
 |   // Return the Attribute that we found or created. | 
 |   return Attribute(PA); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithAlignment(LLVMContext &Context, Align A) { | 
 |   assert(A <= llvm::Value::MaximumAlignment && "Alignment too large."); | 
 |   return get(Context, Alignment, A.value()); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithStackAlignment(LLVMContext &Context, Align A) { | 
 |   assert(A <= 0x100 && "Alignment too large."); | 
 |   return get(Context, StackAlignment, A.value()); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context, | 
 |                                                 uint64_t Bytes) { | 
 |   assert(Bytes && "Bytes must be non-zero."); | 
 |   return get(Context, Dereferenceable, Bytes); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context, | 
 |                                                        uint64_t Bytes) { | 
 |   assert(Bytes && "Bytes must be non-zero."); | 
 |   return get(Context, DereferenceableOrNull, Bytes); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) { | 
 |   return get(Context, ByVal, Ty); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithStructRetType(LLVMContext &Context, Type *Ty) { | 
 |   return get(Context, StructRet, Ty); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithByRefType(LLVMContext &Context, Type *Ty) { | 
 |   return get(Context, ByRef, Ty); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithPreallocatedType(LLVMContext &Context, Type *Ty) { | 
 |   return get(Context, Preallocated, Ty); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithInAllocaType(LLVMContext &Context, Type *Ty) { | 
 |   return get(Context, InAlloca, Ty); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithUWTableKind(LLVMContext &Context, | 
 |                                         UWTableKind Kind) { | 
 |   return get(Context, UWTable, uint64_t(Kind)); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithMemoryEffects(LLVMContext &Context, | 
 |                                           MemoryEffects ME) { | 
 |   return get(Context, Memory, ME.toIntValue()); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithNoFPClass(LLVMContext &Context, | 
 |                                       FPClassTest ClassMask) { | 
 |   return get(Context, NoFPClass, ClassMask); | 
 | } | 
 |  | 
 | Attribute | 
 | Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg, | 
 |                                 const std::optional<unsigned> &NumElemsArg) { | 
 |   assert(!(ElemSizeArg == 0 && NumElemsArg && *NumElemsArg == 0) && | 
 |          "Invalid allocsize arguments -- given allocsize(0, 0)"); | 
 |   return get(Context, AllocSize, packAllocSizeArgs(ElemSizeArg, NumElemsArg)); | 
 | } | 
 |  | 
 | Attribute Attribute::getWithVScaleRangeArgs(LLVMContext &Context, | 
 |                                             unsigned MinValue, | 
 |                                             unsigned MaxValue) { | 
 |   return get(Context, VScaleRange, packVScaleRangeArgs(MinValue, MaxValue)); | 
 | } | 
 |  | 
 | Attribute::AttrKind Attribute::getAttrKindFromName(StringRef AttrName) { | 
 |   return StringSwitch<Attribute::AttrKind>(AttrName) | 
 | #define GET_ATTR_NAMES | 
 | #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME)                                \ | 
 |   .Case(#DISPLAY_NAME, Attribute::ENUM_NAME) | 
 | #include "llvm/IR/Attributes.inc" | 
 |       .Default(Attribute::None); | 
 | } | 
 |  | 
 | StringRef Attribute::getNameFromAttrKind(Attribute::AttrKind AttrKind) { | 
 |   switch (AttrKind) { | 
 | #define GET_ATTR_NAMES | 
 | #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME)                                \ | 
 |   case Attribute::ENUM_NAME:                                                   \ | 
 |     return #DISPLAY_NAME; | 
 | #include "llvm/IR/Attributes.inc" | 
 |   case Attribute::None: | 
 |     return "none"; | 
 |   default: | 
 |     llvm_unreachable("invalid Kind"); | 
 |   } | 
 | } | 
 |  | 
 | bool Attribute::isExistingAttribute(StringRef Name) { | 
 |   return StringSwitch<bool>(Name) | 
 | #define GET_ATTR_NAMES | 
 | #define ATTRIBUTE_ALL(ENUM_NAME, DISPLAY_NAME) .Case(#DISPLAY_NAME, true) | 
 | #include "llvm/IR/Attributes.inc" | 
 |       .Default(false); | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // Attribute Accessor Methods | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | bool Attribute::isEnumAttribute() const { | 
 |   return pImpl && pImpl->isEnumAttribute(); | 
 | } | 
 |  | 
 | bool Attribute::isIntAttribute() const { | 
 |   return pImpl && pImpl->isIntAttribute(); | 
 | } | 
 |  | 
 | bool Attribute::isStringAttribute() const { | 
 |   return pImpl && pImpl->isStringAttribute(); | 
 | } | 
 |  | 
 | bool Attribute::isTypeAttribute() const { | 
 |   return pImpl && pImpl->isTypeAttribute(); | 
 | } | 
 |  | 
 | Attribute::AttrKind Attribute::getKindAsEnum() const { | 
 |   if (!pImpl) return None; | 
 |   assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute()) && | 
 |          "Invalid attribute type to get the kind as an enum!"); | 
 |   return pImpl->getKindAsEnum(); | 
 | } | 
 |  | 
 | uint64_t Attribute::getValueAsInt() const { | 
 |   if (!pImpl) return 0; | 
 |   assert(isIntAttribute() && | 
 |          "Expected the attribute to be an integer attribute!"); | 
 |   return pImpl->getValueAsInt(); | 
 | } | 
 |  | 
 | bool Attribute::getValueAsBool() const { | 
 |   if (!pImpl) return false; | 
 |   assert(isStringAttribute() && | 
 |          "Expected the attribute to be a string attribute!"); | 
 |   return pImpl->getValueAsBool(); | 
 | } | 
 |  | 
 | StringRef Attribute::getKindAsString() const { | 
 |   if (!pImpl) return {}; | 
 |   assert(isStringAttribute() && | 
 |          "Invalid attribute type to get the kind as a string!"); | 
 |   return pImpl->getKindAsString(); | 
 | } | 
 |  | 
 | StringRef Attribute::getValueAsString() const { | 
 |   if (!pImpl) return {}; | 
 |   assert(isStringAttribute() && | 
 |          "Invalid attribute type to get the value as a string!"); | 
 |   return pImpl->getValueAsString(); | 
 | } | 
 |  | 
 | Type *Attribute::getValueAsType() const { | 
 |   if (!pImpl) return {}; | 
 |   assert(isTypeAttribute() && | 
 |          "Invalid attribute type to get the value as a type!"); | 
 |   return pImpl->getValueAsType(); | 
 | } | 
 |  | 
 |  | 
 | bool Attribute::hasAttribute(AttrKind Kind) const { | 
 |   return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None); | 
 | } | 
 |  | 
 | bool Attribute::hasAttribute(StringRef Kind) const { | 
 |   if (!isStringAttribute()) return false; | 
 |   return pImpl && pImpl->hasAttribute(Kind); | 
 | } | 
 |  | 
 | MaybeAlign Attribute::getAlignment() const { | 
 |   assert(hasAttribute(Attribute::Alignment) && | 
 |          "Trying to get alignment from non-alignment attribute!"); | 
 |   return MaybeAlign(pImpl->getValueAsInt()); | 
 | } | 
 |  | 
 | MaybeAlign Attribute::getStackAlignment() const { | 
 |   assert(hasAttribute(Attribute::StackAlignment) && | 
 |          "Trying to get alignment from non-alignment attribute!"); | 
 |   return MaybeAlign(pImpl->getValueAsInt()); | 
 | } | 
 |  | 
 | uint64_t Attribute::getDereferenceableBytes() const { | 
 |   assert(hasAttribute(Attribute::Dereferenceable) && | 
 |          "Trying to get dereferenceable bytes from " | 
 |          "non-dereferenceable attribute!"); | 
 |   return pImpl->getValueAsInt(); | 
 | } | 
 |  | 
 | uint64_t Attribute::getDereferenceableOrNullBytes() const { | 
 |   assert(hasAttribute(Attribute::DereferenceableOrNull) && | 
 |          "Trying to get dereferenceable bytes from " | 
 |          "non-dereferenceable attribute!"); | 
 |   return pImpl->getValueAsInt(); | 
 | } | 
 |  | 
 | std::pair<unsigned, std::optional<unsigned>> | 
 | Attribute::getAllocSizeArgs() const { | 
 |   assert(hasAttribute(Attribute::AllocSize) && | 
 |          "Trying to get allocsize args from non-allocsize attribute"); | 
 |   return unpackAllocSizeArgs(pImpl->getValueAsInt()); | 
 | } | 
 |  | 
 | unsigned Attribute::getVScaleRangeMin() const { | 
 |   assert(hasAttribute(Attribute::VScaleRange) && | 
 |          "Trying to get vscale args from non-vscale attribute"); | 
 |   return unpackVScaleRangeArgs(pImpl->getValueAsInt()).first; | 
 | } | 
 |  | 
 | std::optional<unsigned> Attribute::getVScaleRangeMax() const { | 
 |   assert(hasAttribute(Attribute::VScaleRange) && | 
 |          "Trying to get vscale args from non-vscale attribute"); | 
 |   return unpackVScaleRangeArgs(pImpl->getValueAsInt()).second; | 
 | } | 
 |  | 
 | UWTableKind Attribute::getUWTableKind() const { | 
 |   assert(hasAttribute(Attribute::UWTable) && | 
 |          "Trying to get unwind table kind from non-uwtable attribute"); | 
 |   return UWTableKind(pImpl->getValueAsInt()); | 
 | } | 
 |  | 
 | AllocFnKind Attribute::getAllocKind() const { | 
 |   assert(hasAttribute(Attribute::AllocKind) && | 
 |          "Trying to get allockind value from non-allockind attribute"); | 
 |   return AllocFnKind(pImpl->getValueAsInt()); | 
 | } | 
 |  | 
 | MemoryEffects Attribute::getMemoryEffects() const { | 
 |   assert(hasAttribute(Attribute::Memory) && | 
 |          "Can only call getMemoryEffects() on memory attribute"); | 
 |   return MemoryEffects::createFromIntValue(pImpl->getValueAsInt()); | 
 | } | 
 |  | 
 | FPClassTest Attribute::getNoFPClass() const { | 
 |   assert(hasAttribute(Attribute::NoFPClass) && | 
 |          "Can only call getNoFPClass() on nofpclass attribute"); | 
 |   return static_cast<FPClassTest>(pImpl->getValueAsInt()); | 
 | } | 
 |  | 
 | static const char *getModRefStr(ModRefInfo MR) { | 
 |   switch (MR) { | 
 |   case ModRefInfo::NoModRef: | 
 |     return "none"; | 
 |   case ModRefInfo::Ref: | 
 |     return "read"; | 
 |   case ModRefInfo::Mod: | 
 |     return "write"; | 
 |   case ModRefInfo::ModRef: | 
 |     return "readwrite"; | 
 |   } | 
 |   llvm_unreachable("Invalid ModRefInfo"); | 
 | } | 
 |  | 
 | std::string Attribute::getAsString(bool InAttrGrp) const { | 
 |   if (!pImpl) return {}; | 
 |  | 
 |   if (isEnumAttribute()) | 
 |     return getNameFromAttrKind(getKindAsEnum()).str(); | 
 |  | 
 |   if (isTypeAttribute()) { | 
 |     std::string Result = getNameFromAttrKind(getKindAsEnum()).str(); | 
 |     Result += '('; | 
 |     raw_string_ostream OS(Result); | 
 |     getValueAsType()->print(OS, false, true); | 
 |     OS.flush(); | 
 |     Result += ')'; | 
 |     return Result; | 
 |   } | 
 |  | 
 |   // FIXME: These should be output like this: | 
 |   // | 
 |   //   align=4 | 
 |   //   alignstack=8 | 
 |   // | 
 |   if (hasAttribute(Attribute::Alignment)) | 
 |     return (InAttrGrp ? "align=" + Twine(getValueAsInt()) | 
 |                       : "align " + Twine(getValueAsInt())) | 
 |         .str(); | 
 |  | 
 |   auto AttrWithBytesToString = [&](const char *Name) { | 
 |     return (InAttrGrp ? Name + ("=" + Twine(getValueAsInt())) | 
 |                       : Name + ("(" + Twine(getValueAsInt())) + ")") | 
 |         .str(); | 
 |   }; | 
 |  | 
 |   if (hasAttribute(Attribute::StackAlignment)) | 
 |     return AttrWithBytesToString("alignstack"); | 
 |  | 
 |   if (hasAttribute(Attribute::Dereferenceable)) | 
 |     return AttrWithBytesToString("dereferenceable"); | 
 |  | 
 |   if (hasAttribute(Attribute::DereferenceableOrNull)) | 
 |     return AttrWithBytesToString("dereferenceable_or_null"); | 
 |  | 
 |   if (hasAttribute(Attribute::AllocSize)) { | 
 |     unsigned ElemSize; | 
 |     std::optional<unsigned> NumElems; | 
 |     std::tie(ElemSize, NumElems) = getAllocSizeArgs(); | 
 |  | 
 |     return (NumElems | 
 |                 ? "allocsize(" + Twine(ElemSize) + "," + Twine(*NumElems) + ")" | 
 |                 : "allocsize(" + Twine(ElemSize) + ")") | 
 |         .str(); | 
 |   } | 
 |  | 
 |   if (hasAttribute(Attribute::VScaleRange)) { | 
 |     unsigned MinValue = getVScaleRangeMin(); | 
 |     std::optional<unsigned> MaxValue = getVScaleRangeMax(); | 
 |     return ("vscale_range(" + Twine(MinValue) + "," + | 
 |             Twine(MaxValue.value_or(0)) + ")") | 
 |         .str(); | 
 |   } | 
 |  | 
 |   if (hasAttribute(Attribute::UWTable)) { | 
 |     UWTableKind Kind = getUWTableKind(); | 
 |     if (Kind != UWTableKind::None) { | 
 |       return Kind == UWTableKind::Default | 
 |                  ? "uwtable" | 
 |                  : ("uwtable(" + | 
 |                     Twine(Kind == UWTableKind::Sync ? "sync" : "async") + ")") | 
 |                        .str(); | 
 |     } | 
 |   } | 
 |  | 
 |   if (hasAttribute(Attribute::AllocKind)) { | 
 |     AllocFnKind Kind = getAllocKind(); | 
 |     SmallVector<StringRef> parts; | 
 |     if ((Kind & AllocFnKind::Alloc) != AllocFnKind::Unknown) | 
 |       parts.push_back("alloc"); | 
 |     if ((Kind & AllocFnKind::Realloc) != AllocFnKind::Unknown) | 
 |       parts.push_back("realloc"); | 
 |     if ((Kind & AllocFnKind::Free) != AllocFnKind::Unknown) | 
 |       parts.push_back("free"); | 
 |     if ((Kind & AllocFnKind::Uninitialized) != AllocFnKind::Unknown) | 
 |       parts.push_back("uninitialized"); | 
 |     if ((Kind & AllocFnKind::Zeroed) != AllocFnKind::Unknown) | 
 |       parts.push_back("zeroed"); | 
 |     if ((Kind & AllocFnKind::Aligned) != AllocFnKind::Unknown) | 
 |       parts.push_back("aligned"); | 
 |     return ("allockind(\"" + | 
 |             Twine(llvm::join(parts.begin(), parts.end(), ",")) + "\")") | 
 |         .str(); | 
 |   } | 
 |  | 
 |   if (hasAttribute(Attribute::Memory)) { | 
 |     std::string Result; | 
 |     raw_string_ostream OS(Result); | 
 |     bool First = true; | 
 |     OS << "memory("; | 
 |  | 
 |     MemoryEffects ME = getMemoryEffects(); | 
 |  | 
 |     // Print access kind for "other" as the default access kind. This way it | 
 |     // will apply to any new location kinds that get split out of "other". | 
 |     ModRefInfo OtherMR = ME.getModRef(IRMemLocation::Other); | 
 |     if (OtherMR != ModRefInfo::NoModRef || ME.getModRef() == OtherMR) { | 
 |       First = false; | 
 |       OS << getModRefStr(OtherMR); | 
 |     } | 
 |  | 
 |     for (auto Loc : MemoryEffects::locations()) { | 
 |       ModRefInfo MR = ME.getModRef(Loc); | 
 |       if (MR == OtherMR) | 
 |         continue; | 
 |  | 
 |       if (!First) | 
 |         OS << ", "; | 
 |       First = false; | 
 |  | 
 |       switch (Loc) { | 
 |       case IRMemLocation::ArgMem: | 
 |         OS << "argmem: "; | 
 |         break; | 
 |       case IRMemLocation::InaccessibleMem: | 
 |         OS << "inaccessiblemem: "; | 
 |         break; | 
 |       case IRMemLocation::Other: | 
 |         llvm_unreachable("This is represented as the default access kind"); | 
 |       } | 
 |       OS << getModRefStr(MR); | 
 |     } | 
 |     OS << ")"; | 
 |     OS.flush(); | 
 |     return Result; | 
 |   } | 
 |  | 
 |   if (hasAttribute(Attribute::NoFPClass)) { | 
 |     std::string Result = "nofpclass"; | 
 |     raw_string_ostream OS(Result); | 
 |     OS << getNoFPClass(); | 
 |     return Result; | 
 |   } | 
 |  | 
 |   // Convert target-dependent attributes to strings of the form: | 
 |   // | 
 |   //   "kind" | 
 |   //   "kind" = "value" | 
 |   // | 
 |   if (isStringAttribute()) { | 
 |     std::string Result; | 
 |     { | 
 |       raw_string_ostream OS(Result); | 
 |       OS << '"' << getKindAsString() << '"'; | 
 |  | 
 |       // Since some attribute strings contain special characters that cannot be | 
 |       // printable, those have to be escaped to make the attribute value | 
 |       // printable as is.  e.g. "\01__gnu_mcount_nc" | 
 |       const auto &AttrVal = pImpl->getValueAsString(); | 
 |       if (!AttrVal.empty()) { | 
 |         OS << "=\""; | 
 |         printEscapedString(AttrVal, OS); | 
 |         OS << "\""; | 
 |       } | 
 |     } | 
 |     return Result; | 
 |   } | 
 |  | 
 |   llvm_unreachable("Unknown attribute"); | 
 | } | 
 |  | 
 | bool Attribute::hasParentContext(LLVMContext &C) const { | 
 |   assert(isValid() && "invalid Attribute doesn't refer to any context"); | 
 |   FoldingSetNodeID ID; | 
 |   pImpl->Profile(ID); | 
 |   void *Unused; | 
 |   return C.pImpl->AttrsSet.FindNodeOrInsertPos(ID, Unused) == pImpl; | 
 | } | 
 |  | 
 | bool Attribute::operator<(Attribute A) const { | 
 |   if (!pImpl && !A.pImpl) return false; | 
 |   if (!pImpl) return true; | 
 |   if (!A.pImpl) return false; | 
 |   return *pImpl < *A.pImpl; | 
 | } | 
 |  | 
 | void Attribute::Profile(FoldingSetNodeID &ID) const { | 
 |   ID.AddPointer(pImpl); | 
 | } | 
 |  | 
 | enum AttributeProperty { | 
 |   FnAttr = (1 << 0), | 
 |   ParamAttr = (1 << 1), | 
 |   RetAttr = (1 << 2), | 
 | }; | 
 |  | 
 | #define GET_ATTR_PROP_TABLE | 
 | #include "llvm/IR/Attributes.inc" | 
 |  | 
 | static bool hasAttributeProperty(Attribute::AttrKind Kind, | 
 |                                  AttributeProperty Prop) { | 
 |   unsigned Index = Kind - 1; | 
 |   assert(Index < std::size(AttrPropTable) && "Invalid attribute kind"); | 
 |   return AttrPropTable[Index] & Prop; | 
 | } | 
 |  | 
 | bool Attribute::canUseAsFnAttr(AttrKind Kind) { | 
 |   return hasAttributeProperty(Kind, AttributeProperty::FnAttr); | 
 | } | 
 |  | 
 | bool Attribute::canUseAsParamAttr(AttrKind Kind) { | 
 |   return hasAttributeProperty(Kind, AttributeProperty::ParamAttr); | 
 | } | 
 |  | 
 | bool Attribute::canUseAsRetAttr(AttrKind Kind) { | 
 |   return hasAttributeProperty(Kind, AttributeProperty::RetAttr); | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AttributeImpl Definition | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const { | 
 |   if (isStringAttribute()) return false; | 
 |   return getKindAsEnum() == A; | 
 | } | 
 |  | 
 | bool AttributeImpl::hasAttribute(StringRef Kind) const { | 
 |   if (!isStringAttribute()) return false; | 
 |   return getKindAsString() == Kind; | 
 | } | 
 |  | 
 | Attribute::AttrKind AttributeImpl::getKindAsEnum() const { | 
 |   assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute()); | 
 |   return static_cast<const EnumAttributeImpl *>(this)->getEnumKind(); | 
 | } | 
 |  | 
 | uint64_t AttributeImpl::getValueAsInt() const { | 
 |   assert(isIntAttribute()); | 
 |   return static_cast<const IntAttributeImpl *>(this)->getValue(); | 
 | } | 
 |  | 
 | bool AttributeImpl::getValueAsBool() const { | 
 |   assert(getValueAsString().empty() || getValueAsString() == "false" || getValueAsString() == "true"); | 
 |   return getValueAsString() == "true"; | 
 | } | 
 |  | 
 | StringRef AttributeImpl::getKindAsString() const { | 
 |   assert(isStringAttribute()); | 
 |   return static_cast<const StringAttributeImpl *>(this)->getStringKind(); | 
 | } | 
 |  | 
 | StringRef AttributeImpl::getValueAsString() const { | 
 |   assert(isStringAttribute()); | 
 |   return static_cast<const StringAttributeImpl *>(this)->getStringValue(); | 
 | } | 
 |  | 
 | Type *AttributeImpl::getValueAsType() const { | 
 |   assert(isTypeAttribute()); | 
 |   return static_cast<const TypeAttributeImpl *>(this)->getTypeValue(); | 
 | } | 
 |  | 
 | bool AttributeImpl::operator<(const AttributeImpl &AI) const { | 
 |   if (this == &AI) | 
 |     return false; | 
 |  | 
 |   // This sorts the attributes with Attribute::AttrKinds coming first (sorted | 
 |   // relative to their enum value) and then strings. | 
 |   if (!isStringAttribute()) { | 
 |     if (AI.isStringAttribute()) | 
 |       return true; | 
 |     if (getKindAsEnum() != AI.getKindAsEnum()) | 
 |       return getKindAsEnum() < AI.getKindAsEnum(); | 
 |     assert(!AI.isEnumAttribute() && "Non-unique attribute"); | 
 |     assert(!AI.isTypeAttribute() && "Comparison of types would be unstable"); | 
 |     // TODO: Is this actually needed? | 
 |     assert(AI.isIntAttribute() && "Only possibility left"); | 
 |     return getValueAsInt() < AI.getValueAsInt(); | 
 |   } | 
 |  | 
 |   if (!AI.isStringAttribute()) | 
 |     return false; | 
 |   if (getKindAsString() == AI.getKindAsString()) | 
 |     return getValueAsString() < AI.getValueAsString(); | 
 |   return getKindAsString() < AI.getKindAsString(); | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AttributeSet Definition | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | AttributeSet AttributeSet::get(LLVMContext &C, const AttrBuilder &B) { | 
 |   return AttributeSet(AttributeSetNode::get(C, B)); | 
 | } | 
 |  | 
 | AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef<Attribute> Attrs) { | 
 |   return AttributeSet(AttributeSetNode::get(C, Attrs)); | 
 | } | 
 |  | 
 | AttributeSet AttributeSet::addAttribute(LLVMContext &C, | 
 |                                         Attribute::AttrKind Kind) const { | 
 |   if (hasAttribute(Kind)) return *this; | 
 |   AttrBuilder B(C); | 
 |   B.addAttribute(Kind); | 
 |   return addAttributes(C, AttributeSet::get(C, B)); | 
 | } | 
 |  | 
 | AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind, | 
 |                                         StringRef Value) const { | 
 |   AttrBuilder B(C); | 
 |   B.addAttribute(Kind, Value); | 
 |   return addAttributes(C, AttributeSet::get(C, B)); | 
 | } | 
 |  | 
 | AttributeSet AttributeSet::addAttributes(LLVMContext &C, | 
 |                                          const AttributeSet AS) const { | 
 |   if (!hasAttributes()) | 
 |     return AS; | 
 |  | 
 |   if (!AS.hasAttributes()) | 
 |     return *this; | 
 |  | 
 |   AttrBuilder B(C, *this); | 
 |   B.merge(AttrBuilder(C, AS)); | 
 |   return get(C, B); | 
 | } | 
 |  | 
 | AttributeSet AttributeSet::removeAttribute(LLVMContext &C, | 
 |                                              Attribute::AttrKind Kind) const { | 
 |   if (!hasAttribute(Kind)) return *this; | 
 |   AttrBuilder B(C, *this); | 
 |   B.removeAttribute(Kind); | 
 |   return get(C, B); | 
 | } | 
 |  | 
 | AttributeSet AttributeSet::removeAttribute(LLVMContext &C, | 
 |                                              StringRef Kind) const { | 
 |   if (!hasAttribute(Kind)) return *this; | 
 |   AttrBuilder B(C, *this); | 
 |   B.removeAttribute(Kind); | 
 |   return get(C, B); | 
 | } | 
 |  | 
 | AttributeSet AttributeSet::removeAttributes(LLVMContext &C, | 
 |                                             const AttributeMask &Attrs) const { | 
 |   AttrBuilder B(C, *this); | 
 |   // If there is nothing to remove, directly return the original set. | 
 |   if (!B.overlaps(Attrs)) | 
 |     return *this; | 
 |  | 
 |   B.remove(Attrs); | 
 |   return get(C, B); | 
 | } | 
 |  | 
 | unsigned AttributeSet::getNumAttributes() const { | 
 |   return SetNode ? SetNode->getNumAttributes() : 0; | 
 | } | 
 |  | 
 | bool AttributeSet::hasAttribute(Attribute::AttrKind Kind) const { | 
 |   return SetNode ? SetNode->hasAttribute(Kind) : false; | 
 | } | 
 |  | 
 | bool AttributeSet::hasAttribute(StringRef Kind) const { | 
 |   return SetNode ? SetNode->hasAttribute(Kind) : false; | 
 | } | 
 |  | 
 | Attribute AttributeSet::getAttribute(Attribute::AttrKind Kind) const { | 
 |   return SetNode ? SetNode->getAttribute(Kind) : Attribute(); | 
 | } | 
 |  | 
 | Attribute AttributeSet::getAttribute(StringRef Kind) const { | 
 |   return SetNode ? SetNode->getAttribute(Kind) : Attribute(); | 
 | } | 
 |  | 
 | MaybeAlign AttributeSet::getAlignment() const { | 
 |   return SetNode ? SetNode->getAlignment() : std::nullopt; | 
 | } | 
 |  | 
 | MaybeAlign AttributeSet::getStackAlignment() const { | 
 |   return SetNode ? SetNode->getStackAlignment() : std::nullopt; | 
 | } | 
 |  | 
 | uint64_t AttributeSet::getDereferenceableBytes() const { | 
 |   return SetNode ? SetNode->getDereferenceableBytes() : 0; | 
 | } | 
 |  | 
 | uint64_t AttributeSet::getDereferenceableOrNullBytes() const { | 
 |   return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0; | 
 | } | 
 |  | 
 | Type *AttributeSet::getByRefType() const { | 
 |   return SetNode ? SetNode->getAttributeType(Attribute::ByRef) : nullptr; | 
 | } | 
 |  | 
 | Type *AttributeSet::getByValType() const { | 
 |   return SetNode ? SetNode->getAttributeType(Attribute::ByVal) : nullptr; | 
 | } | 
 |  | 
 | Type *AttributeSet::getStructRetType() const { | 
 |   return SetNode ? SetNode->getAttributeType(Attribute::StructRet) : nullptr; | 
 | } | 
 |  | 
 | Type *AttributeSet::getPreallocatedType() const { | 
 |   return SetNode ? SetNode->getAttributeType(Attribute::Preallocated) : nullptr; | 
 | } | 
 |  | 
 | Type *AttributeSet::getInAllocaType() const { | 
 |   return SetNode ? SetNode->getAttributeType(Attribute::InAlloca) : nullptr; | 
 | } | 
 |  | 
 | Type *AttributeSet::getElementType() const { | 
 |   return SetNode ? SetNode->getAttributeType(Attribute::ElementType) : nullptr; | 
 | } | 
 |  | 
 | std::optional<std::pair<unsigned, std::optional<unsigned>>> | 
 | AttributeSet::getAllocSizeArgs() const { | 
 |   if (SetNode) | 
 |     return SetNode->getAllocSizeArgs(); | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | unsigned AttributeSet::getVScaleRangeMin() const { | 
 |   return SetNode ? SetNode->getVScaleRangeMin() : 1; | 
 | } | 
 |  | 
 | std::optional<unsigned> AttributeSet::getVScaleRangeMax() const { | 
 |   return SetNode ? SetNode->getVScaleRangeMax() : std::nullopt; | 
 | } | 
 |  | 
 | UWTableKind AttributeSet::getUWTableKind() const { | 
 |   return SetNode ? SetNode->getUWTableKind() : UWTableKind::None; | 
 | } | 
 |  | 
 | AllocFnKind AttributeSet::getAllocKind() const { | 
 |   return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown; | 
 | } | 
 |  | 
 | MemoryEffects AttributeSet::getMemoryEffects() const { | 
 |   return SetNode ? SetNode->getMemoryEffects() : MemoryEffects::unknown(); | 
 | } | 
 |  | 
 | FPClassTest AttributeSet::getNoFPClass() const { | 
 |   return SetNode ? SetNode->getNoFPClass() : fcNone; | 
 | } | 
 |  | 
 | std::string AttributeSet::getAsString(bool InAttrGrp) const { | 
 |   return SetNode ? SetNode->getAsString(InAttrGrp) : ""; | 
 | } | 
 |  | 
 | bool AttributeSet::hasParentContext(LLVMContext &C) const { | 
 |   assert(hasAttributes() && "empty AttributeSet doesn't refer to any context"); | 
 |   FoldingSetNodeID ID; | 
 |   SetNode->Profile(ID); | 
 |   void *Unused; | 
 |   return C.pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, Unused) == SetNode; | 
 | } | 
 |  | 
 | AttributeSet::iterator AttributeSet::begin() const { | 
 |   return SetNode ? SetNode->begin() : nullptr; | 
 | } | 
 |  | 
 | AttributeSet::iterator AttributeSet::end() const { | 
 |   return SetNode ? SetNode->end() : nullptr; | 
 | } | 
 |  | 
 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | 
 | LLVM_DUMP_METHOD void AttributeSet::dump() const { | 
 |   dbgs() << "AS =\n"; | 
 |     dbgs() << "  { "; | 
 |     dbgs() << getAsString(true) << " }\n"; | 
 | } | 
 | #endif | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AttributeSetNode Definition | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | AttributeSetNode::AttributeSetNode(ArrayRef<Attribute> Attrs) | 
 |     : NumAttrs(Attrs.size()) { | 
 |   // There's memory after the node where we can store the entries in. | 
 |   llvm::copy(Attrs, getTrailingObjects<Attribute>()); | 
 |  | 
 |   for (const auto &I : *this) { | 
 |     if (I.isStringAttribute()) | 
 |       StringAttrs.insert({ I.getKindAsString(), I }); | 
 |     else | 
 |       AvailableAttrs.addAttribute(I.getKindAsEnum()); | 
 |   } | 
 | } | 
 |  | 
 | AttributeSetNode *AttributeSetNode::get(LLVMContext &C, | 
 |                                         ArrayRef<Attribute> Attrs) { | 
 |   SmallVector<Attribute, 8> SortedAttrs(Attrs.begin(), Attrs.end()); | 
 |   llvm::sort(SortedAttrs); | 
 |   return getSorted(C, SortedAttrs); | 
 | } | 
 |  | 
 | AttributeSetNode *AttributeSetNode::getSorted(LLVMContext &C, | 
 |                                               ArrayRef<Attribute> SortedAttrs) { | 
 |   if (SortedAttrs.empty()) | 
 |     return nullptr; | 
 |  | 
 |   // Build a key to look up the existing attributes. | 
 |   LLVMContextImpl *pImpl = C.pImpl; | 
 |   FoldingSetNodeID ID; | 
 |  | 
 |   assert(llvm::is_sorted(SortedAttrs) && "Expected sorted attributes!"); | 
 |   for (const auto &Attr : SortedAttrs) | 
 |     Attr.Profile(ID); | 
 |  | 
 |   void *InsertPoint; | 
 |   AttributeSetNode *PA = | 
 |     pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, InsertPoint); | 
 |  | 
 |   // If we didn't find any existing attributes of the same shape then create a | 
 |   // new one and insert it. | 
 |   if (!PA) { | 
 |     // Coallocate entries after the AttributeSetNode itself. | 
 |     void *Mem = ::operator new(totalSizeToAlloc<Attribute>(SortedAttrs.size())); | 
 |     PA = new (Mem) AttributeSetNode(SortedAttrs); | 
 |     pImpl->AttrsSetNodes.InsertNode(PA, InsertPoint); | 
 |   } | 
 |  | 
 |   // Return the AttributeSetNode that we found or created. | 
 |   return PA; | 
 | } | 
 |  | 
 | AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) { | 
 |   return getSorted(C, B.attrs()); | 
 | } | 
 |  | 
 | bool AttributeSetNode::hasAttribute(StringRef Kind) const { | 
 |   return StringAttrs.count(Kind); | 
 | } | 
 |  | 
 | std::optional<Attribute> | 
 | AttributeSetNode::findEnumAttribute(Attribute::AttrKind Kind) const { | 
 |   // Do a quick presence check. | 
 |   if (!hasAttribute(Kind)) | 
 |     return std::nullopt; | 
 |  | 
 |   // Attributes in a set are sorted by enum value, followed by string | 
 |   // attributes. Binary search the one we want. | 
 |   const Attribute *I = | 
 |       std::lower_bound(begin(), end() - StringAttrs.size(), Kind, | 
 |                        [](Attribute A, Attribute::AttrKind Kind) { | 
 |                          return A.getKindAsEnum() < Kind; | 
 |                        }); | 
 |   assert(I != end() && I->hasAttribute(Kind) && "Presence check failed?"); | 
 |   return *I; | 
 | } | 
 |  | 
 | Attribute AttributeSetNode::getAttribute(Attribute::AttrKind Kind) const { | 
 |   if (auto A = findEnumAttribute(Kind)) | 
 |     return *A; | 
 |   return {}; | 
 | } | 
 |  | 
 | Attribute AttributeSetNode::getAttribute(StringRef Kind) const { | 
 |   return StringAttrs.lookup(Kind); | 
 | } | 
 |  | 
 | MaybeAlign AttributeSetNode::getAlignment() const { | 
 |   if (auto A = findEnumAttribute(Attribute::Alignment)) | 
 |     return A->getAlignment(); | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | MaybeAlign AttributeSetNode::getStackAlignment() const { | 
 |   if (auto A = findEnumAttribute(Attribute::StackAlignment)) | 
 |     return A->getStackAlignment(); | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | Type *AttributeSetNode::getAttributeType(Attribute::AttrKind Kind) const { | 
 |   if (auto A = findEnumAttribute(Kind)) | 
 |     return A->getValueAsType(); | 
 |   return nullptr; | 
 | } | 
 |  | 
 | uint64_t AttributeSetNode::getDereferenceableBytes() const { | 
 |   if (auto A = findEnumAttribute(Attribute::Dereferenceable)) | 
 |     return A->getDereferenceableBytes(); | 
 |   return 0; | 
 | } | 
 |  | 
 | uint64_t AttributeSetNode::getDereferenceableOrNullBytes() const { | 
 |   if (auto A = findEnumAttribute(Attribute::DereferenceableOrNull)) | 
 |     return A->getDereferenceableOrNullBytes(); | 
 |   return 0; | 
 | } | 
 |  | 
 | std::optional<std::pair<unsigned, std::optional<unsigned>>> | 
 | AttributeSetNode::getAllocSizeArgs() const { | 
 |   if (auto A = findEnumAttribute(Attribute::AllocSize)) | 
 |     return A->getAllocSizeArgs(); | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | unsigned AttributeSetNode::getVScaleRangeMin() const { | 
 |   if (auto A = findEnumAttribute(Attribute::VScaleRange)) | 
 |     return A->getVScaleRangeMin(); | 
 |   return 1; | 
 | } | 
 |  | 
 | std::optional<unsigned> AttributeSetNode::getVScaleRangeMax() const { | 
 |   if (auto A = findEnumAttribute(Attribute::VScaleRange)) | 
 |     return A->getVScaleRangeMax(); | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | UWTableKind AttributeSetNode::getUWTableKind() const { | 
 |   if (auto A = findEnumAttribute(Attribute::UWTable)) | 
 |     return A->getUWTableKind(); | 
 |   return UWTableKind::None; | 
 | } | 
 |  | 
 | AllocFnKind AttributeSetNode::getAllocKind() const { | 
 |   if (auto A = findEnumAttribute(Attribute::AllocKind)) | 
 |     return A->getAllocKind(); | 
 |   return AllocFnKind::Unknown; | 
 | } | 
 |  | 
 | MemoryEffects AttributeSetNode::getMemoryEffects() const { | 
 |   if (auto A = findEnumAttribute(Attribute::Memory)) | 
 |     return A->getMemoryEffects(); | 
 |   return MemoryEffects::unknown(); | 
 | } | 
 |  | 
 | FPClassTest AttributeSetNode::getNoFPClass() const { | 
 |   if (auto A = findEnumAttribute(Attribute::NoFPClass)) | 
 |     return A->getNoFPClass(); | 
 |   return fcNone; | 
 | } | 
 |  | 
 | std::string AttributeSetNode::getAsString(bool InAttrGrp) const { | 
 |   std::string Str; | 
 |   for (iterator I = begin(), E = end(); I != E; ++I) { | 
 |     if (I != begin()) | 
 |       Str += ' '; | 
 |     Str += I->getAsString(InAttrGrp); | 
 |   } | 
 |   return Str; | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AttributeListImpl Definition | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | /// Map from AttributeList index to the internal array index. Adding one happens | 
 | /// to work, because -1 wraps around to 0. | 
 | static unsigned attrIdxToArrayIdx(unsigned Index) { | 
 |   return Index + 1; | 
 | } | 
 |  | 
 | AttributeListImpl::AttributeListImpl(ArrayRef<AttributeSet> Sets) | 
 |     : NumAttrSets(Sets.size()) { | 
 |   assert(!Sets.empty() && "pointless AttributeListImpl"); | 
 |  | 
 |   // There's memory after the node where we can store the entries in. | 
 |   llvm::copy(Sets, getTrailingObjects<AttributeSet>()); | 
 |  | 
 |   // Initialize AvailableFunctionAttrs and AvailableSomewhereAttrs | 
 |   // summary bitsets. | 
 |   for (const auto &I : Sets[attrIdxToArrayIdx(AttributeList::FunctionIndex)]) | 
 |     if (!I.isStringAttribute()) | 
 |       AvailableFunctionAttrs.addAttribute(I.getKindAsEnum()); | 
 |  | 
 |   for (const auto &Set : Sets) | 
 |     for (const auto &I : Set) | 
 |       if (!I.isStringAttribute()) | 
 |         AvailableSomewhereAttrs.addAttribute(I.getKindAsEnum()); | 
 | } | 
 |  | 
 | void AttributeListImpl::Profile(FoldingSetNodeID &ID) const { | 
 |   Profile(ID, ArrayRef(begin(), end())); | 
 | } | 
 |  | 
 | void AttributeListImpl::Profile(FoldingSetNodeID &ID, | 
 |                                 ArrayRef<AttributeSet> Sets) { | 
 |   for (const auto &Set : Sets) | 
 |     ID.AddPointer(Set.SetNode); | 
 | } | 
 |  | 
 | bool AttributeListImpl::hasAttrSomewhere(Attribute::AttrKind Kind, | 
 |                                         unsigned *Index) const { | 
 |   if (!AvailableSomewhereAttrs.hasAttribute(Kind)) | 
 |     return false; | 
 |  | 
 |   if (Index) { | 
 |     for (unsigned I = 0, E = NumAttrSets; I != E; ++I) { | 
 |       if (begin()[I].hasAttribute(Kind)) { | 
 |         *Index = I - 1; | 
 |         break; | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 |  | 
 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | 
 | LLVM_DUMP_METHOD void AttributeListImpl::dump() const { | 
 |   AttributeList(const_cast<AttributeListImpl *>(this)).dump(); | 
 | } | 
 | #endif | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AttributeList Construction and Mutation Methods | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | AttributeList AttributeList::getImpl(LLVMContext &C, | 
 |                                      ArrayRef<AttributeSet> AttrSets) { | 
 |   assert(!AttrSets.empty() && "pointless AttributeListImpl"); | 
 |  | 
 |   LLVMContextImpl *pImpl = C.pImpl; | 
 |   FoldingSetNodeID ID; | 
 |   AttributeListImpl::Profile(ID, AttrSets); | 
 |  | 
 |   void *InsertPoint; | 
 |   AttributeListImpl *PA = | 
 |       pImpl->AttrsLists.FindNodeOrInsertPos(ID, InsertPoint); | 
 |  | 
 |   // If we didn't find any existing attributes of the same shape then | 
 |   // create a new one and insert it. | 
 |   if (!PA) { | 
 |     // Coallocate entries after the AttributeListImpl itself. | 
 |     void *Mem = pImpl->Alloc.Allocate( | 
 |         AttributeListImpl::totalSizeToAlloc<AttributeSet>(AttrSets.size()), | 
 |         alignof(AttributeListImpl)); | 
 |     PA = new (Mem) AttributeListImpl(AttrSets); | 
 |     pImpl->AttrsLists.InsertNode(PA, InsertPoint); | 
 |   } | 
 |  | 
 |   // Return the AttributesList that we found or created. | 
 |   return AttributeList(PA); | 
 | } | 
 |  | 
 | AttributeList | 
 | AttributeList::get(LLVMContext &C, | 
 |                    ArrayRef<std::pair<unsigned, Attribute>> Attrs) { | 
 |   // If there are no attributes then return a null AttributesList pointer. | 
 |   if (Attrs.empty()) | 
 |     return {}; | 
 |  | 
 |   assert(llvm::is_sorted(Attrs, llvm::less_first()) && | 
 |          "Misordered Attributes list!"); | 
 |   assert(llvm::all_of(Attrs, | 
 |                       [](const std::pair<unsigned, Attribute> &Pair) { | 
 |                         return Pair.second.isValid(); | 
 |                       }) && | 
 |          "Pointless attribute!"); | 
 |  | 
 |   // Create a vector if (unsigned, AttributeSetNode*) pairs from the attributes | 
 |   // list. | 
 |   SmallVector<std::pair<unsigned, AttributeSet>, 8> AttrPairVec; | 
 |   for (ArrayRef<std::pair<unsigned, Attribute>>::iterator I = Attrs.begin(), | 
 |          E = Attrs.end(); I != E; ) { | 
 |     unsigned Index = I->first; | 
 |     SmallVector<Attribute, 4> AttrVec; | 
 |     while (I != E && I->first == Index) { | 
 |       AttrVec.push_back(I->second); | 
 |       ++I; | 
 |     } | 
 |  | 
 |     AttrPairVec.emplace_back(Index, AttributeSet::get(C, AttrVec)); | 
 |   } | 
 |  | 
 |   return get(C, AttrPairVec); | 
 | } | 
 |  | 
 | AttributeList | 
 | AttributeList::get(LLVMContext &C, | 
 |                    ArrayRef<std::pair<unsigned, AttributeSet>> Attrs) { | 
 |   // If there are no attributes then return a null AttributesList pointer. | 
 |   if (Attrs.empty()) | 
 |     return {}; | 
 |  | 
 |   assert(llvm::is_sorted(Attrs, llvm::less_first()) && | 
 |          "Misordered Attributes list!"); | 
 |   assert(llvm::none_of(Attrs, | 
 |                        [](const std::pair<unsigned, AttributeSet> &Pair) { | 
 |                          return !Pair.second.hasAttributes(); | 
 |                        }) && | 
 |          "Pointless attribute!"); | 
 |  | 
 |   unsigned MaxIndex = Attrs.back().first; | 
 |   // If the MaxIndex is FunctionIndex and there are other indices in front | 
 |   // of it, we need to use the largest of those to get the right size. | 
 |   if (MaxIndex == FunctionIndex && Attrs.size() > 1) | 
 |     MaxIndex = Attrs[Attrs.size() - 2].first; | 
 |  | 
 |   SmallVector<AttributeSet, 4> AttrVec(attrIdxToArrayIdx(MaxIndex) + 1); | 
 |   for (const auto &Pair : Attrs) | 
 |     AttrVec[attrIdxToArrayIdx(Pair.first)] = Pair.second; | 
 |  | 
 |   return getImpl(C, AttrVec); | 
 | } | 
 |  | 
 | AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs, | 
 |                                  AttributeSet RetAttrs, | 
 |                                  ArrayRef<AttributeSet> ArgAttrs) { | 
 |   // Scan from the end to find the last argument with attributes.  Most | 
 |   // arguments don't have attributes, so it's nice if we can have fewer unique | 
 |   // AttributeListImpls by dropping empty attribute sets at the end of the list. | 
 |   unsigned NumSets = 0; | 
 |   for (size_t I = ArgAttrs.size(); I != 0; --I) { | 
 |     if (ArgAttrs[I - 1].hasAttributes()) { | 
 |       NumSets = I + 2; | 
 |       break; | 
 |     } | 
 |   } | 
 |   if (NumSets == 0) { | 
 |     // Check function and return attributes if we didn't have argument | 
 |     // attributes. | 
 |     if (RetAttrs.hasAttributes()) | 
 |       NumSets = 2; | 
 |     else if (FnAttrs.hasAttributes()) | 
 |       NumSets = 1; | 
 |   } | 
 |  | 
 |   // If all attribute sets were empty, we can use the empty attribute list. | 
 |   if (NumSets == 0) | 
 |     return {}; | 
 |  | 
 |   SmallVector<AttributeSet, 8> AttrSets; | 
 |   AttrSets.reserve(NumSets); | 
 |   // If we have any attributes, we always have function attributes. | 
 |   AttrSets.push_back(FnAttrs); | 
 |   if (NumSets > 1) | 
 |     AttrSets.push_back(RetAttrs); | 
 |   if (NumSets > 2) { | 
 |     // Drop the empty argument attribute sets at the end. | 
 |     ArgAttrs = ArgAttrs.take_front(NumSets - 2); | 
 |     llvm::append_range(AttrSets, ArgAttrs); | 
 |   } | 
 |  | 
 |   return getImpl(C, AttrSets); | 
 | } | 
 |  | 
 | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, | 
 |                                  AttributeSet Attrs) { | 
 |   if (!Attrs.hasAttributes()) | 
 |     return {}; | 
 |   Index = attrIdxToArrayIdx(Index); | 
 |   SmallVector<AttributeSet, 8> AttrSets(Index + 1); | 
 |   AttrSets[Index] = Attrs; | 
 |   return getImpl(C, AttrSets); | 
 | } | 
 |  | 
 | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, | 
 |                                  const AttrBuilder &B) { | 
 |   return get(C, Index, AttributeSet::get(C, B)); | 
 | } | 
 |  | 
 | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, | 
 |                                  ArrayRef<Attribute::AttrKind> Kinds) { | 
 |   SmallVector<std::pair<unsigned, Attribute>, 8> Attrs; | 
 |   for (const auto K : Kinds) | 
 |     Attrs.emplace_back(Index, Attribute::get(C, K)); | 
 |   return get(C, Attrs); | 
 | } | 
 |  | 
 | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, | 
 |                                  ArrayRef<Attribute::AttrKind> Kinds, | 
 |                                  ArrayRef<uint64_t> Values) { | 
 |   assert(Kinds.size() == Values.size() && "Mismatched attribute values."); | 
 |   SmallVector<std::pair<unsigned, Attribute>, 8> Attrs; | 
 |   auto VI = Values.begin(); | 
 |   for (const auto K : Kinds) | 
 |     Attrs.emplace_back(Index, Attribute::get(C, K, *VI++)); | 
 |   return get(C, Attrs); | 
 | } | 
 |  | 
 | AttributeList AttributeList::get(LLVMContext &C, unsigned Index, | 
 |                                  ArrayRef<StringRef> Kinds) { | 
 |   SmallVector<std::pair<unsigned, Attribute>, 8> Attrs; | 
 |   for (const auto &K : Kinds) | 
 |     Attrs.emplace_back(Index, Attribute::get(C, K)); | 
 |   return get(C, Attrs); | 
 | } | 
 |  | 
 | AttributeList AttributeList::get(LLVMContext &C, | 
 |                                  ArrayRef<AttributeList> Attrs) { | 
 |   if (Attrs.empty()) | 
 |     return {}; | 
 |   if (Attrs.size() == 1) | 
 |     return Attrs[0]; | 
 |  | 
 |   unsigned MaxSize = 0; | 
 |   for (const auto &List : Attrs) | 
 |     MaxSize = std::max(MaxSize, List.getNumAttrSets()); | 
 |  | 
 |   // If every list was empty, there is no point in merging the lists. | 
 |   if (MaxSize == 0) | 
 |     return {}; | 
 |  | 
 |   SmallVector<AttributeSet, 8> NewAttrSets(MaxSize); | 
 |   for (unsigned I = 0; I < MaxSize; ++I) { | 
 |     AttrBuilder CurBuilder(C); | 
 |     for (const auto &List : Attrs) | 
 |       CurBuilder.merge(AttrBuilder(C, List.getAttributes(I - 1))); | 
 |     NewAttrSets[I] = AttributeSet::get(C, CurBuilder); | 
 |   } | 
 |  | 
 |   return getImpl(C, NewAttrSets); | 
 | } | 
 |  | 
 | AttributeList | 
 | AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, | 
 |                                    Attribute::AttrKind Kind) const { | 
 |   AttributeSet Attrs = getAttributes(Index); | 
 |   if (Attrs.hasAttribute(Kind)) | 
 |     return *this; | 
 |   // TODO: Insert at correct position and avoid sort. | 
 |   SmallVector<Attribute, 8> NewAttrs(Attrs.begin(), Attrs.end()); | 
 |   NewAttrs.push_back(Attribute::get(C, Kind)); | 
 |   return setAttributesAtIndex(C, Index, AttributeSet::get(C, NewAttrs)); | 
 | } | 
 |  | 
 | AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, | 
 |                                                  StringRef Kind, | 
 |                                                  StringRef Value) const { | 
 |   AttrBuilder B(C); | 
 |   B.addAttribute(Kind, Value); | 
 |   return addAttributesAtIndex(C, Index, B); | 
 | } | 
 |  | 
 | AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index, | 
 |                                                  Attribute A) const { | 
 |   AttrBuilder B(C); | 
 |   B.addAttribute(A); | 
 |   return addAttributesAtIndex(C, Index, B); | 
 | } | 
 |  | 
 | AttributeList AttributeList::setAttributesAtIndex(LLVMContext &C, | 
 |                                                   unsigned Index, | 
 |                                                   AttributeSet Attrs) const { | 
 |   Index = attrIdxToArrayIdx(Index); | 
 |   SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end()); | 
 |   if (Index >= AttrSets.size()) | 
 |     AttrSets.resize(Index + 1); | 
 |   AttrSets[Index] = Attrs; | 
 |  | 
 |   // Remove trailing empty attribute sets. | 
 |   while (!AttrSets.empty() && !AttrSets.back().hasAttributes()) | 
 |     AttrSets.pop_back(); | 
 |   if (AttrSets.empty()) | 
 |     return {}; | 
 |   return AttributeList::getImpl(C, AttrSets); | 
 | } | 
 |  | 
 | AttributeList AttributeList::addAttributesAtIndex(LLVMContext &C, | 
 |                                                   unsigned Index, | 
 |                                                   const AttrBuilder &B) const { | 
 |   if (!B.hasAttributes()) | 
 |     return *this; | 
 |  | 
 |   if (!pImpl) | 
 |     return AttributeList::get(C, {{Index, AttributeSet::get(C, B)}}); | 
 |  | 
 |   AttrBuilder Merged(C, getAttributes(Index)); | 
 |   Merged.merge(B); | 
 |   return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged)); | 
 | } | 
 |  | 
 | AttributeList AttributeList::addParamAttribute(LLVMContext &C, | 
 |                                                ArrayRef<unsigned> ArgNos, | 
 |                                                Attribute A) const { | 
 |   assert(llvm::is_sorted(ArgNos)); | 
 |  | 
 |   SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end()); | 
 |   unsigned MaxIndex = attrIdxToArrayIdx(ArgNos.back() + FirstArgIndex); | 
 |   if (MaxIndex >= AttrSets.size()) | 
 |     AttrSets.resize(MaxIndex + 1); | 
 |  | 
 |   for (unsigned ArgNo : ArgNos) { | 
 |     unsigned Index = attrIdxToArrayIdx(ArgNo + FirstArgIndex); | 
 |     AttrBuilder B(C, AttrSets[Index]); | 
 |     B.addAttribute(A); | 
 |     AttrSets[Index] = AttributeSet::get(C, B); | 
 |   } | 
 |  | 
 |   return getImpl(C, AttrSets); | 
 | } | 
 |  | 
 | AttributeList | 
 | AttributeList::removeAttributeAtIndex(LLVMContext &C, unsigned Index, | 
 |                                       Attribute::AttrKind Kind) const { | 
 |   AttributeSet Attrs = getAttributes(Index); | 
 |   AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind); | 
 |   if (Attrs == NewAttrs) | 
 |     return *this; | 
 |   return setAttributesAtIndex(C, Index, NewAttrs); | 
 | } | 
 |  | 
 | AttributeList AttributeList::removeAttributeAtIndex(LLVMContext &C, | 
 |                                                     unsigned Index, | 
 |                                                     StringRef Kind) const { | 
 |   AttributeSet Attrs = getAttributes(Index); | 
 |   AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind); | 
 |   if (Attrs == NewAttrs) | 
 |     return *this; | 
 |   return setAttributesAtIndex(C, Index, NewAttrs); | 
 | } | 
 |  | 
 | AttributeList AttributeList::removeAttributesAtIndex( | 
 |     LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const { | 
 |   AttributeSet Attrs = getAttributes(Index); | 
 |   AttributeSet NewAttrs = Attrs.removeAttributes(C, AttrsToRemove); | 
 |   // If nothing was removed, return the original list. | 
 |   if (Attrs == NewAttrs) | 
 |     return *this; | 
 |   return setAttributesAtIndex(C, Index, NewAttrs); | 
 | } | 
 |  | 
 | AttributeList | 
 | AttributeList::removeAttributesAtIndex(LLVMContext &C, | 
 |                                        unsigned WithoutIndex) const { | 
 |   if (!pImpl) | 
 |     return {}; | 
 |   if (attrIdxToArrayIdx(WithoutIndex) >= getNumAttrSets()) | 
 |     return *this; | 
 |   return setAttributesAtIndex(C, WithoutIndex, AttributeSet()); | 
 | } | 
 |  | 
 | AttributeList AttributeList::addDereferenceableRetAttr(LLVMContext &C, | 
 |                                                        uint64_t Bytes) const { | 
 |   AttrBuilder B(C); | 
 |   B.addDereferenceableAttr(Bytes); | 
 |   return addRetAttributes(C, B); | 
 | } | 
 |  | 
 | AttributeList AttributeList::addDereferenceableParamAttr(LLVMContext &C, | 
 |                                                          unsigned Index, | 
 |                                                          uint64_t Bytes) const { | 
 |   AttrBuilder B(C); | 
 |   B.addDereferenceableAttr(Bytes); | 
 |   return addParamAttributes(C, Index, B); | 
 | } | 
 |  | 
 | AttributeList | 
 | AttributeList::addDereferenceableOrNullParamAttr(LLVMContext &C, unsigned Index, | 
 |                                                  uint64_t Bytes) const { | 
 |   AttrBuilder B(C); | 
 |   B.addDereferenceableOrNullAttr(Bytes); | 
 |   return addParamAttributes(C, Index, B); | 
 | } | 
 |  | 
 | AttributeList AttributeList::addAllocSizeParamAttr( | 
 |     LLVMContext &C, unsigned Index, unsigned ElemSizeArg, | 
 |     const std::optional<unsigned> &NumElemsArg) { | 
 |   AttrBuilder B(C); | 
 |   B.addAllocSizeAttr(ElemSizeArg, NumElemsArg); | 
 |   return addParamAttributes(C, Index, B); | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AttributeList Accessor Methods | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | AttributeSet AttributeList::getParamAttrs(unsigned ArgNo) const { | 
 |   return getAttributes(ArgNo + FirstArgIndex); | 
 | } | 
 |  | 
 | AttributeSet AttributeList::getRetAttrs() const { | 
 |   return getAttributes(ReturnIndex); | 
 | } | 
 |  | 
 | AttributeSet AttributeList::getFnAttrs() const { | 
 |   return getAttributes(FunctionIndex); | 
 | } | 
 |  | 
 | bool AttributeList::hasAttributeAtIndex(unsigned Index, | 
 |                                         Attribute::AttrKind Kind) const { | 
 |   return getAttributes(Index).hasAttribute(Kind); | 
 | } | 
 |  | 
 | bool AttributeList::hasAttributeAtIndex(unsigned Index, StringRef Kind) const { | 
 |   return getAttributes(Index).hasAttribute(Kind); | 
 | } | 
 |  | 
 | bool AttributeList::hasAttributesAtIndex(unsigned Index) const { | 
 |   return getAttributes(Index).hasAttributes(); | 
 | } | 
 |  | 
 | bool AttributeList::hasFnAttr(Attribute::AttrKind Kind) const { | 
 |   return pImpl && pImpl->hasFnAttribute(Kind); | 
 | } | 
 |  | 
 | bool AttributeList::hasFnAttr(StringRef Kind) const { | 
 |   return hasAttributeAtIndex(AttributeList::FunctionIndex, Kind); | 
 | } | 
 |  | 
 | bool AttributeList::hasAttrSomewhere(Attribute::AttrKind Attr, | 
 |                                      unsigned *Index) const { | 
 |   return pImpl && pImpl->hasAttrSomewhere(Attr, Index); | 
 | } | 
 |  | 
 | Attribute AttributeList::getAttributeAtIndex(unsigned Index, | 
 |                                              Attribute::AttrKind Kind) const { | 
 |   return getAttributes(Index).getAttribute(Kind); | 
 | } | 
 |  | 
 | Attribute AttributeList::getAttributeAtIndex(unsigned Index, | 
 |                                              StringRef Kind) const { | 
 |   return getAttributes(Index).getAttribute(Kind); | 
 | } | 
 |  | 
 | MaybeAlign AttributeList::getRetAlignment() const { | 
 |   return getAttributes(ReturnIndex).getAlignment(); | 
 | } | 
 |  | 
 | MaybeAlign AttributeList::getParamAlignment(unsigned ArgNo) const { | 
 |   return getAttributes(ArgNo + FirstArgIndex).getAlignment(); | 
 | } | 
 |  | 
 | MaybeAlign AttributeList::getParamStackAlignment(unsigned ArgNo) const { | 
 |   return getAttributes(ArgNo + FirstArgIndex).getStackAlignment(); | 
 | } | 
 |  | 
 | Type *AttributeList::getParamByValType(unsigned Index) const { | 
 |   return getAttributes(Index+FirstArgIndex).getByValType(); | 
 | } | 
 |  | 
 | Type *AttributeList::getParamStructRetType(unsigned Index) const { | 
 |   return getAttributes(Index + FirstArgIndex).getStructRetType(); | 
 | } | 
 |  | 
 | Type *AttributeList::getParamByRefType(unsigned Index) const { | 
 |   return getAttributes(Index + FirstArgIndex).getByRefType(); | 
 | } | 
 |  | 
 | Type *AttributeList::getParamPreallocatedType(unsigned Index) const { | 
 |   return getAttributes(Index + FirstArgIndex).getPreallocatedType(); | 
 | } | 
 |  | 
 | Type *AttributeList::getParamInAllocaType(unsigned Index) const { | 
 |   return getAttributes(Index + FirstArgIndex).getInAllocaType(); | 
 | } | 
 |  | 
 | Type *AttributeList::getParamElementType(unsigned Index) const { | 
 |   return getAttributes(Index + FirstArgIndex).getElementType(); | 
 | } | 
 |  | 
 | MaybeAlign AttributeList::getFnStackAlignment() const { | 
 |   return getFnAttrs().getStackAlignment(); | 
 | } | 
 |  | 
 | MaybeAlign AttributeList::getRetStackAlignment() const { | 
 |   return getRetAttrs().getStackAlignment(); | 
 | } | 
 |  | 
 | uint64_t AttributeList::getRetDereferenceableBytes() const { | 
 |   return getRetAttrs().getDereferenceableBytes(); | 
 | } | 
 |  | 
 | uint64_t AttributeList::getParamDereferenceableBytes(unsigned Index) const { | 
 |   return getParamAttrs(Index).getDereferenceableBytes(); | 
 | } | 
 |  | 
 | uint64_t AttributeList::getRetDereferenceableOrNullBytes() const { | 
 |   return getRetAttrs().getDereferenceableOrNullBytes(); | 
 | } | 
 |  | 
 | uint64_t | 
 | AttributeList::getParamDereferenceableOrNullBytes(unsigned Index) const { | 
 |   return getParamAttrs(Index).getDereferenceableOrNullBytes(); | 
 | } | 
 |  | 
 | FPClassTest AttributeList::getRetNoFPClass() const { | 
 |   return getRetAttrs().getNoFPClass(); | 
 | } | 
 |  | 
 | FPClassTest AttributeList::getParamNoFPClass(unsigned Index) const { | 
 |   return getParamAttrs(Index).getNoFPClass(); | 
 | } | 
 |  | 
 | UWTableKind AttributeList::getUWTableKind() const { | 
 |   return getFnAttrs().getUWTableKind(); | 
 | } | 
 |  | 
 | AllocFnKind AttributeList::getAllocKind() const { | 
 |   return getFnAttrs().getAllocKind(); | 
 | } | 
 |  | 
 | MemoryEffects AttributeList::getMemoryEffects() const { | 
 |   return getFnAttrs().getMemoryEffects(); | 
 | } | 
 |  | 
 | std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const { | 
 |   return getAttributes(Index).getAsString(InAttrGrp); | 
 | } | 
 |  | 
 | AttributeSet AttributeList::getAttributes(unsigned Index) const { | 
 |   Index = attrIdxToArrayIdx(Index); | 
 |   if (!pImpl || Index >= getNumAttrSets()) | 
 |     return {}; | 
 |   return pImpl->begin()[Index]; | 
 | } | 
 |  | 
 | bool AttributeList::hasParentContext(LLVMContext &C) const { | 
 |   assert(!isEmpty() && "an empty attribute list has no parent context"); | 
 |   FoldingSetNodeID ID; | 
 |   pImpl->Profile(ID); | 
 |   void *Unused; | 
 |   return C.pImpl->AttrsLists.FindNodeOrInsertPos(ID, Unused) == pImpl; | 
 | } | 
 |  | 
 | AttributeList::iterator AttributeList::begin() const { | 
 |   return pImpl ? pImpl->begin() : nullptr; | 
 | } | 
 |  | 
 | AttributeList::iterator AttributeList::end() const { | 
 |   return pImpl ? pImpl->end() : nullptr; | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AttributeList Introspection Methods | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | unsigned AttributeList::getNumAttrSets() const { | 
 |   return pImpl ? pImpl->NumAttrSets : 0; | 
 | } | 
 |  | 
 | void AttributeList::print(raw_ostream &O) const { | 
 |   O << "AttributeList[\n"; | 
 |  | 
 |   for (unsigned i : indexes()) { | 
 |     if (!getAttributes(i).hasAttributes()) | 
 |       continue; | 
 |     O << "  { "; | 
 |     switch (i) { | 
 |     case AttrIndex::ReturnIndex: | 
 |       O << "return"; | 
 |       break; | 
 |     case AttrIndex::FunctionIndex: | 
 |       O << "function"; | 
 |       break; | 
 |     default: | 
 |       O << "arg(" << i - AttrIndex::FirstArgIndex << ")"; | 
 |     } | 
 |     O << " => " << getAsString(i) << " }\n"; | 
 |   } | 
 |  | 
 |   O << "]\n"; | 
 | } | 
 |  | 
 | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | 
 | LLVM_DUMP_METHOD void AttributeList::dump() const { print(dbgs()); } | 
 | #endif | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AttrBuilder Method Implementations | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | AttrBuilder::AttrBuilder(LLVMContext &Ctx, AttributeSet AS) : Ctx(Ctx) { | 
 |   append_range(Attrs, AS); | 
 |   assert(is_sorted(Attrs) && "AttributeSet should be sorted"); | 
 | } | 
 |  | 
 | void AttrBuilder::clear() { Attrs.clear(); } | 
 |  | 
 | /// Attribute comparator that only compares attribute keys. Enum attributes are | 
 | /// sorted before string attributes. | 
 | struct AttributeComparator { | 
 |   bool operator()(Attribute A0, Attribute A1) const { | 
 |     bool A0IsString = A0.isStringAttribute(); | 
 |     bool A1IsString = A1.isStringAttribute(); | 
 |     if (A0IsString) { | 
 |       if (A1IsString) | 
 |         return A0.getKindAsString() < A1.getKindAsString(); | 
 |       else | 
 |         return false; | 
 |     } | 
 |     if (A1IsString) | 
 |       return true; | 
 |     return A0.getKindAsEnum() < A1.getKindAsEnum(); | 
 |   } | 
 |   bool operator()(Attribute A0, Attribute::AttrKind Kind) const { | 
 |     if (A0.isStringAttribute()) | 
 |       return false; | 
 |     return A0.getKindAsEnum() < Kind; | 
 |   } | 
 |   bool operator()(Attribute A0, StringRef Kind) const { | 
 |     if (A0.isStringAttribute()) | 
 |       return A0.getKindAsString() < Kind; | 
 |     return true; | 
 |   } | 
 | }; | 
 |  | 
 | template <typename K> | 
 | static void addAttributeImpl(SmallVectorImpl<Attribute> &Attrs, K Kind, | 
 |                              Attribute Attr) { | 
 |   auto It = lower_bound(Attrs, Kind, AttributeComparator()); | 
 |   if (It != Attrs.end() && It->hasAttribute(Kind)) | 
 |     std::swap(*It, Attr); | 
 |   else | 
 |     Attrs.insert(It, Attr); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) { | 
 |   if (Attr.isStringAttribute()) | 
 |     addAttributeImpl(Attrs, Attr.getKindAsString(), Attr); | 
 |   else | 
 |     addAttributeImpl(Attrs, Attr.getKindAsEnum(), Attr); | 
 |   return *this; | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Kind) { | 
 |   addAttributeImpl(Attrs, Kind, Attribute::get(Ctx, Kind)); | 
 |   return *this; | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addAttribute(StringRef A, StringRef V) { | 
 |   addAttributeImpl(Attrs, A, Attribute::get(Ctx, A, V)); | 
 |   return *this; | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) { | 
 |   assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!"); | 
 |   auto It = lower_bound(Attrs, Val, AttributeComparator()); | 
 |   if (It != Attrs.end() && It->hasAttribute(Val)) | 
 |     Attrs.erase(It); | 
 |   return *this; | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::removeAttribute(StringRef A) { | 
 |   auto It = lower_bound(Attrs, A, AttributeComparator()); | 
 |   if (It != Attrs.end() && It->hasAttribute(A)) | 
 |     Attrs.erase(It); | 
 |   return *this; | 
 | } | 
 |  | 
 | std::optional<uint64_t> | 
 | AttrBuilder::getRawIntAttr(Attribute::AttrKind Kind) const { | 
 |   assert(Attribute::isIntAttrKind(Kind) && "Not an int attribute"); | 
 |   Attribute A = getAttribute(Kind); | 
 |   if (A.isValid()) | 
 |     return A.getValueAsInt(); | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addRawIntAttr(Attribute::AttrKind Kind, | 
 |                                         uint64_t Value) { | 
 |   return addAttribute(Attribute::get(Ctx, Kind, Value)); | 
 | } | 
 |  | 
 | std::optional<std::pair<unsigned, std::optional<unsigned>>> | 
 | AttrBuilder::getAllocSizeArgs() const { | 
 |   Attribute A = getAttribute(Attribute::AllocSize); | 
 |   if (A.isValid()) | 
 |     return A.getAllocSizeArgs(); | 
 |   return std::nullopt; | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addAlignmentAttr(MaybeAlign Align) { | 
 |   if (!Align) | 
 |     return *this; | 
 |  | 
 |   assert(*Align <= llvm::Value::MaximumAlignment && "Alignment too large."); | 
 |   return addRawIntAttr(Attribute::Alignment, Align->value()); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addStackAlignmentAttr(MaybeAlign Align) { | 
 |   // Default alignment, allow the target to define how to align it. | 
 |   if (!Align) | 
 |     return *this; | 
 |  | 
 |   assert(*Align <= 0x100 && "Alignment too large."); | 
 |   return addRawIntAttr(Attribute::StackAlignment, Align->value()); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) { | 
 |   if (Bytes == 0) return *this; | 
 |  | 
 |   return addRawIntAttr(Attribute::Dereferenceable, Bytes); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) { | 
 |   if (Bytes == 0) | 
 |     return *this; | 
 |  | 
 |   return addRawIntAttr(Attribute::DereferenceableOrNull, Bytes); | 
 | } | 
 |  | 
 | AttrBuilder & | 
 | AttrBuilder::addAllocSizeAttr(unsigned ElemSize, | 
 |                               const std::optional<unsigned> &NumElems) { | 
 |   return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems)); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addAllocSizeAttrFromRawRepr(uint64_t RawArgs) { | 
 |   // (0, 0) is our "not present" value, so we need to check for it here. | 
 |   assert(RawArgs && "Invalid allocsize arguments -- given allocsize(0, 0)"); | 
 |   return addRawIntAttr(Attribute::AllocSize, RawArgs); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addVScaleRangeAttr(unsigned MinValue, | 
 |                                              std::optional<unsigned> MaxValue) { | 
 |   return addVScaleRangeAttrFromRawRepr(packVScaleRangeArgs(MinValue, MaxValue)); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addVScaleRangeAttrFromRawRepr(uint64_t RawArgs) { | 
 |   // (0, 0) is not present hence ignore this case | 
 |   if (RawArgs == 0) | 
 |     return *this; | 
 |  | 
 |   return addRawIntAttr(Attribute::VScaleRange, RawArgs); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addUWTableAttr(UWTableKind Kind) { | 
 |   if (Kind == UWTableKind::None) | 
 |     return *this; | 
 |   return addRawIntAttr(Attribute::UWTable, uint64_t(Kind)); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addMemoryAttr(MemoryEffects ME) { | 
 |   return addRawIntAttr(Attribute::Memory, ME.toIntValue()); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addNoFPClassAttr(FPClassTest Mask) { | 
 |   if (Mask == fcNone) | 
 |     return *this; | 
 |  | 
 |   return addRawIntAttr(Attribute::NoFPClass, Mask); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addAllocKindAttr(AllocFnKind Kind) { | 
 |   return addRawIntAttr(Attribute::AllocKind, static_cast<uint64_t>(Kind)); | 
 | } | 
 |  | 
 | Type *AttrBuilder::getTypeAttr(Attribute::AttrKind Kind) const { | 
 |   assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute"); | 
 |   Attribute A = getAttribute(Kind); | 
 |   return A.isValid() ? A.getValueAsType() : nullptr; | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addTypeAttr(Attribute::AttrKind Kind, Type *Ty) { | 
 |   return addAttribute(Attribute::get(Ctx, Kind, Ty)); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) { | 
 |   return addTypeAttr(Attribute::ByVal, Ty); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addStructRetAttr(Type *Ty) { | 
 |   return addTypeAttr(Attribute::StructRet, Ty); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addByRefAttr(Type *Ty) { | 
 |   return addTypeAttr(Attribute::ByRef, Ty); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addPreallocatedAttr(Type *Ty) { | 
 |   return addTypeAttr(Attribute::Preallocated, Ty); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) { | 
 |   return addTypeAttr(Attribute::InAlloca, Ty); | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) { | 
 |   // TODO: Could make this O(n) as we're merging two sorted lists. | 
 |   for (const auto &I : B.attrs()) | 
 |     addAttribute(I); | 
 |  | 
 |   return *this; | 
 | } | 
 |  | 
 | AttrBuilder &AttrBuilder::remove(const AttributeMask &AM) { | 
 |   erase_if(Attrs, [&](Attribute A) { return AM.contains(A); }); | 
 |   return *this; | 
 | } | 
 |  | 
 | bool AttrBuilder::overlaps(const AttributeMask &AM) const { | 
 |   return any_of(Attrs, [&](Attribute A) { return AM.contains(A); }); | 
 | } | 
 |  | 
 | Attribute AttrBuilder::getAttribute(Attribute::AttrKind A) const { | 
 |   assert((unsigned)A < Attribute::EndAttrKinds && "Attribute out of range!"); | 
 |   auto It = lower_bound(Attrs, A, AttributeComparator()); | 
 |   if (It != Attrs.end() && It->hasAttribute(A)) | 
 |     return *It; | 
 |   return {}; | 
 | } | 
 |  | 
 | Attribute AttrBuilder::getAttribute(StringRef A) const { | 
 |   auto It = lower_bound(Attrs, A, AttributeComparator()); | 
 |   if (It != Attrs.end() && It->hasAttribute(A)) | 
 |     return *It; | 
 |   return {}; | 
 | } | 
 |  | 
 | bool AttrBuilder::contains(Attribute::AttrKind A) const { | 
 |   return getAttribute(A).isValid(); | 
 | } | 
 |  | 
 | bool AttrBuilder::contains(StringRef A) const { | 
 |   return getAttribute(A).isValid(); | 
 | } | 
 |  | 
 | bool AttrBuilder::operator==(const AttrBuilder &B) const { | 
 |   return Attrs == B.Attrs; | 
 | } | 
 |  | 
 | //===----------------------------------------------------------------------===// | 
 | // AttributeFuncs Function Defintions | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | /// Returns true if this is a type legal for the 'nofpclass' attribute. This | 
 | /// follows the same type rules as FPMathOperator. | 
 | /// | 
 | /// TODO: Consider relaxing to any FP type struct fields. | 
 | bool AttributeFuncs::isNoFPClassCompatibleType(Type *Ty) { | 
 |   while (ArrayType *ArrTy = dyn_cast<ArrayType>(Ty)) | 
 |     Ty = ArrTy->getElementType(); | 
 |   return Ty->isFPOrFPVectorTy(); | 
 | } | 
 |  | 
 | /// Which attributes cannot be applied to a type. | 
 | AttributeMask AttributeFuncs::typeIncompatible(Type *Ty, | 
 |                                                AttributeSafetyKind ASK) { | 
 |   AttributeMask Incompatible; | 
 |  | 
 |   if (!Ty->isIntegerTy()) { | 
 |     // Attributes that only apply to integers. | 
 |     if (ASK & ASK_SAFE_TO_DROP) | 
 |       Incompatible.addAttribute(Attribute::AllocAlign); | 
 |     if (ASK & ASK_UNSAFE_TO_DROP) | 
 |       Incompatible.addAttribute(Attribute::SExt).addAttribute(Attribute::ZExt); | 
 |   } | 
 |  | 
 |   if (!Ty->isPointerTy()) { | 
 |     // Attributes that only apply to pointers. | 
 |     if (ASK & ASK_SAFE_TO_DROP) | 
 |       Incompatible.addAttribute(Attribute::NoAlias) | 
 |           .addAttribute(Attribute::NoCapture) | 
 |           .addAttribute(Attribute::NonNull) | 
 |           .addAttribute(Attribute::ReadNone) | 
 |           .addAttribute(Attribute::ReadOnly) | 
 |           .addAttribute(Attribute::Dereferenceable) | 
 |           .addAttribute(Attribute::DereferenceableOrNull); | 
 |     if (ASK & ASK_UNSAFE_TO_DROP) | 
 |       Incompatible.addAttribute(Attribute::Nest) | 
 |           .addAttribute(Attribute::SwiftError) | 
 |           .addAttribute(Attribute::Preallocated) | 
 |           .addAttribute(Attribute::InAlloca) | 
 |           .addAttribute(Attribute::ByVal) | 
 |           .addAttribute(Attribute::StructRet) | 
 |           .addAttribute(Attribute::ByRef) | 
 |           .addAttribute(Attribute::ElementType) | 
 |           .addAttribute(Attribute::AllocatedPointer); | 
 |   } | 
 |  | 
 |     // Attributes that only apply to pointers or vectors of pointers. | 
 |   if (!Ty->isPtrOrPtrVectorTy()) { | 
 |     if (ASK & ASK_SAFE_TO_DROP) | 
 |       Incompatible.addAttribute(Attribute::Alignment); | 
 |   } | 
 |  | 
 |   if (ASK & ASK_SAFE_TO_DROP) { | 
 |     if (!isNoFPClassCompatibleType(Ty)) | 
 |       Incompatible.addAttribute(Attribute::NoFPClass); | 
 |   } | 
 |  | 
 |   // Some attributes can apply to all "values" but there are no `void` values. | 
 |   if (Ty->isVoidTy()) { | 
 |     if (ASK & ASK_SAFE_TO_DROP) | 
 |       Incompatible.addAttribute(Attribute::NoUndef); | 
 |   } | 
 |  | 
 |   return Incompatible; | 
 | } | 
 |  | 
 | AttributeMask AttributeFuncs::getUBImplyingAttributes() { | 
 |   AttributeMask AM; | 
 |   AM.addAttribute(Attribute::NoUndef); | 
 |   AM.addAttribute(Attribute::Dereferenceable); | 
 |   AM.addAttribute(Attribute::DereferenceableOrNull); | 
 |   return AM; | 
 | } | 
 |  | 
 | /// Callees with dynamic denormal modes are compatible with any caller mode. | 
 | static bool denormModeCompatible(DenormalMode CallerMode, | 
 |                                  DenormalMode CalleeMode) { | 
 |   if (CallerMode == CalleeMode || CalleeMode == DenormalMode::getDynamic()) | 
 |     return true; | 
 |  | 
 |   // If they don't exactly match, it's OK if the mismatched component is | 
 |   // dynamic. | 
 |   if (CalleeMode.Input == CallerMode.Input && | 
 |       CalleeMode.Output == DenormalMode::Dynamic) | 
 |     return true; | 
 |  | 
 |   if (CalleeMode.Output == CallerMode.Output && | 
 |       CalleeMode.Input == DenormalMode::Dynamic) | 
 |     return true; | 
 |   return false; | 
 | } | 
 |  | 
 | static bool checkDenormMode(const Function &Caller, const Function &Callee) { | 
 |   DenormalMode CallerMode = Caller.getDenormalModeRaw(); | 
 |   DenormalMode CalleeMode = Callee.getDenormalModeRaw(); | 
 |  | 
 |   if (denormModeCompatible(CallerMode, CalleeMode)) { | 
 |     DenormalMode CallerModeF32 = Caller.getDenormalModeF32Raw(); | 
 |     DenormalMode CalleeModeF32 = Callee.getDenormalModeF32Raw(); | 
 |     if (CallerModeF32 == DenormalMode::getInvalid()) | 
 |       CallerModeF32 = CallerMode; | 
 |     if (CalleeModeF32 == DenormalMode::getInvalid()) | 
 |       CalleeModeF32 = CalleeMode; | 
 |     return denormModeCompatible(CallerModeF32, CalleeModeF32); | 
 |   } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | template<typename AttrClass> | 
 | static bool isEqual(const Function &Caller, const Function &Callee) { | 
 |   return Caller.getFnAttribute(AttrClass::getKind()) == | 
 |          Callee.getFnAttribute(AttrClass::getKind()); | 
 | } | 
 |  | 
 | /// Compute the logical AND of the attributes of the caller and the | 
 | /// callee. | 
 | /// | 
 | /// This function sets the caller's attribute to false if the callee's attribute | 
 | /// is false. | 
 | template<typename AttrClass> | 
 | static void setAND(Function &Caller, const Function &Callee) { | 
 |   if (AttrClass::isSet(Caller, AttrClass::getKind()) && | 
 |       !AttrClass::isSet(Callee, AttrClass::getKind())) | 
 |     AttrClass::set(Caller, AttrClass::getKind(), false); | 
 | } | 
 |  | 
 | /// Compute the logical OR of the attributes of the caller and the | 
 | /// callee. | 
 | /// | 
 | /// This function sets the caller's attribute to true if the callee's attribute | 
 | /// is true. | 
 | template<typename AttrClass> | 
 | static void setOR(Function &Caller, const Function &Callee) { | 
 |   if (!AttrClass::isSet(Caller, AttrClass::getKind()) && | 
 |       AttrClass::isSet(Callee, AttrClass::getKind())) | 
 |     AttrClass::set(Caller, AttrClass::getKind(), true); | 
 | } | 
 |  | 
 | /// If the inlined function had a higher stack protection level than the | 
 | /// calling function, then bump up the caller's stack protection level. | 
 | static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) { | 
 |   // If the calling function has *no* stack protection level (e.g. it was built | 
 |   // with Clang's -fno-stack-protector or no_stack_protector attribute), don't | 
 |   // change it as that could change the program's semantics. | 
 |   if (!Caller.hasStackProtectorFnAttr()) | 
 |     return; | 
 |  | 
 |   // If upgrading the SSP attribute, clear out the old SSP Attributes first. | 
 |   // Having multiple SSP attributes doesn't actually hurt, but it adds useless | 
 |   // clutter to the IR. | 
 |   AttributeMask OldSSPAttr; | 
 |   OldSSPAttr.addAttribute(Attribute::StackProtect) | 
 |       .addAttribute(Attribute::StackProtectStrong) | 
 |       .addAttribute(Attribute::StackProtectReq); | 
 |  | 
 |   if (Callee.hasFnAttribute(Attribute::StackProtectReq)) { | 
 |     Caller.removeFnAttrs(OldSSPAttr); | 
 |     Caller.addFnAttr(Attribute::StackProtectReq); | 
 |   } else if (Callee.hasFnAttribute(Attribute::StackProtectStrong) && | 
 |              !Caller.hasFnAttribute(Attribute::StackProtectReq)) { | 
 |     Caller.removeFnAttrs(OldSSPAttr); | 
 |     Caller.addFnAttr(Attribute::StackProtectStrong); | 
 |   } else if (Callee.hasFnAttribute(Attribute::StackProtect) && | 
 |              !Caller.hasFnAttribute(Attribute::StackProtectReq) && | 
 |              !Caller.hasFnAttribute(Attribute::StackProtectStrong)) | 
 |     Caller.addFnAttr(Attribute::StackProtect); | 
 | } | 
 |  | 
 | /// If the inlined function required stack probes, then ensure that | 
 | /// the calling function has those too. | 
 | static void adjustCallerStackProbes(Function &Caller, const Function &Callee) { | 
 |   if (!Caller.hasFnAttribute("probe-stack") && | 
 |       Callee.hasFnAttribute("probe-stack")) { | 
 |     Caller.addFnAttr(Callee.getFnAttribute("probe-stack")); | 
 |   } | 
 | } | 
 |  | 
 | /// If the inlined function defines the size of guard region | 
 | /// on the stack, then ensure that the calling function defines a guard region | 
 | /// that is no larger. | 
 | static void | 
 | adjustCallerStackProbeSize(Function &Caller, const Function &Callee) { | 
 |   Attribute CalleeAttr = Callee.getFnAttribute("stack-probe-size"); | 
 |   if (CalleeAttr.isValid()) { | 
 |     Attribute CallerAttr = Caller.getFnAttribute("stack-probe-size"); | 
 |     if (CallerAttr.isValid()) { | 
 |       uint64_t CallerStackProbeSize, CalleeStackProbeSize; | 
 |       CallerAttr.getValueAsString().getAsInteger(0, CallerStackProbeSize); | 
 |       CalleeAttr.getValueAsString().getAsInteger(0, CalleeStackProbeSize); | 
 |  | 
 |       if (CallerStackProbeSize > CalleeStackProbeSize) { | 
 |         Caller.addFnAttr(CalleeAttr); | 
 |       } | 
 |     } else { | 
 |       Caller.addFnAttr(CalleeAttr); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /// If the inlined function defines a min legal vector width, then ensure | 
 | /// the calling function has the same or larger min legal vector width. If the | 
 | /// caller has the attribute, but the callee doesn't, we need to remove the | 
 | /// attribute from the caller since we can't make any guarantees about the | 
 | /// caller's requirements. | 
 | /// This function is called after the inlining decision has been made so we have | 
 | /// to merge the attribute this way. Heuristics that would use | 
 | /// min-legal-vector-width to determine inline compatibility would need to be | 
 | /// handled as part of inline cost analysis. | 
 | static void | 
 | adjustMinLegalVectorWidth(Function &Caller, const Function &Callee) { | 
 |   Attribute CallerAttr = Caller.getFnAttribute("min-legal-vector-width"); | 
 |   if (CallerAttr.isValid()) { | 
 |     Attribute CalleeAttr = Callee.getFnAttribute("min-legal-vector-width"); | 
 |     if (CalleeAttr.isValid()) { | 
 |       uint64_t CallerVectorWidth, CalleeVectorWidth; | 
 |       CallerAttr.getValueAsString().getAsInteger(0, CallerVectorWidth); | 
 |       CalleeAttr.getValueAsString().getAsInteger(0, CalleeVectorWidth); | 
 |       if (CallerVectorWidth < CalleeVectorWidth) | 
 |         Caller.addFnAttr(CalleeAttr); | 
 |     } else { | 
 |       // If the callee doesn't have the attribute then we don't know anything | 
 |       // and must drop the attribute from the caller. | 
 |       Caller.removeFnAttr("min-legal-vector-width"); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /// If the inlined function has null_pointer_is_valid attribute, | 
 | /// set this attribute in the caller post inlining. | 
 | static void | 
 | adjustNullPointerValidAttr(Function &Caller, const Function &Callee) { | 
 |   if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) { | 
 |     Caller.addFnAttr(Attribute::NullPointerIsValid); | 
 |   } | 
 | } | 
 |  | 
 | struct EnumAttr { | 
 |   static bool isSet(const Function &Fn, | 
 |                     Attribute::AttrKind Kind) { | 
 |     return Fn.hasFnAttribute(Kind); | 
 |   } | 
 |  | 
 |   static void set(Function &Fn, | 
 |                   Attribute::AttrKind Kind, bool Val) { | 
 |     if (Val) | 
 |       Fn.addFnAttr(Kind); | 
 |     else | 
 |       Fn.removeFnAttr(Kind); | 
 |   } | 
 | }; | 
 |  | 
 | struct StrBoolAttr { | 
 |   static bool isSet(const Function &Fn, | 
 |                     StringRef Kind) { | 
 |     auto A = Fn.getFnAttribute(Kind); | 
 |     return A.getValueAsString().equals("true"); | 
 |   } | 
 |  | 
 |   static void set(Function &Fn, | 
 |                   StringRef Kind, bool Val) { | 
 |     Fn.addFnAttr(Kind, Val ? "true" : "false"); | 
 |   } | 
 | }; | 
 |  | 
 | #define GET_ATTR_NAMES | 
 | #define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME)                                \ | 
 |   struct ENUM_NAME##Attr : EnumAttr {                                          \ | 
 |     static enum Attribute::AttrKind getKind() {                                \ | 
 |       return llvm::Attribute::ENUM_NAME;                                       \ | 
 |     }                                                                          \ | 
 |   }; | 
 | #define ATTRIBUTE_STRBOOL(ENUM_NAME, DISPLAY_NAME)                             \ | 
 |   struct ENUM_NAME##Attr : StrBoolAttr {                                       \ | 
 |     static StringRef getKind() { return #DISPLAY_NAME; }                       \ | 
 |   }; | 
 | #include "llvm/IR/Attributes.inc" | 
 |  | 
 | #define GET_ATTR_COMPAT_FUNC | 
 | #include "llvm/IR/Attributes.inc" | 
 |  | 
 | bool AttributeFuncs::areInlineCompatible(const Function &Caller, | 
 |                                          const Function &Callee) { | 
 |   return hasCompatibleFnAttrs(Caller, Callee); | 
 | } | 
 |  | 
 | bool AttributeFuncs::areOutlineCompatible(const Function &A, | 
 |                                           const Function &B) { | 
 |   return hasCompatibleFnAttrs(A, B); | 
 | } | 
 |  | 
 | void AttributeFuncs::mergeAttributesForInlining(Function &Caller, | 
 |                                                 const Function &Callee) { | 
 |   mergeFnAttrs(Caller, Callee); | 
 | } | 
 |  | 
 | void AttributeFuncs::mergeAttributesForOutlining(Function &Base, | 
 |                                                 const Function &ToMerge) { | 
 |  | 
 |   // We merge functions so that they meet the most general case. | 
 |   // For example, if the NoNansFPMathAttr is set in one function, but not in | 
 |   // the other, in the merged function we can say that the NoNansFPMathAttr | 
 |   // is not set. | 
 |   // However if we have the SpeculativeLoadHardeningAttr set true in one | 
 |   // function, but not the other, we make sure that the function retains | 
 |   // that aspect in the merged function. | 
 |   mergeFnAttrs(Base, ToMerge); | 
 | } | 
 |  | 
 | void AttributeFuncs::updateMinLegalVectorWidthAttr(Function &Fn, | 
 |                                                    uint64_t Width) { | 
 |   Attribute Attr = Fn.getFnAttribute("min-legal-vector-width"); | 
 |   if (Attr.isValid()) { | 
 |     uint64_t OldWidth; | 
 |     Attr.getValueAsString().getAsInteger(0, OldWidth); | 
 |     if (Width > OldWidth) | 
 |       Fn.addFnAttr("min-legal-vector-width", llvm::utostr(Width)); | 
 |   } | 
 | } |