mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 15:26:07 +00:00

Floating-point libcalls are currently conservatively marked as may write any memory. Restrict these to clobber only `errno`.
1180 lines
38 KiB
C++
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;
|
|
}
|