Path: blob/main/contrib/llvm-project/llvm/lib/IR/Attributes.cpp
35234 views
//===- Attributes.cpp - Implement AttributesList --------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// \file9// This file implements the Attribute, AttributeImpl, AttrBuilder,10// AttributeListImpl, and AttributeList classes.11//12//===----------------------------------------------------------------------===//1314#include "llvm/IR/Attributes.h"15#include "AttributeImpl.h"16#include "LLVMContextImpl.h"17#include "llvm/ADT/ArrayRef.h"18#include "llvm/ADT/FoldingSet.h"19#include "llvm/ADT/STLExtras.h"20#include "llvm/ADT/SmallVector.h"21#include "llvm/ADT/StringExtras.h"22#include "llvm/ADT/StringRef.h"23#include "llvm/ADT/StringSwitch.h"24#include "llvm/Config/llvm-config.h"25#include "llvm/IR/AttributeMask.h"26#include "llvm/IR/ConstantRange.h"27#include "llvm/IR/ConstantRangeList.h"28#include "llvm/IR/Function.h"29#include "llvm/IR/LLVMContext.h"30#include "llvm/IR/Type.h"31#include "llvm/Support/Compiler.h"32#include "llvm/Support/ErrorHandling.h"33#include "llvm/Support/ModRef.h"34#include "llvm/Support/raw_ostream.h"35#include <algorithm>36#include <cassert>37#include <cstddef>38#include <cstdint>39#include <limits>40#include <optional>41#include <string>42#include <tuple>43#include <utility>4445using namespace llvm;4647//===----------------------------------------------------------------------===//48// Attribute Construction Methods49//===----------------------------------------------------------------------===//5051// allocsize has two integer arguments, but because they're both 32 bits, we can52// pack them into one 64-bit value, at the cost of making said value53// nonsensical.54//55// In order to do this, we need to reserve one value of the second (optional)56// allocsize argument to signify "not present."57static const unsigned AllocSizeNumElemsNotPresent = -1;5859static uint64_t packAllocSizeArgs(unsigned ElemSizeArg,60const std::optional<unsigned> &NumElemsArg) {61assert((!NumElemsArg || *NumElemsArg != AllocSizeNumElemsNotPresent) &&62"Attempting to pack a reserved value");6364return uint64_t(ElemSizeArg) << 32 |65NumElemsArg.value_or(AllocSizeNumElemsNotPresent);66}6768static std::pair<unsigned, std::optional<unsigned>>69unpackAllocSizeArgs(uint64_t Num) {70unsigned NumElems = Num & std::numeric_limits<unsigned>::max();71unsigned ElemSizeArg = Num >> 32;7273std::optional<unsigned> NumElemsArg;74if (NumElems != AllocSizeNumElemsNotPresent)75NumElemsArg = NumElems;76return std::make_pair(ElemSizeArg, NumElemsArg);77}7879static uint64_t packVScaleRangeArgs(unsigned MinValue,80std::optional<unsigned> MaxValue) {81return uint64_t(MinValue) << 32 | MaxValue.value_or(0);82}8384static std::pair<unsigned, std::optional<unsigned>>85unpackVScaleRangeArgs(uint64_t Value) {86unsigned MaxValue = Value & std::numeric_limits<unsigned>::max();87unsigned MinValue = Value >> 32;8889return std::make_pair(MinValue,90MaxValue > 0 ? MaxValue : std::optional<unsigned>());91}9293Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,94uint64_t Val) {95bool IsIntAttr = Attribute::isIntAttrKind(Kind);96assert((IsIntAttr || Attribute::isEnumAttrKind(Kind)) &&97"Not an enum or int attribute");9899LLVMContextImpl *pImpl = Context.pImpl;100FoldingSetNodeID ID;101ID.AddInteger(Kind);102if (IsIntAttr)103ID.AddInteger(Val);104else105assert(Val == 0 && "Value must be zero for enum attributes");106107void *InsertPoint;108AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);109110if (!PA) {111// If we didn't find any existing attributes of the same shape then create a112// new one and insert it.113if (!IsIntAttr)114PA = new (pImpl->Alloc) EnumAttributeImpl(Kind);115else116PA = new (pImpl->Alloc) IntAttributeImpl(Kind, Val);117pImpl->AttrsSet.InsertNode(PA, InsertPoint);118}119120// Return the Attribute that we found or created.121return Attribute(PA);122}123124Attribute Attribute::get(LLVMContext &Context, StringRef Kind, StringRef Val) {125LLVMContextImpl *pImpl = Context.pImpl;126FoldingSetNodeID ID;127ID.AddString(Kind);128if (!Val.empty()) ID.AddString(Val);129130void *InsertPoint;131AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);132133if (!PA) {134// If we didn't find any existing attributes of the same shape then create a135// new one and insert it.136void *Mem =137pImpl->Alloc.Allocate(StringAttributeImpl::totalSizeToAlloc(Kind, Val),138alignof(StringAttributeImpl));139PA = new (Mem) StringAttributeImpl(Kind, Val);140pImpl->AttrsSet.InsertNode(PA, InsertPoint);141}142143// Return the Attribute that we found or created.144return Attribute(PA);145}146147Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,148Type *Ty) {149assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute");150LLVMContextImpl *pImpl = Context.pImpl;151FoldingSetNodeID ID;152ID.AddInteger(Kind);153ID.AddPointer(Ty);154155void *InsertPoint;156AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);157158if (!PA) {159// If we didn't find any existing attributes of the same shape then create a160// new one and insert it.161PA = new (pImpl->Alloc) TypeAttributeImpl(Kind, Ty);162pImpl->AttrsSet.InsertNode(PA, InsertPoint);163}164165// Return the Attribute that we found or created.166return Attribute(PA);167}168169Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,170const ConstantRange &CR) {171assert(Attribute::isConstantRangeAttrKind(Kind) &&172"Not a ConstantRange attribute");173LLVMContextImpl *pImpl = Context.pImpl;174FoldingSetNodeID ID;175ID.AddInteger(Kind);176CR.getLower().Profile(ID);177CR.getUpper().Profile(ID);178179void *InsertPoint;180AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);181182if (!PA) {183// If we didn't find any existing attributes of the same shape then create a184// new one and insert it.185PA = new (pImpl->ConstantRangeAttributeAlloc.Allocate())186ConstantRangeAttributeImpl(Kind, CR);187pImpl->AttrsSet.InsertNode(PA, InsertPoint);188}189190// Return the Attribute that we found or created.191return Attribute(PA);192}193194Attribute Attribute::get(LLVMContext &Context, Attribute::AttrKind Kind,195ArrayRef<ConstantRange> Val) {196assert(Attribute::isConstantRangeListAttrKind(Kind) &&197"Not a ConstantRangeList attribute");198LLVMContextImpl *pImpl = Context.pImpl;199FoldingSetNodeID ID;200ID.AddInteger(Kind);201ID.AddInteger(Val.size());202for (auto &CR : Val) {203CR.getLower().Profile(ID);204CR.getUpper().Profile(ID);205}206207void *InsertPoint;208AttributeImpl *PA = pImpl->AttrsSet.FindNodeOrInsertPos(ID, InsertPoint);209210if (!PA) {211// If we didn't find any existing attributes of the same shape then create a212// new one and insert it.213// ConstantRangeListAttributeImpl is a dynamically sized class and cannot214// use SpecificBumpPtrAllocator. Instead, we use normal Alloc for215// allocation and record the allocated pointer in216// `ConstantRangeListAttributes`. LLVMContext destructor will call the217// destructor of the allocated pointer explicitly.218void *Mem = pImpl->Alloc.Allocate(219ConstantRangeListAttributeImpl::totalSizeToAlloc(Val),220alignof(ConstantRangeListAttributeImpl));221PA = new (Mem) ConstantRangeListAttributeImpl(Kind, Val);222pImpl->AttrsSet.InsertNode(PA, InsertPoint);223pImpl->ConstantRangeListAttributes.push_back(224reinterpret_cast<ConstantRangeListAttributeImpl *>(PA));225}226227// Return the Attribute that we found or created.228return Attribute(PA);229}230231Attribute Attribute::getWithAlignment(LLVMContext &Context, Align A) {232assert(A <= llvm::Value::MaximumAlignment && "Alignment too large.");233return get(Context, Alignment, A.value());234}235236Attribute Attribute::getWithStackAlignment(LLVMContext &Context, Align A) {237assert(A <= 0x100 && "Alignment too large.");238return get(Context, StackAlignment, A.value());239}240241Attribute Attribute::getWithDereferenceableBytes(LLVMContext &Context,242uint64_t Bytes) {243assert(Bytes && "Bytes must be non-zero.");244return get(Context, Dereferenceable, Bytes);245}246247Attribute Attribute::getWithDereferenceableOrNullBytes(LLVMContext &Context,248uint64_t Bytes) {249assert(Bytes && "Bytes must be non-zero.");250return get(Context, DereferenceableOrNull, Bytes);251}252253Attribute Attribute::getWithByValType(LLVMContext &Context, Type *Ty) {254return get(Context, ByVal, Ty);255}256257Attribute Attribute::getWithStructRetType(LLVMContext &Context, Type *Ty) {258return get(Context, StructRet, Ty);259}260261Attribute Attribute::getWithByRefType(LLVMContext &Context, Type *Ty) {262return get(Context, ByRef, Ty);263}264265Attribute Attribute::getWithPreallocatedType(LLVMContext &Context, Type *Ty) {266return get(Context, Preallocated, Ty);267}268269Attribute Attribute::getWithInAllocaType(LLVMContext &Context, Type *Ty) {270return get(Context, InAlloca, Ty);271}272273Attribute Attribute::getWithUWTableKind(LLVMContext &Context,274UWTableKind Kind) {275return get(Context, UWTable, uint64_t(Kind));276}277278Attribute Attribute::getWithMemoryEffects(LLVMContext &Context,279MemoryEffects ME) {280return get(Context, Memory, ME.toIntValue());281}282283Attribute Attribute::getWithNoFPClass(LLVMContext &Context,284FPClassTest ClassMask) {285return get(Context, NoFPClass, ClassMask);286}287288Attribute289Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg,290const std::optional<unsigned> &NumElemsArg) {291assert(!(ElemSizeArg == 0 && NumElemsArg && *NumElemsArg == 0) &&292"Invalid allocsize arguments -- given allocsize(0, 0)");293return get(Context, AllocSize, packAllocSizeArgs(ElemSizeArg, NumElemsArg));294}295296Attribute Attribute::getWithVScaleRangeArgs(LLVMContext &Context,297unsigned MinValue,298unsigned MaxValue) {299return get(Context, VScaleRange, packVScaleRangeArgs(MinValue, MaxValue));300}301302Attribute::AttrKind Attribute::getAttrKindFromName(StringRef AttrName) {303return StringSwitch<Attribute::AttrKind>(AttrName)304#define GET_ATTR_NAMES305#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \306.Case(#DISPLAY_NAME, Attribute::ENUM_NAME)307#include "llvm/IR/Attributes.inc"308.Default(Attribute::None);309}310311StringRef Attribute::getNameFromAttrKind(Attribute::AttrKind AttrKind) {312switch (AttrKind) {313#define GET_ATTR_NAMES314#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \315case Attribute::ENUM_NAME: \316return #DISPLAY_NAME;317#include "llvm/IR/Attributes.inc"318case Attribute::None:319return "none";320default:321llvm_unreachable("invalid Kind");322}323}324325bool Attribute::isExistingAttribute(StringRef Name) {326return StringSwitch<bool>(Name)327#define GET_ATTR_NAMES328#define ATTRIBUTE_ALL(ENUM_NAME, DISPLAY_NAME) .Case(#DISPLAY_NAME, true)329#include "llvm/IR/Attributes.inc"330.Default(false);331}332333//===----------------------------------------------------------------------===//334// Attribute Accessor Methods335//===----------------------------------------------------------------------===//336337bool Attribute::isEnumAttribute() const {338return pImpl && pImpl->isEnumAttribute();339}340341bool Attribute::isIntAttribute() const {342return pImpl && pImpl->isIntAttribute();343}344345bool Attribute::isStringAttribute() const {346return pImpl && pImpl->isStringAttribute();347}348349bool Attribute::isTypeAttribute() const {350return pImpl && pImpl->isTypeAttribute();351}352353bool Attribute::isConstantRangeAttribute() const {354return pImpl && pImpl->isConstantRangeAttribute();355}356357bool Attribute::isConstantRangeListAttribute() const {358return pImpl && pImpl->isConstantRangeListAttribute();359}360361Attribute::AttrKind Attribute::getKindAsEnum() const {362if (!pImpl) return None;363assert((isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||364isConstantRangeAttribute() || isConstantRangeListAttribute()) &&365"Invalid attribute type to get the kind as an enum!");366return pImpl->getKindAsEnum();367}368369uint64_t Attribute::getValueAsInt() const {370if (!pImpl) return 0;371assert(isIntAttribute() &&372"Expected the attribute to be an integer attribute!");373return pImpl->getValueAsInt();374}375376bool Attribute::getValueAsBool() const {377if (!pImpl) return false;378assert(isStringAttribute() &&379"Expected the attribute to be a string attribute!");380return pImpl->getValueAsBool();381}382383StringRef Attribute::getKindAsString() const {384if (!pImpl) return {};385assert(isStringAttribute() &&386"Invalid attribute type to get the kind as a string!");387return pImpl->getKindAsString();388}389390StringRef Attribute::getValueAsString() const {391if (!pImpl) return {};392assert(isStringAttribute() &&393"Invalid attribute type to get the value as a string!");394return pImpl->getValueAsString();395}396397Type *Attribute::getValueAsType() const {398if (!pImpl) return {};399assert(isTypeAttribute() &&400"Invalid attribute type to get the value as a type!");401return pImpl->getValueAsType();402}403404const ConstantRange &Attribute::getValueAsConstantRange() const {405assert(isConstantRangeAttribute() &&406"Invalid attribute type to get the value as a ConstantRange!");407return pImpl->getValueAsConstantRange();408}409410ArrayRef<ConstantRange> Attribute::getValueAsConstantRangeList() const {411assert(isConstantRangeListAttribute() &&412"Invalid attribute type to get the value as a ConstantRangeList!");413return pImpl->getValueAsConstantRangeList();414}415416bool Attribute::hasAttribute(AttrKind Kind) const {417return (pImpl && pImpl->hasAttribute(Kind)) || (!pImpl && Kind == None);418}419420bool Attribute::hasAttribute(StringRef Kind) const {421if (!isStringAttribute()) return false;422return pImpl && pImpl->hasAttribute(Kind);423}424425MaybeAlign Attribute::getAlignment() const {426assert(hasAttribute(Attribute::Alignment) &&427"Trying to get alignment from non-alignment attribute!");428return MaybeAlign(pImpl->getValueAsInt());429}430431MaybeAlign Attribute::getStackAlignment() const {432assert(hasAttribute(Attribute::StackAlignment) &&433"Trying to get alignment from non-alignment attribute!");434return MaybeAlign(pImpl->getValueAsInt());435}436437uint64_t Attribute::getDereferenceableBytes() const {438assert(hasAttribute(Attribute::Dereferenceable) &&439"Trying to get dereferenceable bytes from "440"non-dereferenceable attribute!");441return pImpl->getValueAsInt();442}443444uint64_t Attribute::getDereferenceableOrNullBytes() const {445assert(hasAttribute(Attribute::DereferenceableOrNull) &&446"Trying to get dereferenceable bytes from "447"non-dereferenceable attribute!");448return pImpl->getValueAsInt();449}450451std::pair<unsigned, std::optional<unsigned>>452Attribute::getAllocSizeArgs() const {453assert(hasAttribute(Attribute::AllocSize) &&454"Trying to get allocsize args from non-allocsize attribute");455return unpackAllocSizeArgs(pImpl->getValueAsInt());456}457458unsigned Attribute::getVScaleRangeMin() const {459assert(hasAttribute(Attribute::VScaleRange) &&460"Trying to get vscale args from non-vscale attribute");461return unpackVScaleRangeArgs(pImpl->getValueAsInt()).first;462}463464std::optional<unsigned> Attribute::getVScaleRangeMax() const {465assert(hasAttribute(Attribute::VScaleRange) &&466"Trying to get vscale args from non-vscale attribute");467return unpackVScaleRangeArgs(pImpl->getValueAsInt()).second;468}469470UWTableKind Attribute::getUWTableKind() const {471assert(hasAttribute(Attribute::UWTable) &&472"Trying to get unwind table kind from non-uwtable attribute");473return UWTableKind(pImpl->getValueAsInt());474}475476AllocFnKind Attribute::getAllocKind() const {477assert(hasAttribute(Attribute::AllocKind) &&478"Trying to get allockind value from non-allockind attribute");479return AllocFnKind(pImpl->getValueAsInt());480}481482MemoryEffects Attribute::getMemoryEffects() const {483assert(hasAttribute(Attribute::Memory) &&484"Can only call getMemoryEffects() on memory attribute");485return MemoryEffects::createFromIntValue(pImpl->getValueAsInt());486}487488FPClassTest Attribute::getNoFPClass() const {489assert(hasAttribute(Attribute::NoFPClass) &&490"Can only call getNoFPClass() on nofpclass attribute");491return static_cast<FPClassTest>(pImpl->getValueAsInt());492}493494const ConstantRange &Attribute::getRange() const {495assert(hasAttribute(Attribute::Range) &&496"Trying to get range args from non-range attribute");497return pImpl->getValueAsConstantRange();498}499500ArrayRef<ConstantRange> Attribute::getInitializes() const {501assert(hasAttribute(Attribute::Initializes) &&502"Trying to get initializes attr from non-ConstantRangeList attribute");503return pImpl->getValueAsConstantRangeList();504}505506static const char *getModRefStr(ModRefInfo MR) {507switch (MR) {508case ModRefInfo::NoModRef:509return "none";510case ModRefInfo::Ref:511return "read";512case ModRefInfo::Mod:513return "write";514case ModRefInfo::ModRef:515return "readwrite";516}517llvm_unreachable("Invalid ModRefInfo");518}519520std::string Attribute::getAsString(bool InAttrGrp) const {521if (!pImpl) return {};522523if (isEnumAttribute())524return getNameFromAttrKind(getKindAsEnum()).str();525526if (isTypeAttribute()) {527std::string Result = getNameFromAttrKind(getKindAsEnum()).str();528Result += '(';529raw_string_ostream OS(Result);530getValueAsType()->print(OS, false, true);531OS.flush();532Result += ')';533return Result;534}535536// FIXME: These should be output like this:537//538// align=4539// alignstack=8540//541if (hasAttribute(Attribute::Alignment))542return (InAttrGrp ? "align=" + Twine(getValueAsInt())543: "align " + Twine(getValueAsInt()))544.str();545546auto AttrWithBytesToString = [&](const char *Name) {547return (InAttrGrp ? Name + ("=" + Twine(getValueAsInt()))548: Name + ("(" + Twine(getValueAsInt())) + ")")549.str();550};551552if (hasAttribute(Attribute::StackAlignment))553return AttrWithBytesToString("alignstack");554555if (hasAttribute(Attribute::Dereferenceable))556return AttrWithBytesToString("dereferenceable");557558if (hasAttribute(Attribute::DereferenceableOrNull))559return AttrWithBytesToString("dereferenceable_or_null");560561if (hasAttribute(Attribute::AllocSize)) {562unsigned ElemSize;563std::optional<unsigned> NumElems;564std::tie(ElemSize, NumElems) = getAllocSizeArgs();565566return (NumElems567? "allocsize(" + Twine(ElemSize) + "," + Twine(*NumElems) + ")"568: "allocsize(" + Twine(ElemSize) + ")")569.str();570}571572if (hasAttribute(Attribute::VScaleRange)) {573unsigned MinValue = getVScaleRangeMin();574std::optional<unsigned> MaxValue = getVScaleRangeMax();575return ("vscale_range(" + Twine(MinValue) + "," +576Twine(MaxValue.value_or(0)) + ")")577.str();578}579580if (hasAttribute(Attribute::UWTable)) {581UWTableKind Kind = getUWTableKind();582assert(Kind != UWTableKind::None && "uwtable attribute should not be none");583return Kind == UWTableKind::Default ? "uwtable" : "uwtable(sync)";584}585586if (hasAttribute(Attribute::AllocKind)) {587AllocFnKind Kind = getAllocKind();588SmallVector<StringRef> parts;589if ((Kind & AllocFnKind::Alloc) != AllocFnKind::Unknown)590parts.push_back("alloc");591if ((Kind & AllocFnKind::Realloc) != AllocFnKind::Unknown)592parts.push_back("realloc");593if ((Kind & AllocFnKind::Free) != AllocFnKind::Unknown)594parts.push_back("free");595if ((Kind & AllocFnKind::Uninitialized) != AllocFnKind::Unknown)596parts.push_back("uninitialized");597if ((Kind & AllocFnKind::Zeroed) != AllocFnKind::Unknown)598parts.push_back("zeroed");599if ((Kind & AllocFnKind::Aligned) != AllocFnKind::Unknown)600parts.push_back("aligned");601return ("allockind(\"" +602Twine(llvm::join(parts.begin(), parts.end(), ",")) + "\")")603.str();604}605606if (hasAttribute(Attribute::Memory)) {607std::string Result;608raw_string_ostream OS(Result);609bool First = true;610OS << "memory(";611612MemoryEffects ME = getMemoryEffects();613614// Print access kind for "other" as the default access kind. This way it615// will apply to any new location kinds that get split out of "other".616ModRefInfo OtherMR = ME.getModRef(IRMemLocation::Other);617if (OtherMR != ModRefInfo::NoModRef || ME.getModRef() == OtherMR) {618First = false;619OS << getModRefStr(OtherMR);620}621622for (auto Loc : MemoryEffects::locations()) {623ModRefInfo MR = ME.getModRef(Loc);624if (MR == OtherMR)625continue;626627if (!First)628OS << ", ";629First = false;630631switch (Loc) {632case IRMemLocation::ArgMem:633OS << "argmem: ";634break;635case IRMemLocation::InaccessibleMem:636OS << "inaccessiblemem: ";637break;638case IRMemLocation::Other:639llvm_unreachable("This is represented as the default access kind");640}641OS << getModRefStr(MR);642}643OS << ")";644OS.flush();645return Result;646}647648if (hasAttribute(Attribute::NoFPClass)) {649std::string Result = "nofpclass";650raw_string_ostream OS(Result);651OS << getNoFPClass();652return Result;653}654655if (hasAttribute(Attribute::Range)) {656std::string Result;657raw_string_ostream OS(Result);658const ConstantRange &CR = getValueAsConstantRange();659OS << "range(";660OS << "i" << CR.getBitWidth() << " ";661OS << CR.getLower() << ", " << CR.getUpper();662OS << ")";663OS.flush();664return Result;665}666667if (hasAttribute(Attribute::Initializes)) {668std::string Result;669raw_string_ostream OS(Result);670ConstantRangeList CRL = getInitializes();671OS << "initializes(";672CRL.print(OS);673OS << ")";674OS.flush();675return Result;676}677678// Convert target-dependent attributes to strings of the form:679//680// "kind"681// "kind" = "value"682//683if (isStringAttribute()) {684std::string Result;685{686raw_string_ostream OS(Result);687OS << '"' << getKindAsString() << '"';688689// Since some attribute strings contain special characters that cannot be690// printable, those have to be escaped to make the attribute value691// printable as is. e.g. "\01__gnu_mcount_nc"692const auto &AttrVal = pImpl->getValueAsString();693if (!AttrVal.empty()) {694OS << "=\"";695printEscapedString(AttrVal, OS);696OS << "\"";697}698}699return Result;700}701702llvm_unreachable("Unknown attribute");703}704705bool Attribute::hasParentContext(LLVMContext &C) const {706assert(isValid() && "invalid Attribute doesn't refer to any context");707FoldingSetNodeID ID;708pImpl->Profile(ID);709void *Unused;710return C.pImpl->AttrsSet.FindNodeOrInsertPos(ID, Unused) == pImpl;711}712713bool Attribute::operator<(Attribute A) const {714if (!pImpl && !A.pImpl) return false;715if (!pImpl) return true;716if (!A.pImpl) return false;717return *pImpl < *A.pImpl;718}719720void Attribute::Profile(FoldingSetNodeID &ID) const {721ID.AddPointer(pImpl);722}723724enum AttributeProperty {725FnAttr = (1 << 0),726ParamAttr = (1 << 1),727RetAttr = (1 << 2),728};729730#define GET_ATTR_PROP_TABLE731#include "llvm/IR/Attributes.inc"732733static bool hasAttributeProperty(Attribute::AttrKind Kind,734AttributeProperty Prop) {735unsigned Index = Kind - 1;736assert(Index < std::size(AttrPropTable) && "Invalid attribute kind");737return AttrPropTable[Index] & Prop;738}739740bool Attribute::canUseAsFnAttr(AttrKind Kind) {741return hasAttributeProperty(Kind, AttributeProperty::FnAttr);742}743744bool Attribute::canUseAsParamAttr(AttrKind Kind) {745return hasAttributeProperty(Kind, AttributeProperty::ParamAttr);746}747748bool Attribute::canUseAsRetAttr(AttrKind Kind) {749return hasAttributeProperty(Kind, AttributeProperty::RetAttr);750}751752//===----------------------------------------------------------------------===//753// AttributeImpl Definition754//===----------------------------------------------------------------------===//755756bool AttributeImpl::hasAttribute(Attribute::AttrKind A) const {757if (isStringAttribute()) return false;758return getKindAsEnum() == A;759}760761bool AttributeImpl::hasAttribute(StringRef Kind) const {762if (!isStringAttribute()) return false;763return getKindAsString() == Kind;764}765766Attribute::AttrKind AttributeImpl::getKindAsEnum() const {767assert(isEnumAttribute() || isIntAttribute() || isTypeAttribute() ||768isConstantRangeAttribute() || isConstantRangeListAttribute());769return static_cast<const EnumAttributeImpl *>(this)->getEnumKind();770}771772uint64_t AttributeImpl::getValueAsInt() const {773assert(isIntAttribute());774return static_cast<const IntAttributeImpl *>(this)->getValue();775}776777bool AttributeImpl::getValueAsBool() const {778assert(getValueAsString().empty() || getValueAsString() == "false" || getValueAsString() == "true");779return getValueAsString() == "true";780}781782StringRef AttributeImpl::getKindAsString() const {783assert(isStringAttribute());784return static_cast<const StringAttributeImpl *>(this)->getStringKind();785}786787StringRef AttributeImpl::getValueAsString() const {788assert(isStringAttribute());789return static_cast<const StringAttributeImpl *>(this)->getStringValue();790}791792Type *AttributeImpl::getValueAsType() const {793assert(isTypeAttribute());794return static_cast<const TypeAttributeImpl *>(this)->getTypeValue();795}796797const ConstantRange &AttributeImpl::getValueAsConstantRange() const {798assert(isConstantRangeAttribute());799return static_cast<const ConstantRangeAttributeImpl *>(this)800->getConstantRangeValue();801}802803ArrayRef<ConstantRange> AttributeImpl::getValueAsConstantRangeList() const {804assert(isConstantRangeListAttribute());805return static_cast<const ConstantRangeListAttributeImpl *>(this)806->getConstantRangeListValue();807}808809bool AttributeImpl::operator<(const AttributeImpl &AI) const {810if (this == &AI)811return false;812813// This sorts the attributes with Attribute::AttrKinds coming first (sorted814// relative to their enum value) and then strings.815if (!isStringAttribute()) {816if (AI.isStringAttribute())817return true;818if (getKindAsEnum() != AI.getKindAsEnum())819return getKindAsEnum() < AI.getKindAsEnum();820assert(!AI.isEnumAttribute() && "Non-unique attribute");821assert(!AI.isTypeAttribute() && "Comparison of types would be unstable");822assert(!AI.isConstantRangeAttribute() && "Unclear how to compare ranges");823assert(!AI.isConstantRangeListAttribute() &&824"Unclear how to compare range list");825// TODO: Is this actually needed?826assert(AI.isIntAttribute() && "Only possibility left");827return getValueAsInt() < AI.getValueAsInt();828}829830if (!AI.isStringAttribute())831return false;832if (getKindAsString() == AI.getKindAsString())833return getValueAsString() < AI.getValueAsString();834return getKindAsString() < AI.getKindAsString();835}836837//===----------------------------------------------------------------------===//838// AttributeSet Definition839//===----------------------------------------------------------------------===//840841AttributeSet AttributeSet::get(LLVMContext &C, const AttrBuilder &B) {842return AttributeSet(AttributeSetNode::get(C, B));843}844845AttributeSet AttributeSet::get(LLVMContext &C, ArrayRef<Attribute> Attrs) {846return AttributeSet(AttributeSetNode::get(C, Attrs));847}848849AttributeSet AttributeSet::addAttribute(LLVMContext &C,850Attribute::AttrKind Kind) const {851if (hasAttribute(Kind)) return *this;852AttrBuilder B(C);853B.addAttribute(Kind);854return addAttributes(C, AttributeSet::get(C, B));855}856857AttributeSet AttributeSet::addAttribute(LLVMContext &C, StringRef Kind,858StringRef Value) const {859AttrBuilder B(C);860B.addAttribute(Kind, Value);861return addAttributes(C, AttributeSet::get(C, B));862}863864AttributeSet AttributeSet::addAttributes(LLVMContext &C,865const AttributeSet AS) const {866if (!hasAttributes())867return AS;868869if (!AS.hasAttributes())870return *this;871872AttrBuilder B(C, *this);873B.merge(AttrBuilder(C, AS));874return get(C, B);875}876877AttributeSet AttributeSet::removeAttribute(LLVMContext &C,878Attribute::AttrKind Kind) const {879if (!hasAttribute(Kind)) return *this;880AttrBuilder B(C, *this);881B.removeAttribute(Kind);882return get(C, B);883}884885AttributeSet AttributeSet::removeAttribute(LLVMContext &C,886StringRef Kind) const {887if (!hasAttribute(Kind)) return *this;888AttrBuilder B(C, *this);889B.removeAttribute(Kind);890return get(C, B);891}892893AttributeSet AttributeSet::removeAttributes(LLVMContext &C,894const AttributeMask &Attrs) const {895AttrBuilder B(C, *this);896// If there is nothing to remove, directly return the original set.897if (!B.overlaps(Attrs))898return *this;899900B.remove(Attrs);901return get(C, B);902}903904unsigned AttributeSet::getNumAttributes() const {905return SetNode ? SetNode->getNumAttributes() : 0;906}907908bool AttributeSet::hasAttribute(Attribute::AttrKind Kind) const {909return SetNode ? SetNode->hasAttribute(Kind) : false;910}911912bool AttributeSet::hasAttribute(StringRef Kind) const {913return SetNode ? SetNode->hasAttribute(Kind) : false;914}915916Attribute AttributeSet::getAttribute(Attribute::AttrKind Kind) const {917return SetNode ? SetNode->getAttribute(Kind) : Attribute();918}919920Attribute AttributeSet::getAttribute(StringRef Kind) const {921return SetNode ? SetNode->getAttribute(Kind) : Attribute();922}923924MaybeAlign AttributeSet::getAlignment() const {925return SetNode ? SetNode->getAlignment() : std::nullopt;926}927928MaybeAlign AttributeSet::getStackAlignment() const {929return SetNode ? SetNode->getStackAlignment() : std::nullopt;930}931932uint64_t AttributeSet::getDereferenceableBytes() const {933return SetNode ? SetNode->getDereferenceableBytes() : 0;934}935936uint64_t AttributeSet::getDereferenceableOrNullBytes() const {937return SetNode ? SetNode->getDereferenceableOrNullBytes() : 0;938}939940Type *AttributeSet::getByRefType() const {941return SetNode ? SetNode->getAttributeType(Attribute::ByRef) : nullptr;942}943944Type *AttributeSet::getByValType() const {945return SetNode ? SetNode->getAttributeType(Attribute::ByVal) : nullptr;946}947948Type *AttributeSet::getStructRetType() const {949return SetNode ? SetNode->getAttributeType(Attribute::StructRet) : nullptr;950}951952Type *AttributeSet::getPreallocatedType() const {953return SetNode ? SetNode->getAttributeType(Attribute::Preallocated) : nullptr;954}955956Type *AttributeSet::getInAllocaType() const {957return SetNode ? SetNode->getAttributeType(Attribute::InAlloca) : nullptr;958}959960Type *AttributeSet::getElementType() const {961return SetNode ? SetNode->getAttributeType(Attribute::ElementType) : nullptr;962}963964std::optional<std::pair<unsigned, std::optional<unsigned>>>965AttributeSet::getAllocSizeArgs() const {966if (SetNode)967return SetNode->getAllocSizeArgs();968return std::nullopt;969}970971unsigned AttributeSet::getVScaleRangeMin() const {972return SetNode ? SetNode->getVScaleRangeMin() : 1;973}974975std::optional<unsigned> AttributeSet::getVScaleRangeMax() const {976return SetNode ? SetNode->getVScaleRangeMax() : std::nullopt;977}978979UWTableKind AttributeSet::getUWTableKind() const {980return SetNode ? SetNode->getUWTableKind() : UWTableKind::None;981}982983AllocFnKind AttributeSet::getAllocKind() const {984return SetNode ? SetNode->getAllocKind() : AllocFnKind::Unknown;985}986987MemoryEffects AttributeSet::getMemoryEffects() const {988return SetNode ? SetNode->getMemoryEffects() : MemoryEffects::unknown();989}990991FPClassTest AttributeSet::getNoFPClass() const {992return SetNode ? SetNode->getNoFPClass() : fcNone;993}994995std::string AttributeSet::getAsString(bool InAttrGrp) const {996return SetNode ? SetNode->getAsString(InAttrGrp) : "";997}998999bool AttributeSet::hasParentContext(LLVMContext &C) const {1000assert(hasAttributes() && "empty AttributeSet doesn't refer to any context");1001FoldingSetNodeID ID;1002SetNode->Profile(ID);1003void *Unused;1004return C.pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, Unused) == SetNode;1005}10061007AttributeSet::iterator AttributeSet::begin() const {1008return SetNode ? SetNode->begin() : nullptr;1009}10101011AttributeSet::iterator AttributeSet::end() const {1012return SetNode ? SetNode->end() : nullptr;1013}10141015#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1016LLVM_DUMP_METHOD void AttributeSet::dump() const {1017dbgs() << "AS =\n";1018dbgs() << " { ";1019dbgs() << getAsString(true) << " }\n";1020}1021#endif10221023//===----------------------------------------------------------------------===//1024// AttributeSetNode Definition1025//===----------------------------------------------------------------------===//10261027AttributeSetNode::AttributeSetNode(ArrayRef<Attribute> Attrs)1028: NumAttrs(Attrs.size()) {1029// There's memory after the node where we can store the entries in.1030llvm::copy(Attrs, getTrailingObjects<Attribute>());10311032for (const auto &I : *this) {1033if (I.isStringAttribute())1034StringAttrs.insert({ I.getKindAsString(), I });1035else1036AvailableAttrs.addAttribute(I.getKindAsEnum());1037}1038}10391040AttributeSetNode *AttributeSetNode::get(LLVMContext &C,1041ArrayRef<Attribute> Attrs) {1042SmallVector<Attribute, 8> SortedAttrs(Attrs.begin(), Attrs.end());1043llvm::sort(SortedAttrs);1044return getSorted(C, SortedAttrs);1045}10461047AttributeSetNode *AttributeSetNode::getSorted(LLVMContext &C,1048ArrayRef<Attribute> SortedAttrs) {1049if (SortedAttrs.empty())1050return nullptr;10511052// Build a key to look up the existing attributes.1053LLVMContextImpl *pImpl = C.pImpl;1054FoldingSetNodeID ID;10551056assert(llvm::is_sorted(SortedAttrs) && "Expected sorted attributes!");1057for (const auto &Attr : SortedAttrs)1058Attr.Profile(ID);10591060void *InsertPoint;1061AttributeSetNode *PA =1062pImpl->AttrsSetNodes.FindNodeOrInsertPos(ID, InsertPoint);10631064// If we didn't find any existing attributes of the same shape then create a1065// new one and insert it.1066if (!PA) {1067// Coallocate entries after the AttributeSetNode itself.1068void *Mem = ::operator new(totalSizeToAlloc<Attribute>(SortedAttrs.size()));1069PA = new (Mem) AttributeSetNode(SortedAttrs);1070pImpl->AttrsSetNodes.InsertNode(PA, InsertPoint);1071}10721073// Return the AttributeSetNode that we found or created.1074return PA;1075}10761077AttributeSetNode *AttributeSetNode::get(LLVMContext &C, const AttrBuilder &B) {1078return getSorted(C, B.attrs());1079}10801081bool AttributeSetNode::hasAttribute(StringRef Kind) const {1082return StringAttrs.count(Kind);1083}10841085std::optional<Attribute>1086AttributeSetNode::findEnumAttribute(Attribute::AttrKind Kind) const {1087// Do a quick presence check.1088if (!hasAttribute(Kind))1089return std::nullopt;10901091// Attributes in a set are sorted by enum value, followed by string1092// attributes. Binary search the one we want.1093const Attribute *I =1094std::lower_bound(begin(), end() - StringAttrs.size(), Kind,1095[](Attribute A, Attribute::AttrKind Kind) {1096return A.getKindAsEnum() < Kind;1097});1098assert(I != end() && I->hasAttribute(Kind) && "Presence check failed?");1099return *I;1100}11011102Attribute AttributeSetNode::getAttribute(Attribute::AttrKind Kind) const {1103if (auto A = findEnumAttribute(Kind))1104return *A;1105return {};1106}11071108Attribute AttributeSetNode::getAttribute(StringRef Kind) const {1109return StringAttrs.lookup(Kind);1110}11111112MaybeAlign AttributeSetNode::getAlignment() const {1113if (auto A = findEnumAttribute(Attribute::Alignment))1114return A->getAlignment();1115return std::nullopt;1116}11171118MaybeAlign AttributeSetNode::getStackAlignment() const {1119if (auto A = findEnumAttribute(Attribute::StackAlignment))1120return A->getStackAlignment();1121return std::nullopt;1122}11231124Type *AttributeSetNode::getAttributeType(Attribute::AttrKind Kind) const {1125if (auto A = findEnumAttribute(Kind))1126return A->getValueAsType();1127return nullptr;1128}11291130uint64_t AttributeSetNode::getDereferenceableBytes() const {1131if (auto A = findEnumAttribute(Attribute::Dereferenceable))1132return A->getDereferenceableBytes();1133return 0;1134}11351136uint64_t AttributeSetNode::getDereferenceableOrNullBytes() const {1137if (auto A = findEnumAttribute(Attribute::DereferenceableOrNull))1138return A->getDereferenceableOrNullBytes();1139return 0;1140}11411142std::optional<std::pair<unsigned, std::optional<unsigned>>>1143AttributeSetNode::getAllocSizeArgs() const {1144if (auto A = findEnumAttribute(Attribute::AllocSize))1145return A->getAllocSizeArgs();1146return std::nullopt;1147}11481149unsigned AttributeSetNode::getVScaleRangeMin() const {1150if (auto A = findEnumAttribute(Attribute::VScaleRange))1151return A->getVScaleRangeMin();1152return 1;1153}11541155std::optional<unsigned> AttributeSetNode::getVScaleRangeMax() const {1156if (auto A = findEnumAttribute(Attribute::VScaleRange))1157return A->getVScaleRangeMax();1158return std::nullopt;1159}11601161UWTableKind AttributeSetNode::getUWTableKind() const {1162if (auto A = findEnumAttribute(Attribute::UWTable))1163return A->getUWTableKind();1164return UWTableKind::None;1165}11661167AllocFnKind AttributeSetNode::getAllocKind() const {1168if (auto A = findEnumAttribute(Attribute::AllocKind))1169return A->getAllocKind();1170return AllocFnKind::Unknown;1171}11721173MemoryEffects AttributeSetNode::getMemoryEffects() const {1174if (auto A = findEnumAttribute(Attribute::Memory))1175return A->getMemoryEffects();1176return MemoryEffects::unknown();1177}11781179FPClassTest AttributeSetNode::getNoFPClass() const {1180if (auto A = findEnumAttribute(Attribute::NoFPClass))1181return A->getNoFPClass();1182return fcNone;1183}11841185std::string AttributeSetNode::getAsString(bool InAttrGrp) const {1186std::string Str;1187for (iterator I = begin(), E = end(); I != E; ++I) {1188if (I != begin())1189Str += ' ';1190Str += I->getAsString(InAttrGrp);1191}1192return Str;1193}11941195//===----------------------------------------------------------------------===//1196// AttributeListImpl Definition1197//===----------------------------------------------------------------------===//11981199/// Map from AttributeList index to the internal array index. Adding one happens1200/// to work, because -1 wraps around to 0.1201static unsigned attrIdxToArrayIdx(unsigned Index) {1202return Index + 1;1203}12041205AttributeListImpl::AttributeListImpl(ArrayRef<AttributeSet> Sets)1206: NumAttrSets(Sets.size()) {1207assert(!Sets.empty() && "pointless AttributeListImpl");12081209// There's memory after the node where we can store the entries in.1210llvm::copy(Sets, getTrailingObjects<AttributeSet>());12111212// Initialize AvailableFunctionAttrs and AvailableSomewhereAttrs1213// summary bitsets.1214for (const auto &I : Sets[attrIdxToArrayIdx(AttributeList::FunctionIndex)])1215if (!I.isStringAttribute())1216AvailableFunctionAttrs.addAttribute(I.getKindAsEnum());12171218for (const auto &Set : Sets)1219for (const auto &I : Set)1220if (!I.isStringAttribute())1221AvailableSomewhereAttrs.addAttribute(I.getKindAsEnum());1222}12231224void AttributeListImpl::Profile(FoldingSetNodeID &ID) const {1225Profile(ID, ArrayRef(begin(), end()));1226}12271228void AttributeListImpl::Profile(FoldingSetNodeID &ID,1229ArrayRef<AttributeSet> Sets) {1230for (const auto &Set : Sets)1231ID.AddPointer(Set.SetNode);1232}12331234bool AttributeListImpl::hasAttrSomewhere(Attribute::AttrKind Kind,1235unsigned *Index) const {1236if (!AvailableSomewhereAttrs.hasAttribute(Kind))1237return false;12381239if (Index) {1240for (unsigned I = 0, E = NumAttrSets; I != E; ++I) {1241if (begin()[I].hasAttribute(Kind)) {1242*Index = I - 1;1243break;1244}1245}1246}12471248return true;1249}125012511252#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1253LLVM_DUMP_METHOD void AttributeListImpl::dump() const {1254AttributeList(const_cast<AttributeListImpl *>(this)).dump();1255}1256#endif12571258//===----------------------------------------------------------------------===//1259// AttributeList Construction and Mutation Methods1260//===----------------------------------------------------------------------===//12611262AttributeList AttributeList::getImpl(LLVMContext &C,1263ArrayRef<AttributeSet> AttrSets) {1264assert(!AttrSets.empty() && "pointless AttributeListImpl");12651266LLVMContextImpl *pImpl = C.pImpl;1267FoldingSetNodeID ID;1268AttributeListImpl::Profile(ID, AttrSets);12691270void *InsertPoint;1271AttributeListImpl *PA =1272pImpl->AttrsLists.FindNodeOrInsertPos(ID, InsertPoint);12731274// If we didn't find any existing attributes of the same shape then1275// create a new one and insert it.1276if (!PA) {1277// Coallocate entries after the AttributeListImpl itself.1278void *Mem = pImpl->Alloc.Allocate(1279AttributeListImpl::totalSizeToAlloc<AttributeSet>(AttrSets.size()),1280alignof(AttributeListImpl));1281PA = new (Mem) AttributeListImpl(AttrSets);1282pImpl->AttrsLists.InsertNode(PA, InsertPoint);1283}12841285// Return the AttributesList that we found or created.1286return AttributeList(PA);1287}12881289AttributeList1290AttributeList::get(LLVMContext &C,1291ArrayRef<std::pair<unsigned, Attribute>> Attrs) {1292// If there are no attributes then return a null AttributesList pointer.1293if (Attrs.empty())1294return {};12951296assert(llvm::is_sorted(Attrs, llvm::less_first()) &&1297"Misordered Attributes list!");1298assert(llvm::all_of(Attrs,1299[](const std::pair<unsigned, Attribute> &Pair) {1300return Pair.second.isValid();1301}) &&1302"Pointless attribute!");13031304// Create a vector if (unsigned, AttributeSetNode*) pairs from the attributes1305// list.1306SmallVector<std::pair<unsigned, AttributeSet>, 8> AttrPairVec;1307for (ArrayRef<std::pair<unsigned, Attribute>>::iterator I = Attrs.begin(),1308E = Attrs.end(); I != E; ) {1309unsigned Index = I->first;1310SmallVector<Attribute, 4> AttrVec;1311while (I != E && I->first == Index) {1312AttrVec.push_back(I->second);1313++I;1314}13151316AttrPairVec.emplace_back(Index, AttributeSet::get(C, AttrVec));1317}13181319return get(C, AttrPairVec);1320}13211322AttributeList1323AttributeList::get(LLVMContext &C,1324ArrayRef<std::pair<unsigned, AttributeSet>> Attrs) {1325// If there are no attributes then return a null AttributesList pointer.1326if (Attrs.empty())1327return {};13281329assert(llvm::is_sorted(Attrs, llvm::less_first()) &&1330"Misordered Attributes list!");1331assert(llvm::none_of(Attrs,1332[](const std::pair<unsigned, AttributeSet> &Pair) {1333return !Pair.second.hasAttributes();1334}) &&1335"Pointless attribute!");13361337unsigned MaxIndex = Attrs.back().first;1338// If the MaxIndex is FunctionIndex and there are other indices in front1339// of it, we need to use the largest of those to get the right size.1340if (MaxIndex == FunctionIndex && Attrs.size() > 1)1341MaxIndex = Attrs[Attrs.size() - 2].first;13421343SmallVector<AttributeSet, 4> AttrVec(attrIdxToArrayIdx(MaxIndex) + 1);1344for (const auto &Pair : Attrs)1345AttrVec[attrIdxToArrayIdx(Pair.first)] = Pair.second;13461347return getImpl(C, AttrVec);1348}13491350AttributeList AttributeList::get(LLVMContext &C, AttributeSet FnAttrs,1351AttributeSet RetAttrs,1352ArrayRef<AttributeSet> ArgAttrs) {1353// Scan from the end to find the last argument with attributes. Most1354// arguments don't have attributes, so it's nice if we can have fewer unique1355// AttributeListImpls by dropping empty attribute sets at the end of the list.1356unsigned NumSets = 0;1357for (size_t I = ArgAttrs.size(); I != 0; --I) {1358if (ArgAttrs[I - 1].hasAttributes()) {1359NumSets = I + 2;1360break;1361}1362}1363if (NumSets == 0) {1364// Check function and return attributes if we didn't have argument1365// attributes.1366if (RetAttrs.hasAttributes())1367NumSets = 2;1368else if (FnAttrs.hasAttributes())1369NumSets = 1;1370}13711372// If all attribute sets were empty, we can use the empty attribute list.1373if (NumSets == 0)1374return {};13751376SmallVector<AttributeSet, 8> AttrSets;1377AttrSets.reserve(NumSets);1378// If we have any attributes, we always have function attributes.1379AttrSets.push_back(FnAttrs);1380if (NumSets > 1)1381AttrSets.push_back(RetAttrs);1382if (NumSets > 2) {1383// Drop the empty argument attribute sets at the end.1384ArgAttrs = ArgAttrs.take_front(NumSets - 2);1385llvm::append_range(AttrSets, ArgAttrs);1386}13871388return getImpl(C, AttrSets);1389}13901391AttributeList AttributeList::get(LLVMContext &C, unsigned Index,1392AttributeSet Attrs) {1393if (!Attrs.hasAttributes())1394return {};1395Index = attrIdxToArrayIdx(Index);1396SmallVector<AttributeSet, 8> AttrSets(Index + 1);1397AttrSets[Index] = Attrs;1398return getImpl(C, AttrSets);1399}14001401AttributeList AttributeList::get(LLVMContext &C, unsigned Index,1402const AttrBuilder &B) {1403return get(C, Index, AttributeSet::get(C, B));1404}14051406AttributeList AttributeList::get(LLVMContext &C, unsigned Index,1407ArrayRef<Attribute::AttrKind> Kinds) {1408SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;1409for (const auto K : Kinds)1410Attrs.emplace_back(Index, Attribute::get(C, K));1411return get(C, Attrs);1412}14131414AttributeList AttributeList::get(LLVMContext &C, unsigned Index,1415ArrayRef<Attribute::AttrKind> Kinds,1416ArrayRef<uint64_t> Values) {1417assert(Kinds.size() == Values.size() && "Mismatched attribute values.");1418SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;1419auto VI = Values.begin();1420for (const auto K : Kinds)1421Attrs.emplace_back(Index, Attribute::get(C, K, *VI++));1422return get(C, Attrs);1423}14241425AttributeList AttributeList::get(LLVMContext &C, unsigned Index,1426ArrayRef<StringRef> Kinds) {1427SmallVector<std::pair<unsigned, Attribute>, 8> Attrs;1428for (const auto &K : Kinds)1429Attrs.emplace_back(Index, Attribute::get(C, K));1430return get(C, Attrs);1431}14321433AttributeList AttributeList::get(LLVMContext &C,1434ArrayRef<AttributeList> Attrs) {1435if (Attrs.empty())1436return {};1437if (Attrs.size() == 1)1438return Attrs[0];14391440unsigned MaxSize = 0;1441for (const auto &List : Attrs)1442MaxSize = std::max(MaxSize, List.getNumAttrSets());14431444// If every list was empty, there is no point in merging the lists.1445if (MaxSize == 0)1446return {};14471448SmallVector<AttributeSet, 8> NewAttrSets(MaxSize);1449for (unsigned I = 0; I < MaxSize; ++I) {1450AttrBuilder CurBuilder(C);1451for (const auto &List : Attrs)1452CurBuilder.merge(AttrBuilder(C, List.getAttributes(I - 1)));1453NewAttrSets[I] = AttributeSet::get(C, CurBuilder);1454}14551456return getImpl(C, NewAttrSets);1457}14581459AttributeList1460AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,1461Attribute::AttrKind Kind) const {1462AttributeSet Attrs = getAttributes(Index);1463if (Attrs.hasAttribute(Kind))1464return *this;1465// TODO: Insert at correct position and avoid sort.1466SmallVector<Attribute, 8> NewAttrs(Attrs.begin(), Attrs.end());1467NewAttrs.push_back(Attribute::get(C, Kind));1468return setAttributesAtIndex(C, Index, AttributeSet::get(C, NewAttrs));1469}14701471AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,1472StringRef Kind,1473StringRef Value) const {1474AttrBuilder B(C);1475B.addAttribute(Kind, Value);1476return addAttributesAtIndex(C, Index, B);1477}14781479AttributeList AttributeList::addAttributeAtIndex(LLVMContext &C, unsigned Index,1480Attribute A) const {1481AttrBuilder B(C);1482B.addAttribute(A);1483return addAttributesAtIndex(C, Index, B);1484}14851486AttributeList AttributeList::setAttributesAtIndex(LLVMContext &C,1487unsigned Index,1488AttributeSet Attrs) const {1489Index = attrIdxToArrayIdx(Index);1490SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());1491if (Index >= AttrSets.size())1492AttrSets.resize(Index + 1);1493AttrSets[Index] = Attrs;14941495// Remove trailing empty attribute sets.1496while (!AttrSets.empty() && !AttrSets.back().hasAttributes())1497AttrSets.pop_back();1498if (AttrSets.empty())1499return {};1500return AttributeList::getImpl(C, AttrSets);1501}15021503AttributeList AttributeList::addAttributesAtIndex(LLVMContext &C,1504unsigned Index,1505const AttrBuilder &B) const {1506if (!B.hasAttributes())1507return *this;15081509if (!pImpl)1510return AttributeList::get(C, {{Index, AttributeSet::get(C, B)}});15111512AttrBuilder Merged(C, getAttributes(Index));1513Merged.merge(B);1514return setAttributesAtIndex(C, Index, AttributeSet::get(C, Merged));1515}15161517AttributeList AttributeList::addParamAttribute(LLVMContext &C,1518ArrayRef<unsigned> ArgNos,1519Attribute A) const {1520assert(llvm::is_sorted(ArgNos));15211522SmallVector<AttributeSet, 4> AttrSets(this->begin(), this->end());1523unsigned MaxIndex = attrIdxToArrayIdx(ArgNos.back() + FirstArgIndex);1524if (MaxIndex >= AttrSets.size())1525AttrSets.resize(MaxIndex + 1);15261527for (unsigned ArgNo : ArgNos) {1528unsigned Index = attrIdxToArrayIdx(ArgNo + FirstArgIndex);1529AttrBuilder B(C, AttrSets[Index]);1530B.addAttribute(A);1531AttrSets[Index] = AttributeSet::get(C, B);1532}15331534return getImpl(C, AttrSets);1535}15361537AttributeList1538AttributeList::removeAttributeAtIndex(LLVMContext &C, unsigned Index,1539Attribute::AttrKind Kind) const {1540AttributeSet Attrs = getAttributes(Index);1541AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind);1542if (Attrs == NewAttrs)1543return *this;1544return setAttributesAtIndex(C, Index, NewAttrs);1545}15461547AttributeList AttributeList::removeAttributeAtIndex(LLVMContext &C,1548unsigned Index,1549StringRef Kind) const {1550AttributeSet Attrs = getAttributes(Index);1551AttributeSet NewAttrs = Attrs.removeAttribute(C, Kind);1552if (Attrs == NewAttrs)1553return *this;1554return setAttributesAtIndex(C, Index, NewAttrs);1555}15561557AttributeList AttributeList::removeAttributesAtIndex(1558LLVMContext &C, unsigned Index, const AttributeMask &AttrsToRemove) const {1559AttributeSet Attrs = getAttributes(Index);1560AttributeSet NewAttrs = Attrs.removeAttributes(C, AttrsToRemove);1561// If nothing was removed, return the original list.1562if (Attrs == NewAttrs)1563return *this;1564return setAttributesAtIndex(C, Index, NewAttrs);1565}15661567AttributeList1568AttributeList::removeAttributesAtIndex(LLVMContext &C,1569unsigned WithoutIndex) const {1570if (!pImpl)1571return {};1572if (attrIdxToArrayIdx(WithoutIndex) >= getNumAttrSets())1573return *this;1574return setAttributesAtIndex(C, WithoutIndex, AttributeSet());1575}15761577AttributeList AttributeList::addDereferenceableRetAttr(LLVMContext &C,1578uint64_t Bytes) const {1579AttrBuilder B(C);1580B.addDereferenceableAttr(Bytes);1581return addRetAttributes(C, B);1582}15831584AttributeList AttributeList::addDereferenceableParamAttr(LLVMContext &C,1585unsigned Index,1586uint64_t Bytes) const {1587AttrBuilder B(C);1588B.addDereferenceableAttr(Bytes);1589return addParamAttributes(C, Index, B);1590}15911592AttributeList1593AttributeList::addDereferenceableOrNullParamAttr(LLVMContext &C, unsigned Index,1594uint64_t Bytes) const {1595AttrBuilder B(C);1596B.addDereferenceableOrNullAttr(Bytes);1597return addParamAttributes(C, Index, B);1598}15991600AttributeList AttributeList::addRangeRetAttr(LLVMContext &C,1601const ConstantRange &CR) const {1602AttrBuilder B(C);1603B.addRangeAttr(CR);1604return addRetAttributes(C, B);1605}16061607AttributeList AttributeList::addAllocSizeParamAttr(1608LLVMContext &C, unsigned Index, unsigned ElemSizeArg,1609const std::optional<unsigned> &NumElemsArg) {1610AttrBuilder B(C);1611B.addAllocSizeAttr(ElemSizeArg, NumElemsArg);1612return addParamAttributes(C, Index, B);1613}16141615//===----------------------------------------------------------------------===//1616// AttributeList Accessor Methods1617//===----------------------------------------------------------------------===//16181619AttributeSet AttributeList::getParamAttrs(unsigned ArgNo) const {1620return getAttributes(ArgNo + FirstArgIndex);1621}16221623AttributeSet AttributeList::getRetAttrs() const {1624return getAttributes(ReturnIndex);1625}16261627AttributeSet AttributeList::getFnAttrs() const {1628return getAttributes(FunctionIndex);1629}16301631bool AttributeList::hasAttributeAtIndex(unsigned Index,1632Attribute::AttrKind Kind) const {1633return getAttributes(Index).hasAttribute(Kind);1634}16351636bool AttributeList::hasAttributeAtIndex(unsigned Index, StringRef Kind) const {1637return getAttributes(Index).hasAttribute(Kind);1638}16391640bool AttributeList::hasAttributesAtIndex(unsigned Index) const {1641return getAttributes(Index).hasAttributes();1642}16431644bool AttributeList::hasFnAttr(Attribute::AttrKind Kind) const {1645return pImpl && pImpl->hasFnAttribute(Kind);1646}16471648bool AttributeList::hasFnAttr(StringRef Kind) const {1649return hasAttributeAtIndex(AttributeList::FunctionIndex, Kind);1650}16511652bool AttributeList::hasAttrSomewhere(Attribute::AttrKind Attr,1653unsigned *Index) const {1654return pImpl && pImpl->hasAttrSomewhere(Attr, Index);1655}16561657Attribute AttributeList::getAttributeAtIndex(unsigned Index,1658Attribute::AttrKind Kind) const {1659return getAttributes(Index).getAttribute(Kind);1660}16611662Attribute AttributeList::getAttributeAtIndex(unsigned Index,1663StringRef Kind) const {1664return getAttributes(Index).getAttribute(Kind);1665}16661667MaybeAlign AttributeList::getRetAlignment() const {1668return getAttributes(ReturnIndex).getAlignment();1669}16701671MaybeAlign AttributeList::getParamAlignment(unsigned ArgNo) const {1672return getAttributes(ArgNo + FirstArgIndex).getAlignment();1673}16741675MaybeAlign AttributeList::getParamStackAlignment(unsigned ArgNo) const {1676return getAttributes(ArgNo + FirstArgIndex).getStackAlignment();1677}16781679Type *AttributeList::getParamByValType(unsigned Index) const {1680return getAttributes(Index+FirstArgIndex).getByValType();1681}16821683Type *AttributeList::getParamStructRetType(unsigned Index) const {1684return getAttributes(Index + FirstArgIndex).getStructRetType();1685}16861687Type *AttributeList::getParamByRefType(unsigned Index) const {1688return getAttributes(Index + FirstArgIndex).getByRefType();1689}16901691Type *AttributeList::getParamPreallocatedType(unsigned Index) const {1692return getAttributes(Index + FirstArgIndex).getPreallocatedType();1693}16941695Type *AttributeList::getParamInAllocaType(unsigned Index) const {1696return getAttributes(Index + FirstArgIndex).getInAllocaType();1697}16981699Type *AttributeList::getParamElementType(unsigned Index) const {1700return getAttributes(Index + FirstArgIndex).getElementType();1701}17021703MaybeAlign AttributeList::getFnStackAlignment() const {1704return getFnAttrs().getStackAlignment();1705}17061707MaybeAlign AttributeList::getRetStackAlignment() const {1708return getRetAttrs().getStackAlignment();1709}17101711uint64_t AttributeList::getRetDereferenceableBytes() const {1712return getRetAttrs().getDereferenceableBytes();1713}17141715uint64_t AttributeList::getParamDereferenceableBytes(unsigned Index) const {1716return getParamAttrs(Index).getDereferenceableBytes();1717}17181719uint64_t AttributeList::getRetDereferenceableOrNullBytes() const {1720return getRetAttrs().getDereferenceableOrNullBytes();1721}17221723uint64_t1724AttributeList::getParamDereferenceableOrNullBytes(unsigned Index) const {1725return getParamAttrs(Index).getDereferenceableOrNullBytes();1726}17271728FPClassTest AttributeList::getRetNoFPClass() const {1729return getRetAttrs().getNoFPClass();1730}17311732FPClassTest AttributeList::getParamNoFPClass(unsigned Index) const {1733return getParamAttrs(Index).getNoFPClass();1734}17351736UWTableKind AttributeList::getUWTableKind() const {1737return getFnAttrs().getUWTableKind();1738}17391740AllocFnKind AttributeList::getAllocKind() const {1741return getFnAttrs().getAllocKind();1742}17431744MemoryEffects AttributeList::getMemoryEffects() const {1745return getFnAttrs().getMemoryEffects();1746}17471748std::string AttributeList::getAsString(unsigned Index, bool InAttrGrp) const {1749return getAttributes(Index).getAsString(InAttrGrp);1750}17511752AttributeSet AttributeList::getAttributes(unsigned Index) const {1753Index = attrIdxToArrayIdx(Index);1754if (!pImpl || Index >= getNumAttrSets())1755return {};1756return pImpl->begin()[Index];1757}17581759bool AttributeList::hasParentContext(LLVMContext &C) const {1760assert(!isEmpty() && "an empty attribute list has no parent context");1761FoldingSetNodeID ID;1762pImpl->Profile(ID);1763void *Unused;1764return C.pImpl->AttrsLists.FindNodeOrInsertPos(ID, Unused) == pImpl;1765}17661767AttributeList::iterator AttributeList::begin() const {1768return pImpl ? pImpl->begin() : nullptr;1769}17701771AttributeList::iterator AttributeList::end() const {1772return pImpl ? pImpl->end() : nullptr;1773}17741775//===----------------------------------------------------------------------===//1776// AttributeList Introspection Methods1777//===----------------------------------------------------------------------===//17781779unsigned AttributeList::getNumAttrSets() const {1780return pImpl ? pImpl->NumAttrSets : 0;1781}17821783void AttributeList::print(raw_ostream &O) const {1784O << "AttributeList[\n";17851786for (unsigned i : indexes()) {1787if (!getAttributes(i).hasAttributes())1788continue;1789O << " { ";1790switch (i) {1791case AttrIndex::ReturnIndex:1792O << "return";1793break;1794case AttrIndex::FunctionIndex:1795O << "function";1796break;1797default:1798O << "arg(" << i - AttrIndex::FirstArgIndex << ")";1799}1800O << " => " << getAsString(i) << " }\n";1801}18021803O << "]\n";1804}18051806#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)1807LLVM_DUMP_METHOD void AttributeList::dump() const { print(dbgs()); }1808#endif18091810//===----------------------------------------------------------------------===//1811// AttrBuilder Method Implementations1812//===----------------------------------------------------------------------===//18131814AttrBuilder::AttrBuilder(LLVMContext &Ctx, AttributeSet AS) : Ctx(Ctx) {1815append_range(Attrs, AS);1816assert(is_sorted(Attrs) && "AttributeSet should be sorted");1817}18181819void AttrBuilder::clear() { Attrs.clear(); }18201821/// Attribute comparator that only compares attribute keys. Enum attributes are1822/// sorted before string attributes.1823struct AttributeComparator {1824bool operator()(Attribute A0, Attribute A1) const {1825bool A0IsString = A0.isStringAttribute();1826bool A1IsString = A1.isStringAttribute();1827if (A0IsString) {1828if (A1IsString)1829return A0.getKindAsString() < A1.getKindAsString();1830else1831return false;1832}1833if (A1IsString)1834return true;1835return A0.getKindAsEnum() < A1.getKindAsEnum();1836}1837bool operator()(Attribute A0, Attribute::AttrKind Kind) const {1838if (A0.isStringAttribute())1839return false;1840return A0.getKindAsEnum() < Kind;1841}1842bool operator()(Attribute A0, StringRef Kind) const {1843if (A0.isStringAttribute())1844return A0.getKindAsString() < Kind;1845return true;1846}1847};18481849template <typename K>1850static void addAttributeImpl(SmallVectorImpl<Attribute> &Attrs, K Kind,1851Attribute Attr) {1852auto It = lower_bound(Attrs, Kind, AttributeComparator());1853if (It != Attrs.end() && It->hasAttribute(Kind))1854std::swap(*It, Attr);1855else1856Attrs.insert(It, Attr);1857}18581859AttrBuilder &AttrBuilder::addAttribute(Attribute Attr) {1860if (Attr.isStringAttribute())1861addAttributeImpl(Attrs, Attr.getKindAsString(), Attr);1862else1863addAttributeImpl(Attrs, Attr.getKindAsEnum(), Attr);1864return *this;1865}18661867AttrBuilder &AttrBuilder::addAttribute(Attribute::AttrKind Kind) {1868addAttributeImpl(Attrs, Kind, Attribute::get(Ctx, Kind));1869return *this;1870}18711872AttrBuilder &AttrBuilder::addAttribute(StringRef A, StringRef V) {1873addAttributeImpl(Attrs, A, Attribute::get(Ctx, A, V));1874return *this;1875}18761877AttrBuilder &AttrBuilder::removeAttribute(Attribute::AttrKind Val) {1878assert((unsigned)Val < Attribute::EndAttrKinds && "Attribute out of range!");1879auto It = lower_bound(Attrs, Val, AttributeComparator());1880if (It != Attrs.end() && It->hasAttribute(Val))1881Attrs.erase(It);1882return *this;1883}18841885AttrBuilder &AttrBuilder::removeAttribute(StringRef A) {1886auto It = lower_bound(Attrs, A, AttributeComparator());1887if (It != Attrs.end() && It->hasAttribute(A))1888Attrs.erase(It);1889return *this;1890}18911892std::optional<uint64_t>1893AttrBuilder::getRawIntAttr(Attribute::AttrKind Kind) const {1894assert(Attribute::isIntAttrKind(Kind) && "Not an int attribute");1895Attribute A = getAttribute(Kind);1896if (A.isValid())1897return A.getValueAsInt();1898return std::nullopt;1899}19001901AttrBuilder &AttrBuilder::addRawIntAttr(Attribute::AttrKind Kind,1902uint64_t Value) {1903return addAttribute(Attribute::get(Ctx, Kind, Value));1904}19051906std::optional<std::pair<unsigned, std::optional<unsigned>>>1907AttrBuilder::getAllocSizeArgs() const {1908Attribute A = getAttribute(Attribute::AllocSize);1909if (A.isValid())1910return A.getAllocSizeArgs();1911return std::nullopt;1912}19131914AttrBuilder &AttrBuilder::addAlignmentAttr(MaybeAlign Align) {1915if (!Align)1916return *this;19171918assert(*Align <= llvm::Value::MaximumAlignment && "Alignment too large.");1919return addRawIntAttr(Attribute::Alignment, Align->value());1920}19211922AttrBuilder &AttrBuilder::addStackAlignmentAttr(MaybeAlign Align) {1923// Default alignment, allow the target to define how to align it.1924if (!Align)1925return *this;19261927assert(*Align <= 0x100 && "Alignment too large.");1928return addRawIntAttr(Attribute::StackAlignment, Align->value());1929}19301931AttrBuilder &AttrBuilder::addDereferenceableAttr(uint64_t Bytes) {1932if (Bytes == 0) return *this;19331934return addRawIntAttr(Attribute::Dereferenceable, Bytes);1935}19361937AttrBuilder &AttrBuilder::addDereferenceableOrNullAttr(uint64_t Bytes) {1938if (Bytes == 0)1939return *this;19401941return addRawIntAttr(Attribute::DereferenceableOrNull, Bytes);1942}19431944AttrBuilder &1945AttrBuilder::addAllocSizeAttr(unsigned ElemSize,1946const std::optional<unsigned> &NumElems) {1947return addAllocSizeAttrFromRawRepr(packAllocSizeArgs(ElemSize, NumElems));1948}19491950AttrBuilder &AttrBuilder::addAllocSizeAttrFromRawRepr(uint64_t RawArgs) {1951// (0, 0) is our "not present" value, so we need to check for it here.1952assert(RawArgs && "Invalid allocsize arguments -- given allocsize(0, 0)");1953return addRawIntAttr(Attribute::AllocSize, RawArgs);1954}19551956AttrBuilder &AttrBuilder::addVScaleRangeAttr(unsigned MinValue,1957std::optional<unsigned> MaxValue) {1958return addVScaleRangeAttrFromRawRepr(packVScaleRangeArgs(MinValue, MaxValue));1959}19601961AttrBuilder &AttrBuilder::addVScaleRangeAttrFromRawRepr(uint64_t RawArgs) {1962// (0, 0) is not present hence ignore this case1963if (RawArgs == 0)1964return *this;19651966return addRawIntAttr(Attribute::VScaleRange, RawArgs);1967}19681969AttrBuilder &AttrBuilder::addUWTableAttr(UWTableKind Kind) {1970if (Kind == UWTableKind::None)1971return *this;1972return addRawIntAttr(Attribute::UWTable, uint64_t(Kind));1973}19741975AttrBuilder &AttrBuilder::addMemoryAttr(MemoryEffects ME) {1976return addRawIntAttr(Attribute::Memory, ME.toIntValue());1977}19781979AttrBuilder &AttrBuilder::addNoFPClassAttr(FPClassTest Mask) {1980if (Mask == fcNone)1981return *this;19821983return addRawIntAttr(Attribute::NoFPClass, Mask);1984}19851986AttrBuilder &AttrBuilder::addAllocKindAttr(AllocFnKind Kind) {1987return addRawIntAttr(Attribute::AllocKind, static_cast<uint64_t>(Kind));1988}19891990Type *AttrBuilder::getTypeAttr(Attribute::AttrKind Kind) const {1991assert(Attribute::isTypeAttrKind(Kind) && "Not a type attribute");1992Attribute A = getAttribute(Kind);1993return A.isValid() ? A.getValueAsType() : nullptr;1994}19951996AttrBuilder &AttrBuilder::addTypeAttr(Attribute::AttrKind Kind, Type *Ty) {1997return addAttribute(Attribute::get(Ctx, Kind, Ty));1998}19992000AttrBuilder &AttrBuilder::addByValAttr(Type *Ty) {2001return addTypeAttr(Attribute::ByVal, Ty);2002}20032004AttrBuilder &AttrBuilder::addStructRetAttr(Type *Ty) {2005return addTypeAttr(Attribute::StructRet, Ty);2006}20072008AttrBuilder &AttrBuilder::addByRefAttr(Type *Ty) {2009return addTypeAttr(Attribute::ByRef, Ty);2010}20112012AttrBuilder &AttrBuilder::addPreallocatedAttr(Type *Ty) {2013return addTypeAttr(Attribute::Preallocated, Ty);2014}20152016AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) {2017return addTypeAttr(Attribute::InAlloca, Ty);2018}20192020AttrBuilder &AttrBuilder::addConstantRangeAttr(Attribute::AttrKind Kind,2021const ConstantRange &CR) {2022return addAttribute(Attribute::get(Ctx, Kind, CR));2023}20242025AttrBuilder &AttrBuilder::addRangeAttr(const ConstantRange &CR) {2026return addConstantRangeAttr(Attribute::Range, CR);2027}20282029AttrBuilder &2030AttrBuilder::addConstantRangeListAttr(Attribute::AttrKind Kind,2031ArrayRef<ConstantRange> Val) {2032return addAttribute(Attribute::get(Ctx, Kind, Val));2033}20342035AttrBuilder &AttrBuilder::addInitializesAttr(const ConstantRangeList &CRL) {2036return addConstantRangeListAttr(Attribute::Initializes, CRL.rangesRef());2037}20382039AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {2040// TODO: Could make this O(n) as we're merging two sorted lists.2041for (const auto &I : B.attrs())2042addAttribute(I);20432044return *this;2045}20462047AttrBuilder &AttrBuilder::remove(const AttributeMask &AM) {2048erase_if(Attrs, [&](Attribute A) { return AM.contains(A); });2049return *this;2050}20512052bool AttrBuilder::overlaps(const AttributeMask &AM) const {2053return any_of(Attrs, [&](Attribute A) { return AM.contains(A); });2054}20552056Attribute AttrBuilder::getAttribute(Attribute::AttrKind A) const {2057assert((unsigned)A < Attribute::EndAttrKinds && "Attribute out of range!");2058auto It = lower_bound(Attrs, A, AttributeComparator());2059if (It != Attrs.end() && It->hasAttribute(A))2060return *It;2061return {};2062}20632064Attribute AttrBuilder::getAttribute(StringRef A) const {2065auto It = lower_bound(Attrs, A, AttributeComparator());2066if (It != Attrs.end() && It->hasAttribute(A))2067return *It;2068return {};2069}20702071bool AttrBuilder::contains(Attribute::AttrKind A) const {2072return getAttribute(A).isValid();2073}20742075bool AttrBuilder::contains(StringRef A) const {2076return getAttribute(A).isValid();2077}20782079bool AttrBuilder::operator==(const AttrBuilder &B) const {2080return Attrs == B.Attrs;2081}20822083//===----------------------------------------------------------------------===//2084// AttributeFuncs Function Defintions2085//===----------------------------------------------------------------------===//20862087/// Returns true if this is a type legal for the 'nofpclass' attribute. This2088/// follows the same type rules as FPMathOperator.2089///2090/// TODO: Consider relaxing to any FP type struct fields.2091bool AttributeFuncs::isNoFPClassCompatibleType(Type *Ty) {2092while (ArrayType *ArrTy = dyn_cast<ArrayType>(Ty))2093Ty = ArrTy->getElementType();2094return Ty->isFPOrFPVectorTy();2095}20962097/// Which attributes cannot be applied to a type.2098AttributeMask AttributeFuncs::typeIncompatible(Type *Ty,2099AttributeSafetyKind ASK) {2100AttributeMask Incompatible;21012102if (!Ty->isIntegerTy()) {2103// Attributes that only apply to integers.2104if (ASK & ASK_SAFE_TO_DROP)2105Incompatible.addAttribute(Attribute::AllocAlign);2106if (ASK & ASK_UNSAFE_TO_DROP)2107Incompatible.addAttribute(Attribute::SExt).addAttribute(Attribute::ZExt);2108}21092110if (!Ty->isIntOrIntVectorTy()) {2111// Attributes that only apply to integers or vector of integers.2112if (ASK & ASK_SAFE_TO_DROP)2113Incompatible.addAttribute(Attribute::Range);2114}21152116if (!Ty->isPointerTy()) {2117// Attributes that only apply to pointers.2118if (ASK & ASK_SAFE_TO_DROP)2119Incompatible.addAttribute(Attribute::NoAlias)2120.addAttribute(Attribute::NoCapture)2121.addAttribute(Attribute::NonNull)2122.addAttribute(Attribute::ReadNone)2123.addAttribute(Attribute::ReadOnly)2124.addAttribute(Attribute::Dereferenceable)2125.addAttribute(Attribute::DereferenceableOrNull)2126.addAttribute(Attribute::Writable)2127.addAttribute(Attribute::DeadOnUnwind)2128.addAttribute(Attribute::Initializes);2129if (ASK & ASK_UNSAFE_TO_DROP)2130Incompatible.addAttribute(Attribute::Nest)2131.addAttribute(Attribute::SwiftError)2132.addAttribute(Attribute::Preallocated)2133.addAttribute(Attribute::InAlloca)2134.addAttribute(Attribute::ByVal)2135.addAttribute(Attribute::StructRet)2136.addAttribute(Attribute::ByRef)2137.addAttribute(Attribute::ElementType)2138.addAttribute(Attribute::AllocatedPointer);2139}21402141// Attributes that only apply to pointers or vectors of pointers.2142if (!Ty->isPtrOrPtrVectorTy()) {2143if (ASK & ASK_SAFE_TO_DROP)2144Incompatible.addAttribute(Attribute::Alignment);2145}21462147if (ASK & ASK_SAFE_TO_DROP) {2148if (!isNoFPClassCompatibleType(Ty))2149Incompatible.addAttribute(Attribute::NoFPClass);2150}21512152// Some attributes can apply to all "values" but there are no `void` values.2153if (Ty->isVoidTy()) {2154if (ASK & ASK_SAFE_TO_DROP)2155Incompatible.addAttribute(Attribute::NoUndef);2156}21572158return Incompatible;2159}21602161AttributeMask AttributeFuncs::getUBImplyingAttributes() {2162AttributeMask AM;2163AM.addAttribute(Attribute::NoUndef);2164AM.addAttribute(Attribute::Dereferenceable);2165AM.addAttribute(Attribute::DereferenceableOrNull);2166return AM;2167}21682169/// Callees with dynamic denormal modes are compatible with any caller mode.2170static bool denormModeCompatible(DenormalMode CallerMode,2171DenormalMode CalleeMode) {2172if (CallerMode == CalleeMode || CalleeMode == DenormalMode::getDynamic())2173return true;21742175// If they don't exactly match, it's OK if the mismatched component is2176// dynamic.2177if (CalleeMode.Input == CallerMode.Input &&2178CalleeMode.Output == DenormalMode::Dynamic)2179return true;21802181if (CalleeMode.Output == CallerMode.Output &&2182CalleeMode.Input == DenormalMode::Dynamic)2183return true;2184return false;2185}21862187static bool checkDenormMode(const Function &Caller, const Function &Callee) {2188DenormalMode CallerMode = Caller.getDenormalModeRaw();2189DenormalMode CalleeMode = Callee.getDenormalModeRaw();21902191if (denormModeCompatible(CallerMode, CalleeMode)) {2192DenormalMode CallerModeF32 = Caller.getDenormalModeF32Raw();2193DenormalMode CalleeModeF32 = Callee.getDenormalModeF32Raw();2194if (CallerModeF32 == DenormalMode::getInvalid())2195CallerModeF32 = CallerMode;2196if (CalleeModeF32 == DenormalMode::getInvalid())2197CalleeModeF32 = CalleeMode;2198return denormModeCompatible(CallerModeF32, CalleeModeF32);2199}22002201return false;2202}22032204static bool checkStrictFP(const Function &Caller, const Function &Callee) {2205// Do not inline strictfp function into non-strictfp one. It would require2206// conversion of all FP operations in host function to constrained intrinsics.2207return !Callee.getAttributes().hasFnAttr(Attribute::StrictFP) ||2208Caller.getAttributes().hasFnAttr(Attribute::StrictFP);2209}22102211template<typename AttrClass>2212static bool isEqual(const Function &Caller, const Function &Callee) {2213return Caller.getFnAttribute(AttrClass::getKind()) ==2214Callee.getFnAttribute(AttrClass::getKind());2215}22162217static bool isEqual(const Function &Caller, const Function &Callee,2218const StringRef &AttrName) {2219return Caller.getFnAttribute(AttrName) == Callee.getFnAttribute(AttrName);2220}22212222/// Compute the logical AND of the attributes of the caller and the2223/// callee.2224///2225/// This function sets the caller's attribute to false if the callee's attribute2226/// is false.2227template<typename AttrClass>2228static void setAND(Function &Caller, const Function &Callee) {2229if (AttrClass::isSet(Caller, AttrClass::getKind()) &&2230!AttrClass::isSet(Callee, AttrClass::getKind()))2231AttrClass::set(Caller, AttrClass::getKind(), false);2232}22332234/// Compute the logical OR of the attributes of the caller and the2235/// callee.2236///2237/// This function sets the caller's attribute to true if the callee's attribute2238/// is true.2239template<typename AttrClass>2240static void setOR(Function &Caller, const Function &Callee) {2241if (!AttrClass::isSet(Caller, AttrClass::getKind()) &&2242AttrClass::isSet(Callee, AttrClass::getKind()))2243AttrClass::set(Caller, AttrClass::getKind(), true);2244}22452246/// If the inlined function had a higher stack protection level than the2247/// calling function, then bump up the caller's stack protection level.2248static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) {2249// If the calling function has *no* stack protection level (e.g. it was built2250// with Clang's -fno-stack-protector or no_stack_protector attribute), don't2251// change it as that could change the program's semantics.2252if (!Caller.hasStackProtectorFnAttr())2253return;22542255// If upgrading the SSP attribute, clear out the old SSP Attributes first.2256// Having multiple SSP attributes doesn't actually hurt, but it adds useless2257// clutter to the IR.2258AttributeMask OldSSPAttr;2259OldSSPAttr.addAttribute(Attribute::StackProtect)2260.addAttribute(Attribute::StackProtectStrong)2261.addAttribute(Attribute::StackProtectReq);22622263if (Callee.hasFnAttribute(Attribute::StackProtectReq)) {2264Caller.removeFnAttrs(OldSSPAttr);2265Caller.addFnAttr(Attribute::StackProtectReq);2266} else if (Callee.hasFnAttribute(Attribute::StackProtectStrong) &&2267!Caller.hasFnAttribute(Attribute::StackProtectReq)) {2268Caller.removeFnAttrs(OldSSPAttr);2269Caller.addFnAttr(Attribute::StackProtectStrong);2270} else if (Callee.hasFnAttribute(Attribute::StackProtect) &&2271!Caller.hasFnAttribute(Attribute::StackProtectReq) &&2272!Caller.hasFnAttribute(Attribute::StackProtectStrong))2273Caller.addFnAttr(Attribute::StackProtect);2274}22752276/// If the inlined function required stack probes, then ensure that2277/// the calling function has those too.2278static void adjustCallerStackProbes(Function &Caller, const Function &Callee) {2279if (!Caller.hasFnAttribute("probe-stack") &&2280Callee.hasFnAttribute("probe-stack")) {2281Caller.addFnAttr(Callee.getFnAttribute("probe-stack"));2282}2283}22842285/// If the inlined function defines the size of guard region2286/// on the stack, then ensure that the calling function defines a guard region2287/// that is no larger.2288static void2289adjustCallerStackProbeSize(Function &Caller, const Function &Callee) {2290Attribute CalleeAttr = Callee.getFnAttribute("stack-probe-size");2291if (CalleeAttr.isValid()) {2292Attribute CallerAttr = Caller.getFnAttribute("stack-probe-size");2293if (CallerAttr.isValid()) {2294uint64_t CallerStackProbeSize, CalleeStackProbeSize;2295CallerAttr.getValueAsString().getAsInteger(0, CallerStackProbeSize);2296CalleeAttr.getValueAsString().getAsInteger(0, CalleeStackProbeSize);22972298if (CallerStackProbeSize > CalleeStackProbeSize) {2299Caller.addFnAttr(CalleeAttr);2300}2301} else {2302Caller.addFnAttr(CalleeAttr);2303}2304}2305}23062307/// If the inlined function defines a min legal vector width, then ensure2308/// the calling function has the same or larger min legal vector width. If the2309/// caller has the attribute, but the callee doesn't, we need to remove the2310/// attribute from the caller since we can't make any guarantees about the2311/// caller's requirements.2312/// This function is called after the inlining decision has been made so we have2313/// to merge the attribute this way. Heuristics that would use2314/// min-legal-vector-width to determine inline compatibility would need to be2315/// handled as part of inline cost analysis.2316static void2317adjustMinLegalVectorWidth(Function &Caller, const Function &Callee) {2318Attribute CallerAttr = Caller.getFnAttribute("min-legal-vector-width");2319if (CallerAttr.isValid()) {2320Attribute CalleeAttr = Callee.getFnAttribute("min-legal-vector-width");2321if (CalleeAttr.isValid()) {2322uint64_t CallerVectorWidth, CalleeVectorWidth;2323CallerAttr.getValueAsString().getAsInteger(0, CallerVectorWidth);2324CalleeAttr.getValueAsString().getAsInteger(0, CalleeVectorWidth);2325if (CallerVectorWidth < CalleeVectorWidth)2326Caller.addFnAttr(CalleeAttr);2327} else {2328// If the callee doesn't have the attribute then we don't know anything2329// and must drop the attribute from the caller.2330Caller.removeFnAttr("min-legal-vector-width");2331}2332}2333}23342335/// If the inlined function has null_pointer_is_valid attribute,2336/// set this attribute in the caller post inlining.2337static void2338adjustNullPointerValidAttr(Function &Caller, const Function &Callee) {2339if (Callee.nullPointerIsDefined() && !Caller.nullPointerIsDefined()) {2340Caller.addFnAttr(Attribute::NullPointerIsValid);2341}2342}23432344struct EnumAttr {2345static bool isSet(const Function &Fn,2346Attribute::AttrKind Kind) {2347return Fn.hasFnAttribute(Kind);2348}23492350static void set(Function &Fn,2351Attribute::AttrKind Kind, bool Val) {2352if (Val)2353Fn.addFnAttr(Kind);2354else2355Fn.removeFnAttr(Kind);2356}2357};23582359struct StrBoolAttr {2360static bool isSet(const Function &Fn,2361StringRef Kind) {2362auto A = Fn.getFnAttribute(Kind);2363return A.getValueAsString() == "true";2364}23652366static void set(Function &Fn,2367StringRef Kind, bool Val) {2368Fn.addFnAttr(Kind, Val ? "true" : "false");2369}2370};23712372#define GET_ATTR_NAMES2373#define ATTRIBUTE_ENUM(ENUM_NAME, DISPLAY_NAME) \2374struct ENUM_NAME##Attr : EnumAttr { \2375static enum Attribute::AttrKind getKind() { \2376return llvm::Attribute::ENUM_NAME; \2377} \2378};2379#define ATTRIBUTE_STRBOOL(ENUM_NAME, DISPLAY_NAME) \2380struct ENUM_NAME##Attr : StrBoolAttr { \2381static StringRef getKind() { return #DISPLAY_NAME; } \2382};2383#include "llvm/IR/Attributes.inc"23842385#define GET_ATTR_COMPAT_FUNC2386#include "llvm/IR/Attributes.inc"23872388bool AttributeFuncs::areInlineCompatible(const Function &Caller,2389const Function &Callee) {2390return hasCompatibleFnAttrs(Caller, Callee);2391}23922393bool AttributeFuncs::areOutlineCompatible(const Function &A,2394const Function &B) {2395return hasCompatibleFnAttrs(A, B);2396}23972398void AttributeFuncs::mergeAttributesForInlining(Function &Caller,2399const Function &Callee) {2400mergeFnAttrs(Caller, Callee);2401}24022403void AttributeFuncs::mergeAttributesForOutlining(Function &Base,2404const Function &ToMerge) {24052406// We merge functions so that they meet the most general case.2407// For example, if the NoNansFPMathAttr is set in one function, but not in2408// the other, in the merged function we can say that the NoNansFPMathAttr2409// is not set.2410// However if we have the SpeculativeLoadHardeningAttr set true in one2411// function, but not the other, we make sure that the function retains2412// that aspect in the merged function.2413mergeFnAttrs(Base, ToMerge);2414}24152416void AttributeFuncs::updateMinLegalVectorWidthAttr(Function &Fn,2417uint64_t Width) {2418Attribute Attr = Fn.getFnAttribute("min-legal-vector-width");2419if (Attr.isValid()) {2420uint64_t OldWidth;2421Attr.getValueAsString().getAsInteger(0, OldWidth);2422if (Width > OldWidth)2423Fn.addFnAttr("min-legal-vector-width", llvm::utostr(Width));2424}2425}242624272428