| //===- Function.cpp - Implement the Global object classes -----------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the Function class for the IR library. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/IR/Function.h" | |
| #include "SymbolTableListTraitsImpl.h" | |
| #include "llvm/ADT/ArrayRef.h" | |
| #include "llvm/ADT/BitVector.h" | |
| #include "llvm/ADT/DenseSet.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/ADT/SmallString.h" | |
| #include "llvm/ADT/SmallVector.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include "llvm/IR/AbstractCallSite.h" | |
| #include "llvm/IR/Argument.h" | |
| #include "llvm/IR/Attributes.h" | |
| #include "llvm/IR/BasicBlock.h" | |
| #include "llvm/IR/Constant.h" | |
| #include "llvm/IR/ConstantRange.h" | |
| #include "llvm/IR/Constants.h" | |
| #include "llvm/IR/DerivedTypes.h" | |
| #include "llvm/IR/GlobalValue.h" | |
| #include "llvm/IR/InstIterator.h" | |
| #include "llvm/IR/Instruction.h" | |
| #include "llvm/IR/IntrinsicInst.h" | |
| #include "llvm/IR/Intrinsics.h" | |
| #include "llvm/IR/LLVMContext.h" | |
| #include "llvm/IR/MDBuilder.h" | |
| #include "llvm/IR/Metadata.h" | |
| #include "llvm/IR/Module.h" | |
| #include "llvm/IR/Operator.h" | |
| #include "llvm/IR/ProfDataUtils.h" | |
| #include "llvm/IR/SymbolTableListTraits.h" | |
| #include "llvm/IR/Type.h" | |
| #include "llvm/IR/Use.h" | |
| #include "llvm/IR/User.h" | |
| #include "llvm/IR/Value.h" | |
| #include "llvm/IR/ValueSymbolTable.h" | |
| #include "llvm/Support/Casting.h" | |
| #include "llvm/Support/CommandLine.h" | |
| #include "llvm/Support/Compiler.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/ModRef.h" | |
| #include <cassert> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <cstring> | |
| #include <string> | |
| using namespace llvm; | |
| // Explicit instantiations of SymbolTableListTraits since some of the methods | |
| // are not in the public header file... | |
| template class LLVM_EXPORT_TEMPLATE llvm::SymbolTableListTraits<BasicBlock>; | |
| static cl::opt<int> NonGlobalValueMaxNameSize( | |
| "non-global-value-max-name-size", cl::Hidden, cl::init(1024), | |
| cl::desc("Maximum size for the name of non-global values.")); | |
| void Function::renumberBlocks() { | |
| validateBlockNumbers(); | |
| NextBlockNum = 0; | |
| for (auto &BB : *this) | |
| BB.Number = NextBlockNum++; | |
| BlockNumEpoch++; | |
| } | |
| void Function::validateBlockNumbers() const { | |
| #ifndef NDEBUG | |
| BitVector Numbers(NextBlockNum); | |
| for (const auto &BB : *this) { | |
| unsigned Num = BB.getNumber(); | |
| assert(Num < NextBlockNum && "out of range block number"); | |
| assert(!Numbers[Num] && "duplicate block numbers"); | |
| Numbers.set(Num); | |
| } | |
| #endif | |
| } | |
| void Function::convertToNewDbgValues() { | |
| for (auto &BB : *this) { | |
| BB.convertToNewDbgValues(); | |
| } | |
| } | |
| bool Function::convertFromNewDbgValues() { | |
| bool Modified = false; | |
| for (auto &BB : *this) { | |
| if (BB.convertFromNewDbgValues()) | |
| Modified = true; | |
| } | |
| return Modified; | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Argument Implementation | |
| //===----------------------------------------------------------------------===// | |
| Argument::Argument(Type *Ty, const Twine &Name, Function *Par, unsigned ArgNo) | |
| : Value(Ty, Value::ArgumentVal), Parent(Par), ArgNo(ArgNo) { | |
| setName(Name); | |
| } | |
| void Argument::setParent(Function *parent) { | |
| Parent = parent; | |
| } | |
| bool Argument::hasNonNullAttr(bool AllowUndefOrPoison) const { | |
| if (!getType()->isPointerTy()) return false; | |
| AttributeSet Attrs = getAttributes(); | |
| if (Attrs.hasAttribute(Attribute::NonNull) && | |
| (AllowUndefOrPoison || Attrs.hasAttribute(Attribute::NoUndef))) | |
| return true; | |
| else if (getDereferenceableBytes() > 0 && | |
| !NullPointerIsDefined(getParent(), | |
| getType()->getPointerAddressSpace())) | |
| return true; | |
| return false; | |
| } | |
| bool Argument::hasByValAttr() const { | |
| if (!getType()->isPointerTy()) return false; | |
| return hasAttribute(Attribute::ByVal); | |
| } | |
| DeadOnReturnInfo Argument::getDeadOnReturnInfo() const { | |
| assert(getType()->isPointerTy() && "Only pointers have dead_on_return bytes"); | |
| return getParent()->getDeadOnReturnInfo(getArgNo()); | |
| } | |
| bool Argument::hasByRefAttr() const { | |
| if (!getType()->isPointerTy()) | |
| return false; | |
| return hasAttribute(Attribute::ByRef); | |
| } | |
| bool Argument::hasSwiftSelfAttr() const { | |
| return getParent()->hasParamAttribute(getArgNo(), Attribute::SwiftSelf); | |
| } | |
| bool Argument::hasSwiftErrorAttr() const { | |
| return getParent()->hasParamAttribute(getArgNo(), Attribute::SwiftError); | |
| } | |
| bool Argument::hasInAllocaAttr() const { | |
| if (!getType()->isPointerTy()) return false; | |
| return hasAttribute(Attribute::InAlloca); | |
| } | |
| bool Argument::hasPreallocatedAttr() const { | |
| if (!getType()->isPointerTy()) | |
| return false; | |
| return hasAttribute(Attribute::Preallocated); | |
| } | |
| bool Argument::hasPassPointeeByValueCopyAttr() const { | |
| if (!getType()->isPointerTy()) return false; | |
| AttributeSet Attrs = getAttributes(); | |
| return Attrs.hasAttribute(Attribute::ByVal) || | |
| Attrs.hasAttribute(Attribute::InAlloca) || | |
| Attrs.hasAttribute(Attribute::Preallocated); | |
| } | |
| bool Argument::hasPointeeInMemoryValueAttr() const { | |
| if (!getType()->isPointerTy()) | |
| return false; | |
| AttributeSet Attrs = getAttributes(); | |
| return Attrs.hasAttribute(Attribute::ByVal) || | |
| Attrs.hasAttribute(Attribute::StructRet) || | |
| Attrs.hasAttribute(Attribute::InAlloca) || | |
| Attrs.hasAttribute(Attribute::Preallocated) || | |
| Attrs.hasAttribute(Attribute::ByRef); | |
| } | |
| /// For a byval, sret, inalloca, or preallocated parameter, get the in-memory | |
| /// parameter type. | |
| static Type *getMemoryParamAllocType(AttributeSet ParamAttrs) { | |
| // FIXME: All the type carrying attributes are mutually exclusive, so there | |
| // should be a single query to get the stored type that handles any of them. | |
| if (Type *ByValTy = ParamAttrs.getByValType()) | |
| return ByValTy; | |
| if (Type *ByRefTy = ParamAttrs.getByRefType()) | |
| return ByRefTy; | |
| if (Type *PreAllocTy = ParamAttrs.getPreallocatedType()) | |
| return PreAllocTy; | |
| if (Type *InAllocaTy = ParamAttrs.getInAllocaType()) | |
| return InAllocaTy; | |
| if (Type *SRetTy = ParamAttrs.getStructRetType()) | |
| return SRetTy; | |
| return nullptr; | |
| } | |
| uint64_t Argument::getPassPointeeByValueCopySize(const DataLayout &DL) const { | |
| if (Type *MemTy = getMemoryParamAllocType(getAttributes())) | |
| return DL.getTypeAllocSize(MemTy); | |
| return 0; | |
| } | |
| Type *Argument::getPointeeInMemoryValueType() const { | |
| return getMemoryParamAllocType(getAttributes()); | |
| } | |
| MaybeAlign Argument::getParamAlign() const { | |
| assert(getType()->isPointerTy() && "Only pointers have alignments"); | |
| return getParent()->getParamAlign(getArgNo()); | |
| } | |
| MaybeAlign Argument::getParamStackAlign() const { | |
| return getParent()->getParamStackAlign(getArgNo()); | |
| } | |
| Type *Argument::getParamByValType() const { | |
| assert(getType()->isPointerTy() && "Only pointers have byval types"); | |
| return getParent()->getParamByValType(getArgNo()); | |
| } | |
| Type *Argument::getParamStructRetType() const { | |
| assert(getType()->isPointerTy() && "Only pointers have sret types"); | |
| return getParent()->getParamStructRetType(getArgNo()); | |
| } | |
| Type *Argument::getParamByRefType() const { | |
| assert(getType()->isPointerTy() && "Only pointers have byref types"); | |
| return getParent()->getParamByRefType(getArgNo()); | |
| } | |
| Type *Argument::getParamInAllocaType() const { | |
| assert(getType()->isPointerTy() && "Only pointers have inalloca types"); | |
| return getParent()->getParamInAllocaType(getArgNo()); | |
| } | |
| uint64_t Argument::getDereferenceableBytes() const { | |
| assert(getType()->isPointerTy() && | |
| "Only pointers have dereferenceable bytes"); | |
| return getParent()->getParamDereferenceableBytes(getArgNo()); | |
| } | |
| uint64_t Argument::getDereferenceableOrNullBytes() const { | |
| assert(getType()->isPointerTy() && | |
| "Only pointers have dereferenceable bytes"); | |
| return getParent()->getParamDereferenceableOrNullBytes(getArgNo()); | |
| } | |
| FPClassTest Argument::getNoFPClass() const { | |
| return getParent()->getParamNoFPClass(getArgNo()); | |
| } | |
| std::optional<ConstantRange> Argument::getRange() const { | |
| const Attribute RangeAttr = getAttribute(llvm::Attribute::Range); | |
| if (RangeAttr.isValid()) | |
| return RangeAttr.getRange(); | |
| return std::nullopt; | |
| } | |
| bool Argument::hasNestAttr() const { | |
| if (!getType()->isPointerTy()) return false; | |
| return hasAttribute(Attribute::Nest); | |
| } | |
| bool Argument::hasNoAliasAttr() const { | |
| if (!getType()->isPointerTy()) return false; | |
| return hasAttribute(Attribute::NoAlias); | |
| } | |
| bool Argument::hasNoCaptureAttr() const { | |
| if (!getType()->isPointerTy()) return false; | |
| return capturesNothing(getAttributes().getCaptureInfo()); | |
| } | |
| bool Argument::hasNoFreeAttr() const { | |
| if (!getType()->isPointerTy()) return false; | |
| return hasAttribute(Attribute::NoFree); | |
| } | |
| bool Argument::hasStructRetAttr() const { | |
| if (!getType()->isPointerTy()) return false; | |
| return hasAttribute(Attribute::StructRet); | |
| } | |
| bool Argument::hasInRegAttr() const { | |
| return hasAttribute(Attribute::InReg); | |
| } | |
| bool Argument::hasReturnedAttr() const { | |
| return hasAttribute(Attribute::Returned); | |
| } | |
| bool Argument::hasZExtAttr() const { | |
| return hasAttribute(Attribute::ZExt); | |
| } | |
| bool Argument::hasSExtAttr() const { | |
| return hasAttribute(Attribute::SExt); | |
| } | |
| bool Argument::onlyReadsMemory() const { | |
| AttributeSet Attrs = getAttributes(); | |
| return Attrs.hasAttribute(Attribute::ReadOnly) || | |
| Attrs.hasAttribute(Attribute::ReadNone); | |
| } | |
| void Argument::addAttrs(AttrBuilder &B) { | |
| AttributeList AL = getParent()->getAttributes(); | |
| AL = AL.addParamAttributes(Parent->getContext(), getArgNo(), B); | |
| getParent()->setAttributes(AL); | |
| } | |
| void Argument::addAttr(Attribute::AttrKind Kind) { | |
| getParent()->addParamAttr(getArgNo(), Kind); | |
| } | |
| void Argument::addAttr(Attribute Attr) { | |
| getParent()->addParamAttr(getArgNo(), Attr); | |
| } | |
| void Argument::removeAttr(Attribute::AttrKind Kind) { | |
| getParent()->removeParamAttr(getArgNo(), Kind); | |
| } | |
| void Argument::removeAttrs(const AttributeMask &AM) { | |
| AttributeList AL = getParent()->getAttributes(); | |
| AL = AL.removeParamAttributes(Parent->getContext(), getArgNo(), AM); | |
| getParent()->setAttributes(AL); | |
| } | |
| bool Argument::hasAttribute(Attribute::AttrKind Kind) const { | |
| return getParent()->hasParamAttribute(getArgNo(), Kind); | |
| } | |
| bool Argument::hasAttribute(StringRef Kind) const { | |
| return getParent()->hasParamAttribute(getArgNo(), Kind); | |
| } | |
| Attribute Argument::getAttribute(Attribute::AttrKind Kind) const { | |
| return getParent()->getParamAttribute(getArgNo(), Kind); | |
| } | |
| AttributeSet Argument::getAttributes() const { | |
| return getParent()->getAttributes().getParamAttrs(getArgNo()); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Helper Methods in Function | |
| //===----------------------------------------------------------------------===// | |
| LLVMContext &Function::getContext() const { | |
| return getType()->getContext(); | |
| } | |
| const DataLayout &Function::getDataLayout() const { | |
| return getParent()->getDataLayout(); | |
| } | |
| unsigned Function::getInstructionCount() const { | |
| unsigned NumInstrs = 0; | |
| for (const BasicBlock &BB : BasicBlocks) | |
| NumInstrs += BB.size(); | |
| return NumInstrs; | |
| } | |
| Function *Function::Create(FunctionType *Ty, LinkageTypes Linkage, | |
| const Twine &N, Module &M) { | |
| return Create(Ty, Linkage, M.getDataLayout().getProgramAddressSpace(), N, &M); | |
| } | |
| Function *Function::createWithDefaultAttr(FunctionType *Ty, | |
| LinkageTypes Linkage, | |
| unsigned AddrSpace, const Twine &N, | |
| Module *M) { | |
| auto *F = new (AllocMarker) Function(Ty, Linkage, AddrSpace, N, M); | |
| AttrBuilder B(F->getContext()); | |
| UWTableKind UWTable = M->getUwtable(); | |
| if (UWTable != UWTableKind::None) | |
| B.addUWTableAttr(UWTable); | |
| switch (M->getFramePointer()) { | |
| case FramePointerKind::None: | |
| // 0 ("none") is the default. | |
| break; | |
| case FramePointerKind::Reserved: | |
| B.addAttribute("frame-pointer", "reserved"); | |
| break; | |
| case FramePointerKind::NonLeaf: | |
| B.addAttribute("frame-pointer", "non-leaf"); | |
| break; | |
| case FramePointerKind::NonLeafNoReserve: | |
| B.addAttribute("frame-pointer", "non-leaf-no-reserve"); | |
| break; | |
| case FramePointerKind::All: | |
| B.addAttribute("frame-pointer", "all"); | |
| break; | |
| } | |
| if (M->getModuleFlag("function_return_thunk_extern")) | |
| B.addAttribute(Attribute::FnRetThunkExtern); | |
| StringRef DefaultCPU = F->getContext().getDefaultTargetCPU(); | |
| if (!DefaultCPU.empty()) | |
| B.addAttribute("target-cpu", DefaultCPU); | |
| StringRef DefaultFeatures = F->getContext().getDefaultTargetFeatures(); | |
| if (!DefaultFeatures.empty()) | |
| B.addAttribute("target-features", DefaultFeatures); | |
| // Check if the module attribute is present and not zero. | |
| auto isModuleAttributeSet = [&](const StringRef &ModAttr) -> bool { | |
| const auto *Attr = | |
| mdconst::extract_or_null<ConstantInt>(M->getModuleFlag(ModAttr)); | |
| return Attr && !Attr->isZero(); | |
| }; | |
| auto AddAttributeIfSet = [&](const StringRef &ModAttr) { | |
| if (isModuleAttributeSet(ModAttr)) | |
| B.addAttribute(ModAttr); | |
| }; | |
| StringRef SignType = "none"; | |
| if (isModuleAttributeSet("sign-return-address")) | |
| SignType = "non-leaf"; | |
| if (isModuleAttributeSet("sign-return-address-all")) | |
| SignType = "all"; | |
| if (SignType != "none") { | |
| B.addAttribute("sign-return-address", SignType); | |
| B.addAttribute("sign-return-address-key", | |
| isModuleAttributeSet("sign-return-address-with-bkey") | |
| ? "b_key" | |
| : "a_key"); | |
| } | |
| if (auto Value = dyn_cast_if_present<MDString>( | |
| M->getModuleFlag("sign-return-address-harden"))) | |
| B.addAttribute("sign-return-address-harden", Value->getString()); | |
| AddAttributeIfSet("branch-target-enforcement"); | |
| AddAttributeIfSet("branch-protection-pauth-lr"); | |
| AddAttributeIfSet("guarded-control-stack"); | |
| AddAttributeIfSet("ptrauth-returns"); | |
| AddAttributeIfSet("ptrauth-auth-traps"); | |
| AddAttributeIfSet("ptrauth-indirect-gotos"); | |
| AddAttributeIfSet("aarch64-jump-table-hardening"); | |
| F->addFnAttrs(B); | |
| return F; | |
| } | |
| void Function::removeFromParent() { | |
| getParent()->getFunctionList().remove(getIterator()); | |
| } | |
| void Function::eraseFromParent() { | |
| getParent()->getFunctionList().erase(getIterator()); | |
| } | |
| void Function::splice(Function::iterator ToIt, Function *FromF, | |
| Function::iterator FromBeginIt, | |
| Function::iterator FromEndIt) { | |
| #ifdef EXPENSIVE_CHECKS | |
| // Check that FromBeginIt is before FromEndIt. | |
| auto FromFEnd = FromF->end(); | |
| for (auto It = FromBeginIt; It != FromEndIt; ++It) | |
| assert(It != FromFEnd && "FromBeginIt not before FromEndIt!"); | |
| #endif // EXPENSIVE_CHECKS | |
| BasicBlocks.splice(ToIt, FromF->BasicBlocks, FromBeginIt, FromEndIt); | |
| } | |
| Function::iterator Function::erase(Function::iterator FromIt, | |
| Function::iterator ToIt) { | |
| return BasicBlocks.erase(FromIt, ToIt); | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // Function Implementation | |
| //===----------------------------------------------------------------------===// | |
| static unsigned computeAddrSpace(unsigned AddrSpace, Module *M) { | |
| // If AS == -1 and we are passed a valid module pointer we place the function | |
| // in the program address space. Otherwise we default to AS0. | |
| if (AddrSpace == static_cast<unsigned>(-1)) | |
| return M ? M->getDataLayout().getProgramAddressSpace() : 0; | |
| return AddrSpace; | |
| } | |
| Function::Function(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, | |
| const Twine &name, Module *ParentModule) | |
| : GlobalObject(Ty, Value::FunctionVal, AllocMarker, Linkage, name, | |
| computeAddrSpace(AddrSpace, ParentModule)), | |
| NumArgs(Ty->getNumParams()) { | |
| assert(FunctionType::isValidReturnType(getReturnType()) && | |
| "invalid return type"); | |
| setGlobalObjectSubClassData(0); | |
| // We only need a symbol table for a function if the context keeps value names | |
| if (!getContext().shouldDiscardValueNames()) | |
| SymTab = std::make_unique<ValueSymbolTable>(NonGlobalValueMaxNameSize); | |
| // If the function has arguments, mark them as lazily built. | |
| if (Ty->getNumParams()) | |
| setValueSubclassData(1); // Set the "has lazy arguments" bit. | |
| if (ParentModule) { | |
| ParentModule->getFunctionList().push_back(this); | |
| } | |
| HasLLVMReservedName = getName().starts_with("llvm."); | |
| // Ensure intrinsics have the right parameter attributes. | |
| // Note, the IntID field will have been set in Value::setName if this function | |
| // name is a valid intrinsic ID. | |
| if (IntID) { | |
| // Don't set the attributes if the intrinsic signature is invalid. This | |
| // case will either be auto-upgraded or fail verification. | |
| SmallVector<Type *> OverloadTys; | |
| if (!Intrinsic::isSignatureValid(IntID, Ty, OverloadTys)) | |
| return; | |
| setAttributes(Intrinsic::getAttributes(getContext(), IntID, Ty)); | |
| } | |
| } | |
| Function::~Function() { | |
| validateBlockNumbers(); | |
| dropAllReferences(); // After this it is safe to delete instructions. | |
| // Delete all of the method arguments and unlink from symbol table... | |
| if (Arguments) | |
| clearArguments(); | |
| // Remove the function from the on-the-side GC table. | |
| clearGC(); | |
| } | |
| void Function::BuildLazyArguments() const { | |
| // Create the arguments vector, all arguments start out unnamed. | |
| auto *FT = getFunctionType(); | |
| if (NumArgs > 0) { | |
| Arguments = std::allocator<Argument>().allocate(NumArgs); | |
| for (unsigned i = 0, e = NumArgs; i != e; ++i) { | |
| Type *ArgTy = FT->getParamType(i); | |
| assert(!ArgTy->isVoidTy() && "Cannot have void typed arguments!"); | |
| new (Arguments + i) Argument(ArgTy, "", const_cast<Function *>(this), i); | |
| } | |
| } | |
| // Clear the lazy arguments bit. | |
| unsigned SDC = getSubclassDataFromValue(); | |
| SDC &= ~(1 << 0); | |
| const_cast<Function*>(this)->setValueSubclassData(SDC); | |
| assert(!hasLazyArguments()); | |
| } | |
| static MutableArrayRef<Argument> makeArgArray(Argument *Args, size_t Count) { | |
| return MutableArrayRef<Argument>(Args, Count); | |
| } | |
| bool Function::isConstrainedFPIntrinsic() const { | |
| return Intrinsic::isConstrainedFPIntrinsic(getIntrinsicID()); | |
| } | |
| void Function::clearArguments() { | |
| for (Argument &A : makeArgArray(Arguments, NumArgs)) { | |
| A.setName(""); | |
| A.~Argument(); | |
| } | |
| std::allocator<Argument>().deallocate(Arguments, NumArgs); | |
| Arguments = nullptr; | |
| } | |
| void Function::stealArgumentListFrom(Function &Src) { | |
| assert(isDeclaration() && "Expected no references to current arguments"); | |
| // Drop the current arguments, if any, and set the lazy argument bit. | |
| if (!hasLazyArguments()) { | |
| assert(llvm::all_of(makeArgArray(Arguments, NumArgs), | |
| [](const Argument &A) { return A.use_empty(); }) && | |
| "Expected arguments to be unused in declaration"); | |
| clearArguments(); | |
| setValueSubclassData(getSubclassDataFromValue() | (1 << 0)); | |
| } | |
| // Nothing to steal if Src has lazy arguments. | |
| if (Src.hasLazyArguments()) | |
| return; | |
| // Steal arguments from Src, and fix the lazy argument bits. | |
| assert(arg_size() == Src.arg_size()); | |
| Arguments = Src.Arguments; | |
| Src.Arguments = nullptr; | |
| for (Argument &A : makeArgArray(Arguments, NumArgs)) { | |
| // FIXME: This does the work of transferNodesFromList inefficiently. | |
| SmallString<128> Name; | |
| if (A.hasName()) | |
| Name = A.getName(); | |
| if (!Name.empty()) | |
| A.setName(""); | |
| A.setParent(this); | |
| if (!Name.empty()) | |
| A.setName(Name); | |
| } | |
| setValueSubclassData(getSubclassDataFromValue() & ~(1 << 0)); | |
| assert(!hasLazyArguments()); | |
| Src.setValueSubclassData(Src.getSubclassDataFromValue() | (1 << 0)); | |
| } | |
| void Function::deleteBodyImpl(bool ShouldDrop) { | |
| setIsMaterializable(false); | |
| for (BasicBlock &BB : *this) | |
| BB.dropAllReferences(); | |
| // Delete all basic blocks. They are now unused, except possibly by | |
| // blockaddresses, but BasicBlock's destructor takes care of those. | |
| while (!BasicBlocks.empty()) | |
| BasicBlocks.begin()->eraseFromParent(); | |
| if (getNumOperands()) { | |
| if (ShouldDrop) { | |
| // Drop uses of any optional data (real or placeholder). | |
| User::dropAllReferences(); | |
| setNumHungOffUseOperands(0); | |
| } else { | |
| // The code needs to match Function::allocHungoffUselist(). | |
| auto *CPN = ConstantPointerNull::get(PointerType::get(getContext(), 0)); | |
| Op<0>().set(CPN); | |
| Op<1>().set(CPN); | |
| Op<2>().set(CPN); | |
| } | |
| setValueSubclassData(getSubclassDataFromValue() & ~0xe); | |
| } | |
| // Metadata is stored in a side-table. | |
| clearMetadata(); | |
| } | |
| void Function::addAttributeAtIndex(unsigned i, Attribute Attr) { | |
| AttributeSets = AttributeSets.addAttributeAtIndex(getContext(), i, Attr); | |
| } | |
| void Function::addFnAttr(Attribute::AttrKind Kind) { | |
| AttributeSets = AttributeSets.addFnAttribute(getContext(), Kind); | |
| } | |
| void Function::addFnAttr(StringRef Kind, StringRef Val) { | |
| AttributeSets = AttributeSets.addFnAttribute(getContext(), Kind, Val); | |
| } | |
| void Function::addFnAttr(Attribute Attr) { | |
| AttributeSets = AttributeSets.addFnAttribute(getContext(), Attr); | |
| } | |
| void Function::addFnAttrs(const AttrBuilder &Attrs) { | |
| AttributeSets = AttributeSets.addFnAttributes(getContext(), Attrs); | |
| } | |
| void Function::addRetAttr(Attribute::AttrKind Kind) { | |
| AttributeSets = AttributeSets.addRetAttribute(getContext(), Kind); | |
| } | |
| void Function::addRetAttr(Attribute Attr) { | |
| AttributeSets = AttributeSets.addRetAttribute(getContext(), Attr); | |
| } | |
| void Function::addRetAttrs(const AttrBuilder &Attrs) { | |
| AttributeSets = AttributeSets.addRetAttributes(getContext(), Attrs); | |
| } | |
| void Function::addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) { | |
| AttributeSets = AttributeSets.addParamAttribute(getContext(), ArgNo, Kind); | |
| } | |
| void Function::addParamAttr(unsigned ArgNo, Attribute Attr) { | |
| AttributeSets = AttributeSets.addParamAttribute(getContext(), ArgNo, Attr); | |
| } | |
| void Function::addParamAttrs(unsigned ArgNo, const AttrBuilder &Attrs) { | |
| AttributeSets = AttributeSets.addParamAttributes(getContext(), ArgNo, Attrs); | |
| } | |
| void Function::removeAttributeAtIndex(unsigned i, Attribute::AttrKind Kind) { | |
| AttributeSets = AttributeSets.removeAttributeAtIndex(getContext(), i, Kind); | |
| } | |
| void Function::removeAttributeAtIndex(unsigned i, StringRef Kind) { | |
| AttributeSets = AttributeSets.removeAttributeAtIndex(getContext(), i, Kind); | |
| } | |
| void Function::removeFnAttr(Attribute::AttrKind Kind) { | |
| AttributeSets = AttributeSets.removeFnAttribute(getContext(), Kind); | |
| } | |
| void Function::removeFnAttr(StringRef Kind) { | |
| AttributeSets = AttributeSets.removeFnAttribute(getContext(), Kind); | |
| } | |
| void Function::removeFnAttrs(const AttributeMask &AM) { | |
| AttributeSets = AttributeSets.removeFnAttributes(getContext(), AM); | |
| } | |
| void Function::removeRetAttr(Attribute::AttrKind Kind) { | |
| AttributeSets = AttributeSets.removeRetAttribute(getContext(), Kind); | |
| } | |
| void Function::removeRetAttr(StringRef Kind) { | |
| AttributeSets = AttributeSets.removeRetAttribute(getContext(), Kind); | |
| } | |
| void Function::removeRetAttrs(const AttributeMask &Attrs) { | |
| AttributeSets = AttributeSets.removeRetAttributes(getContext(), Attrs); | |
| } | |
| void Function::removeParamAttr(unsigned ArgNo, Attribute::AttrKind Kind) { | |
| AttributeSets = AttributeSets.removeParamAttribute(getContext(), ArgNo, Kind); | |
| } | |
| void Function::removeParamAttr(unsigned ArgNo, StringRef Kind) { | |
| AttributeSets = AttributeSets.removeParamAttribute(getContext(), ArgNo, Kind); | |
| } | |
| void Function::removeParamAttrs(unsigned ArgNo, const AttributeMask &Attrs) { | |
| AttributeSets = | |
| AttributeSets.removeParamAttributes(getContext(), ArgNo, Attrs); | |
| } | |
| void Function::addDereferenceableParamAttr(unsigned ArgNo, uint64_t Bytes) { | |
| AttributeSets = | |
| AttributeSets.addDereferenceableParamAttr(getContext(), ArgNo, Bytes); | |
| } | |
| bool Function::hasFnAttribute(Attribute::AttrKind Kind) const { | |
| return AttributeSets.hasFnAttr(Kind); | |
| } | |
| bool Function::hasFnAttribute(StringRef Kind) const { | |
| return AttributeSets.hasFnAttr(Kind); | |
| } | |
| bool Function::hasRetAttribute(Attribute::AttrKind Kind) const { | |
| return AttributeSets.hasRetAttr(Kind); | |
| } | |
| bool Function::hasParamAttribute(unsigned ArgNo, | |
| Attribute::AttrKind Kind) const { | |
| return AttributeSets.hasParamAttr(ArgNo, Kind); | |
| } | |
| bool Function::hasParamAttribute(unsigned ArgNo, StringRef Kind) const { | |
| return AttributeSets.hasParamAttr(ArgNo, Kind); | |
| } | |
| Attribute Function::getAttributeAtIndex(unsigned i, | |
| Attribute::AttrKind Kind) const { | |
| return AttributeSets.getAttributeAtIndex(i, Kind); | |
| } | |
| Attribute Function::getAttributeAtIndex(unsigned i, StringRef Kind) const { | |
| return AttributeSets.getAttributeAtIndex(i, Kind); | |
| } | |
| bool Function::hasAttributeAtIndex(unsigned Idx, | |
| Attribute::AttrKind Kind) const { | |
| return AttributeSets.hasAttributeAtIndex(Idx, Kind); | |
| } | |
| Attribute Function::getFnAttribute(Attribute::AttrKind Kind) const { | |
| return AttributeSets.getFnAttr(Kind); | |
| } | |
| Attribute Function::getFnAttribute(StringRef Kind) const { | |
| return AttributeSets.getFnAttr(Kind); | |
| } | |
| Attribute Function::getRetAttribute(Attribute::AttrKind Kind) const { | |
| return AttributeSets.getRetAttr(Kind); | |
| } | |
| uint64_t Function::getFnAttributeAsParsedInteger(StringRef Name, | |
| uint64_t Default) const { | |
| Attribute A = getFnAttribute(Name); | |
| uint64_t Result = Default; | |
| if (A.isStringAttribute()) { | |
| StringRef Str = A.getValueAsString(); | |
| if (Str.getAsInteger(0, Result)) | |
| getContext().emitError("cannot parse integer attribute " + Name); | |
| } | |
| return Result; | |
| } | |
| /// gets the specified attribute from the list of attributes. | |
| Attribute Function::getParamAttribute(unsigned ArgNo, | |
| Attribute::AttrKind Kind) const { | |
| return AttributeSets.getParamAttr(ArgNo, Kind); | |
| } | |
| void Function::addDereferenceableOrNullParamAttr(unsigned ArgNo, | |
| uint64_t Bytes) { | |
| AttributeSets = AttributeSets.addDereferenceableOrNullParamAttr(getContext(), | |
| ArgNo, Bytes); | |
| } | |
| void Function::addRangeRetAttr(const ConstantRange &CR) { | |
| AttributeSets = AttributeSets.addRangeRetAttr(getContext(), CR); | |
| } | |
| DenormalMode Function::getDenormalMode(const fltSemantics &FPType) const { | |
| Attribute Attr = getFnAttribute(Attribute::DenormalFPEnv); | |
| if (!Attr.isValid()) | |
| return DenormalMode::getDefault(); | |
| DenormalFPEnv FPEnv = Attr.getDenormalFPEnv(); | |
| return &FPType == &APFloat::IEEEsingle() ? FPEnv.F32Mode : FPEnv.DefaultMode; | |
| } | |
| DenormalFPEnv Function::getDenormalFPEnv() const { | |
| Attribute Attr = getFnAttribute(Attribute::DenormalFPEnv); | |
| return Attr.isValid() ? Attr.getDenormalFPEnv() : DenormalFPEnv::getDefault(); | |
| } | |
| const std::string &Function::getGC() const { | |
| assert(hasGC() && "Function has no collector"); | |
| return getContext().getGC(*this); | |
| } | |
| void Function::setGC(std::string Str) { | |
| setValueSubclassDataBit(14, !Str.empty()); | |
| getContext().setGC(*this, std::move(Str)); | |
| } | |
| void Function::clearGC() { | |
| if (!hasGC()) | |
| return; | |
| getContext().deleteGC(*this); | |
| setValueSubclassDataBit(14, false); | |
| } | |
| bool Function::hasStackProtectorFnAttr() const { | |
| return hasFnAttribute(Attribute::StackProtect) || | |
| hasFnAttribute(Attribute::StackProtectStrong) || | |
| hasFnAttribute(Attribute::StackProtectReq); | |
| } | |
| /// Copy all additional attributes (those not needed to create a Function) from | |
| /// the Function Src to this one. | |
| void Function::copyAttributesFrom(const Function *Src) { | |
| GlobalObject::copyAttributesFrom(Src); | |
| setCallingConv(Src->getCallingConv()); | |
| setAttributes(Src->getAttributes()); | |
| if (Src->hasGC()) | |
| setGC(Src->getGC()); | |
| else | |
| clearGC(); | |
| if (Src->hasPersonalityFn()) | |
| setPersonalityFn(Src->getPersonalityFn()); | |
| if (Src->hasPrefixData()) | |
| setPrefixData(Src->getPrefixData()); | |
| if (Src->hasPrologueData()) | |
| setPrologueData(Src->getPrologueData()); | |
| } | |
| MemoryEffects Function::getMemoryEffects() const { | |
| return getAttributes().getMemoryEffects(); | |
| } | |
| void Function::setMemoryEffects(MemoryEffects ME) { | |
| addFnAttr(Attribute::getWithMemoryEffects(getContext(), ME)); | |
| } | |
| /// Determine if the function does not access memory. | |
| bool Function::doesNotAccessMemory() const { | |
| return getMemoryEffects().doesNotAccessMemory(); | |
| } | |
| void Function::setDoesNotAccessMemory() { | |
| setMemoryEffects(MemoryEffects::none()); | |
| } | |
| /// Determine if the function does not access or only reads memory. | |
| bool Function::onlyReadsMemory() const { | |
| return getMemoryEffects().onlyReadsMemory(); | |
| } | |
| void Function::setOnlyReadsMemory() { | |
| setMemoryEffects(getMemoryEffects() & MemoryEffects::readOnly()); | |
| } | |
| /// Determine if the function does not access or only writes memory. | |
| bool Function::onlyWritesMemory() const { | |
| return getMemoryEffects().onlyWritesMemory(); | |
| } | |
| void Function::setOnlyWritesMemory() { | |
| setMemoryEffects(getMemoryEffects() & MemoryEffects::writeOnly()); | |
| } | |
| /// Determine if the call can access memory only using pointers based | |
| /// on its arguments. | |
| bool Function::onlyAccessesArgMemory() const { | |
| return getMemoryEffects().onlyAccessesArgPointees(); | |
| } | |
| void Function::setOnlyAccessesArgMemory() { | |
| setMemoryEffects(getMemoryEffects() & MemoryEffects::argMemOnly()); | |
| } | |
| /// Determine if the function may only access memory that is | |
| /// inaccessible from the IR. | |
| bool Function::onlyAccessesInaccessibleMemory() const { | |
| return getMemoryEffects().onlyAccessesInaccessibleMem(); | |
| } | |
| void Function::setOnlyAccessesInaccessibleMemory() { | |
| setMemoryEffects(getMemoryEffects() & MemoryEffects::inaccessibleMemOnly()); | |
| } | |
| /// Determine if the function may only access memory that is | |
| /// either inaccessible from the IR or pointed to by its arguments. | |
| bool Function::onlyAccessesInaccessibleMemOrArgMem() const { | |
| return getMemoryEffects().onlyAccessesInaccessibleOrArgMem(); | |
| } | |
| void Function::setOnlyAccessesInaccessibleMemOrArgMem() { | |
| setMemoryEffects(getMemoryEffects() & | |
| MemoryEffects::inaccessibleOrArgMemOnly()); | |
| } | |
| bool Function::isTargetIntrinsic() const { | |
| return Intrinsic::isTargetIntrinsic(IntID); | |
| } | |
| void Function::updateAfterNameChange() { | |
| LibFuncCache = UnknownLibFunc; | |
| StringRef Name = getName(); | |
| if (!Name.starts_with("llvm.")) { | |
| HasLLVMReservedName = false; | |
| IntID = Intrinsic::not_intrinsic; | |
| return; | |
| } | |
| HasLLVMReservedName = true; | |
| IntID = Intrinsic::lookupIntrinsicID(Name); | |
| } | |
| /// hasAddressTaken - returns true if there are any uses of this function | |
| /// other than direct calls or invokes to it. Optionally ignores callback | |
| /// uses, assume like pointer annotation calls, and references in llvm.used | |
| /// and llvm.compiler.used variables. | |
| bool Function::hasAddressTaken(const User **PutOffender, | |
| bool IgnoreCallbackUses, | |
| bool IgnoreAssumeLikeCalls, bool IgnoreLLVMUsed, | |
| bool IgnoreARCAttachedCall, | |
| bool IgnoreCastedDirectCall) const { | |
| for (const Use &U : uses()) { | |
| const User *FU = U.getUser(); | |
| if (IgnoreCallbackUses) { | |
| AbstractCallSite ACS(&U); | |
| if (ACS && ACS.isCallbackCall()) | |
| continue; | |
| } | |
| const auto *Call = dyn_cast<CallBase>(FU); | |
| if (!Call) { | |
| if (IgnoreAssumeLikeCalls && | |
| isa<BitCastOperator, AddrSpaceCastOperator>(FU) && | |
| all_of(FU->users(), [](const User *U) { | |
| if (const auto *I = dyn_cast<IntrinsicInst>(U)) | |
| return I->isAssumeLikeIntrinsic(); | |
| return false; | |
| })) { | |
| continue; | |
| } | |
| if (IgnoreLLVMUsed && !FU->user_empty()) { | |
| const User *FUU = FU; | |
| if (isa<BitCastOperator, AddrSpaceCastOperator>(FU) && | |
| FU->hasOneUse() && !FU->user_begin()->user_empty()) | |
| FUU = *FU->user_begin(); | |
| if (llvm::all_of(FUU->users(), [](const User *U) { | |
| if (const auto *GV = dyn_cast<GlobalVariable>(U)) | |
| return GV->hasName() && | |
| (GV->getName() == "llvm.compiler.used" || | |
| GV->getName() == "llvm.used"); | |
| return false; | |
| })) | |
| continue; | |
| } | |
| if (PutOffender) | |
| *PutOffender = FU; | |
| return true; | |
| } | |
| if (IgnoreAssumeLikeCalls) { | |
| if (const auto *I = dyn_cast<IntrinsicInst>(Call)) | |
| if (I->isAssumeLikeIntrinsic()) | |
| continue; | |
| } | |
| if (!Call->isCallee(&U) || (!IgnoreCastedDirectCall && | |
| Call->getFunctionType() != getFunctionType())) { | |
| if (IgnoreARCAttachedCall && | |
| Call->isOperandBundleOfType(LLVMContext::OB_clang_arc_attachedcall, | |
| U.getOperandNo())) | |
| continue; | |
| if (PutOffender) | |
| *PutOffender = FU; | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| bool Function::isDefTriviallyDead() const { | |
| // Check the linkage | |
| if (!hasLinkOnceLinkage() && !hasLocalLinkage() && | |
| !hasAvailableExternallyLinkage()) | |
| return false; | |
| return use_empty(); | |
| } | |
| /// callsFunctionThatReturnsTwice - Return true if the function has a call to | |
| /// setjmp or other function that gcc recognizes as "returning twice". | |
| bool Function::callsFunctionThatReturnsTwice() const { | |
| for (const Instruction &I : instructions(this)) | |
| if (const auto *Call = dyn_cast<CallBase>(&I)) | |
| if (Call->hasFnAttr(Attribute::ReturnsTwice)) | |
| return true; | |
| return false; | |
| } | |
| Constant *Function::getPersonalityFn() const { | |
| assert(hasPersonalityFn() && getNumOperands()); | |
| return cast<Constant>(Op<0>()); | |
| } | |
| void Function::setPersonalityFn(Constant *Fn) { | |
| setHungoffOperand<0>(Fn); | |
| setValueSubclassDataBit(3, Fn != nullptr); | |
| } | |
| Constant *Function::getPrefixData() const { | |
| assert(hasPrefixData() && getNumOperands()); | |
| return cast<Constant>(Op<1>()); | |
| } | |
| void Function::setPrefixData(Constant *PrefixData) { | |
| setHungoffOperand<1>(PrefixData); | |
| setValueSubclassDataBit(1, PrefixData != nullptr); | |
| } | |
| Constant *Function::getPrologueData() const { | |
| assert(hasPrologueData() && getNumOperands()); | |
| return cast<Constant>(Op<2>()); | |
| } | |
| void Function::setPrologueData(Constant *PrologueData) { | |
| setHungoffOperand<2>(PrologueData); | |
| setValueSubclassDataBit(2, PrologueData != nullptr); | |
| } | |
| void Function::allocHungoffUselist() { | |
| // If we've already allocated a uselist, stop here. | |
| if (getNumOperands()) | |
| return; | |
| allocHungoffUses(3, /*IsPhi=*/ false); | |
| setNumHungOffUseOperands(3); | |
| // Initialize the uselist with placeholder operands to allow traversal. | |
| auto *CPN = ConstantPointerNull::get(PointerType::get(getContext(), 0)); | |
| Op<0>().set(CPN); | |
| Op<1>().set(CPN); | |
| Op<2>().set(CPN); | |
| } | |
| template <int Idx> | |
| void Function::setHungoffOperand(Constant *C) { | |
| if (C) { | |
| allocHungoffUselist(); | |
| Op<Idx>().set(C); | |
| } else if (getNumOperands()) { | |
| Op<Idx>().set(ConstantPointerNull::get(PointerType::get(getContext(), 0))); | |
| } | |
| } | |
| void Function::setValueSubclassDataBit(unsigned Bit, bool On) { | |
| assert(Bit < 16 && "SubclassData contains only 16 bits"); | |
| if (On) | |
| setValueSubclassData(getSubclassDataFromValue() | (1 << Bit)); | |
| else | |
| setValueSubclassData(getSubclassDataFromValue() & ~(1 << Bit)); | |
| } | |
| void Function::setEntryCount(uint64_t Count, | |
| const DenseSet<GlobalValue::GUID> *S) { | |
| auto ImportGUIDs = getImportGUIDs(); | |
| if (S == nullptr && ImportGUIDs.size()) | |
| S = &ImportGUIDs; | |
| MDBuilder MDB(getContext()); | |
| setMetadata(LLVMContext::MD_prof, | |
| MDB.createFunctionEntryCount(Count, false, S)); | |
| } | |
| std::optional<uint64_t> Function::getEntryCount() const { | |
| MDNode *MD = getMetadata(LLVMContext::MD_prof); | |
| if (MD && MD->getOperand(0)) | |
| if (MDString *MDS = dyn_cast<MDString>(MD->getOperand(0))) { | |
| if (MDS->getString() != MDProfLabels::FunctionEntryCount) | |
| return std::nullopt; | |
| ConstantInt *CI = mdconst::extract<ConstantInt>(MD->getOperand(1)); | |
| uint64_t Count = CI->getValue().getZExtValue(); | |
| // A value of -1 is used for SamplePGO when there were no samples. | |
| // Treat this the same as unknown. | |
| if (Count == static_cast<uint64_t>(-1)) | |
| return std::nullopt; | |
| return Count; | |
| } | |
| return std::nullopt; | |
| } | |
| DenseSet<GlobalValue::GUID> Function::getImportGUIDs() const { | |
| DenseSet<GlobalValue::GUID> R; | |
| if (MDNode *MD = getMetadata(LLVMContext::MD_prof)) | |
| if (MDString *MDS = dyn_cast<MDString>(MD->getOperand(0))) | |
| if (MDS->getString() == MDProfLabels::FunctionEntryCount) | |
| for (unsigned i = 2; i < MD->getNumOperands(); i++) | |
| R.insert(mdconst::extract<ConstantInt>(MD->getOperand(i)) | |
| ->getValue() | |
| .getZExtValue()); | |
| return R; | |
| } | |
| bool Function::nullPointerIsDefined() const { | |
| return hasFnAttribute(Attribute::NullPointerIsValid); | |
| } | |
| unsigned Function::getVScaleValue() const { | |
| Attribute Attr = getFnAttribute(Attribute::VScaleRange); | |
| if (!Attr.isValid()) | |
| return 0; | |
| unsigned VScale = Attr.getVScaleRangeMin(); | |
| if (VScale && VScale == Attr.getVScaleRangeMax()) | |
| return VScale; | |
| return 0; | |
| } | |
| bool llvm::NullPointerIsDefined(const Function *F, unsigned AS) { | |
| if (F && F->nullPointerIsDefined()) | |
| return true; | |
| if (AS != 0) | |
| return true; | |
| return false; | |
| } | |
| bool llvm::CallingConv::supportsNonVoidReturnType(CallingConv::ID CC) { | |
| switch (CC) { | |
| case CallingConv::C: | |
| case CallingConv::Fast: | |
| case CallingConv::Cold: | |
| case CallingConv::GHC: | |
| case CallingConv::HiPE: | |
| case CallingConv::AnyReg: | |
| case CallingConv::PreserveMost: | |
| case CallingConv::PreserveAll: | |
| case CallingConv::Swift: | |
| case CallingConv::CXX_FAST_TLS: | |
| case CallingConv::Tail: | |
| case CallingConv::CFGuard_Check: | |
| case CallingConv::SwiftTail: | |
| case CallingConv::PreserveNone: | |
| case CallingConv::X86_StdCall: | |
| case CallingConv::X86_FastCall: | |
| case CallingConv::ARM_APCS: | |
| case CallingConv::ARM_AAPCS: | |
| case CallingConv::ARM_AAPCS_VFP: | |
| case CallingConv::MSP430_INTR: | |
| case CallingConv::X86_ThisCall: | |
| case CallingConv::PTX_Device: | |
| case CallingConv::SPIR_FUNC: | |
| case CallingConv::Intel_OCL_BI: | |
| case CallingConv::X86_64_SysV: | |
| case CallingConv::Win64: | |
| case CallingConv::X86_VectorCall: | |
| case CallingConv::DUMMY_HHVM: | |
| case CallingConv::DUMMY_HHVM_C: | |
| case CallingConv::X86_INTR: | |
| case CallingConv::AVR_INTR: | |
| case CallingConv::AVR_SIGNAL: | |
| case CallingConv::AVR_BUILTIN: | |
| return true; | |
| case CallingConv::AMDGPU_KERNEL: | |
| case CallingConv::SPIR_KERNEL: | |
| case CallingConv::AMDGPU_CS_Chain: | |
| case CallingConv::AMDGPU_CS_ChainPreserve: | |
| return false; | |
| case CallingConv::AMDGPU_VS: | |
| case CallingConv::AMDGPU_HS: | |
| case CallingConv::AMDGPU_GS: | |
| case CallingConv::AMDGPU_PS: | |
| case CallingConv::AMDGPU_CS: | |
| case CallingConv::AMDGPU_LS: | |
| case CallingConv::AMDGPU_ES: | |
| case CallingConv::MSP430_BUILTIN: | |
| case CallingConv::AArch64_VectorCall: | |
| case CallingConv::AArch64_SVE_VectorCall: | |
| case CallingConv::WASM_EmscriptenInvoke: | |
| case CallingConv::AMDGPU_Gfx: | |
| case CallingConv::AMDGPU_Gfx_WholeWave: | |
| case CallingConv::M68k_INTR: | |
| case CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X0: | |
| case CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2: | |
| case CallingConv::M68k_RTD: | |
| case CallingConv::GRAAL: | |
| case CallingConv::ARM64EC_Thunk_X64: | |
| case CallingConv::ARM64EC_Thunk_Native: | |
| case CallingConv::RISCV_VectorCall: | |
| case CallingConv::AArch64_SME_ABI_Support_Routines_PreserveMost_From_X1: | |
| case CallingConv::RISCV_VLSCall_32: | |
| case CallingConv::RISCV_VLSCall_64: | |
| case CallingConv::RISCV_VLSCall_128: | |
| case CallingConv::RISCV_VLSCall_256: | |
| case CallingConv::RISCV_VLSCall_512: | |
| case CallingConv::RISCV_VLSCall_1024: | |
| case CallingConv::RISCV_VLSCall_2048: | |
| case CallingConv::RISCV_VLSCall_4096: | |
| case CallingConv::RISCV_VLSCall_8192: | |
| case CallingConv::RISCV_VLSCall_16384: | |
| case CallingConv::RISCV_VLSCall_32768: | |
| case CallingConv::RISCV_VLSCall_65536: | |
| return true; | |
| default: | |
| return false; | |
| } | |
| llvm_unreachable("covered callingconv switch"); | |
| } |