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