llvm-project/llvm/lib/IR/Function.cpp
Antonio Frighetto 139add531a [InferAttrs] Mark floating-point libcalls as errno-writing
Floating-point libcalls are currently conservatively marked as
may write any memory. Restrict these to clobber only `errno`.
2025-03-13 10:40:33 +01:00

1180 lines
38 KiB
C++

//===- 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/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;
using ProfileCount = Function::ProfileCount;
// Explicit instantiations of SymbolTableListTraits since some of the methods
// are not in the public header file...
template class 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."));
extern cl::opt<bool> UseNewDbgInfoFormat;
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() {
IsNewDbgInfoFormat = true;
for (auto &BB : *this) {
BB.convertToNewDbgValues();
}
}
void Function::convertFromNewDbgValues() {
IsNewDbgInfoFormat = false;
for (auto &BB : *this) {
BB.convertFromNewDbgValues();
}
}
void Function::setIsNewDbgInfoFormat(bool NewFlag) {
if (NewFlag && !IsNewDbgInfoFormat)
convertToNewDbgValues();
else if (!NewFlag && IsNewDbgInfoFormat)
convertFromNewDbgValues();
}
void Function::setNewDbgInfoFormatFlag(bool NewFlag) {
for (auto &BB : *this) {
BB.setNewDbgInfoFormatFlag(NewFlag);
}
IsNewDbgInfoFormat = NewFlag;
}
//===----------------------------------------------------------------------===//
// 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;
if (getParent()->hasParamAttribute(getArgNo(), Attribute::NonNull) &&
(AllowUndefOrPoison ||
getParent()->hasParamAttribute(getArgNo(), 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);
}
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;
AttributeList Attrs = getParent()->getAttributes();
return Attrs.hasParamAttr(getArgNo(), Attribute::ByVal) ||
Attrs.hasParamAttr(getArgNo(), Attribute::InAlloca) ||
Attrs.hasParamAttr(getArgNo(), Attribute::Preallocated);
}
bool Argument::hasPointeeInMemoryValueAttr() const {
if (!getType()->isPointerTy())
return false;
AttributeList Attrs = getParent()->getAttributes();
return Attrs.hasParamAttr(getArgNo(), Attribute::ByVal) ||
Attrs.hasParamAttr(getArgNo(), Attribute::StructRet) ||
Attrs.hasParamAttr(getArgNo(), Attribute::InAlloca) ||
Attrs.hasParamAttr(getArgNo(), Attribute::Preallocated) ||
Attrs.hasParamAttr(getArgNo(), 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 {
AttributeSet ParamAttrs =
getParent()->getAttributes().getParamAttrs(getArgNo());
if (Type *MemTy = getMemoryParamAllocType(ParamAttrs))
return DL.getTypeAllocSize(MemTy);
return 0;
}
Type *Argument::getPointeeInMemoryValueType() const {
AttributeSet ParamAttrs =
getParent()->getAttributes().getParamAttrs(getArgNo());
return getMemoryParamAllocType(ParamAttrs);
}
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 {
AttributeList Attrs = getParent()->getAttributes();
return Attrs.hasParamAttr(getArgNo(), Attribute::ReadOnly) ||
Attrs.hasParamAttr(getArgNo(), 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 += std::distance(BB.instructionsWithoutDebug().begin(),
BB.instructionsWithoutDebug().end());
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::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");
}
AddAttributeIfSet("branch-target-enforcement");
AddAttributeIfSet("branch-protection-pauth-lr");
AddAttributeIfSet("guarded-control-stack");
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()), IsNewDbgInfoFormat(UseNewDbgInfoFormat) {
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);
IsNewDbgInfoFormat = ParentModule->IsNewDbgInfoFormat;
}
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)
setAttributes(Intrinsic::getAttributes(getContext(), IntID));
}
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 {
if (&FPType == &APFloat::IEEEsingle()) {
DenormalMode Mode = getDenormalModeF32Raw();
// If the f32 variant of the attribute isn't specified, try to use the
// generic one.
if (Mode.isValid())
return Mode;
}
return getDenormalModeRaw();
}
DenormalMode Function::getDenormalModeRaw() const {
Attribute Attr = getFnAttribute("denormal-fp-math");
StringRef Val = Attr.getValueAsString();
return parseDenormalFPAttribute(Val);
}
DenormalMode Function::getDenormalModeF32Raw() const {
Attribute Attr = getFnAttribute("denormal-fp-math-f32");
if (Attr.isValid()) {
StringRef Val = Attr.getValueAsString();
return parseDenormalFPAttribute(Val);
}
return DenormalMode::getInvalid();
}
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 (isa<BlockAddress>(FU))
continue;
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;
// Check if the function is used by anything other than a blockaddress.
for (const User *U : users())
if (!isa<BlockAddress>(U))
return false;
return true;
}
/// 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(ProfileCount Count,
const DenseSet<GlobalValue::GUID> *S) {
#if !defined(NDEBUG)
auto PrevCount = getEntryCount();
assert(!PrevCount || PrevCount->getType() == Count.getType());
#endif
auto ImportGUIDs = getImportGUIDs();
if (S == nullptr && ImportGUIDs.size())
S = &ImportGUIDs;
MDBuilder MDB(getContext());
setMetadata(
LLVMContext::MD_prof,
MDB.createFunctionEntryCount(Count.getCount(), Count.isSynthetic(), S));
}
void Function::setEntryCount(uint64_t Count, Function::ProfileCountType Type,
const DenseSet<GlobalValue::GUID> *Imports) {
setEntryCount(ProfileCount(Count, Type), Imports);
}
std::optional<ProfileCount> Function::getEntryCount(bool AllowSynthetic) const {
MDNode *MD = getMetadata(LLVMContext::MD_prof);
if (MD && MD->getOperand(0))
if (MDString *MDS = dyn_cast<MDString>(MD->getOperand(0))) {
if (MDS->getString() == "function_entry_count") {
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 == (uint64_t)-1)
return std::nullopt;
return ProfileCount(Count, PCT_Real);
} else if (AllowSynthetic &&
MDS->getString() == "synthetic_function_entry_count") {
ConstantInt *CI = mdconst::extract<ConstantInt>(MD->getOperand(1));
uint64_t Count = CI->getValue().getZExtValue();
return ProfileCount(Count, PCT_Synthetic);
}
}
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() == "function_entry_count")
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);
}
bool llvm::NullPointerIsDefined(const Function *F, unsigned AS) {
if (F && F->nullPointerIsDefined())
return true;
if (AS != 0)
return true;
return false;
}