#include "llvm/Analysis/InlineCost.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/CodeMetrics.h"
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/AssemblyAnnotationWriter.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/raw_ostream.h"
#include <climits>
#include <limits>
#include <optional>
usingnamespacellvm;
#define DEBUG_TYPE …
STATISTIC(NumCallsAnalyzed, "Number of call sites analyzed");
static cl::opt<int>
DefaultThreshold("inlinedefault-threshold", cl::Hidden, cl::init(225),
cl::desc("Default amount of inlining to perform"));
static cl::opt<bool> IgnoreTTIInlineCompatible(
"ignore-tti-inline-compatible", cl::Hidden, cl::init(false),
cl::desc("Ignore TTI attributes compatibility check between callee/caller "
"during inline cost calculation"));
static cl::opt<bool> PrintInstructionComments(
"print-instruction-comments", cl::Hidden, cl::init(false),
cl::desc("Prints comments for instruction based on inline cost analysis"));
static cl::opt<int> InlineThreshold(
"inline-threshold", cl::Hidden, cl::init(225),
cl::desc("Control the amount of inlining to perform (default = 225)"));
static cl::opt<int> HintThreshold(
"inlinehint-threshold", cl::Hidden, cl::init(325),
cl::desc("Threshold for inlining functions with inline hint"));
static cl::opt<int>
ColdCallSiteThreshold("inline-cold-callsite-threshold", cl::Hidden,
cl::init(45),
cl::desc("Threshold for inlining cold callsites"));
static cl::opt<bool> InlineEnableCostBenefitAnalysis(
"inline-enable-cost-benefit-analysis", cl::Hidden, cl::init(false),
cl::desc("Enable the cost-benefit analysis for the inliner"));
static cl::opt<int> InlineSavingsMultiplier(
"inline-savings-multiplier", cl::Hidden, cl::init(8),
cl::desc("Multiplier to multiply cycle savings by during inlining"));
static cl::opt<int> InlineSavingsProfitableMultiplier(
"inline-savings-profitable-multiplier", cl::Hidden, cl::init(4),
cl::desc("A multiplier on top of cycle savings to decide whether the "
"savings won't justify the cost"));
static cl::opt<int>
InlineSizeAllowance("inline-size-allowance", cl::Hidden, cl::init(100),
cl::desc("The maximum size of a callee that get's "
"inlined without sufficient cycle savings"));
static cl::opt<int> ColdThreshold(
"inlinecold-threshold", cl::Hidden, cl::init(45),
cl::desc("Threshold for inlining functions with cold attribute"));
static cl::opt<int>
HotCallSiteThreshold("hot-callsite-threshold", cl::Hidden, cl::init(3000),
cl::desc("Threshold for hot callsites "));
static cl::opt<int> LocallyHotCallSiteThreshold(
"locally-hot-callsite-threshold", cl::Hidden, cl::init(525),
cl::desc("Threshold for locally hot callsites "));
static cl::opt<int> ColdCallSiteRelFreq(
"cold-callsite-rel-freq", cl::Hidden, cl::init(2),
cl::desc("Maximum block frequency, expressed as a percentage of caller's "
"entry frequency, for a callsite to be cold in the absence of "
"profile information."));
static cl::opt<uint64_t> HotCallSiteRelFreq(
"hot-callsite-rel-freq", cl::Hidden, cl::init(60),
cl::desc("Minimum block frequency, expressed as a multiple of caller's "
"entry frequency, for a callsite to be hot in the absence of "
"profile information."));
static cl::opt<int>
InstrCost("inline-instr-cost", cl::Hidden, cl::init(5),
cl::desc("Cost of a single instruction when inlining"));
static cl::opt<int>
MemAccessCost("inline-memaccess-cost", cl::Hidden, cl::init(0),
cl::desc("Cost of load/store instruction when inlining"));
static cl::opt<int> CallPenalty(
"inline-call-penalty", cl::Hidden, cl::init(25),
cl::desc("Call penalty that is applied per callsite when inlining"));
static cl::opt<size_t>
StackSizeThreshold("inline-max-stacksize", cl::Hidden,
cl::init(std::numeric_limits<size_t>::max()),
cl::desc("Do not inline functions with a stack size "
"that exceeds the specified limit"));
static cl::opt<size_t> RecurStackSizeThreshold(
"recursive-inline-max-stacksize", cl::Hidden,
cl::init(InlineConstants::TotalAllocaSizeRecursiveCaller),
cl::desc("Do not inline recursive functions with a stack "
"size that exceeds the specified limit"));
static cl::opt<bool> OptComputeFullInlineCost(
"inline-cost-full", cl::Hidden,
cl::desc("Compute the full inline cost of a call site even when the cost "
"exceeds the threshold."));
static cl::opt<bool> InlineCallerSupersetNoBuiltin(
"inline-caller-superset-nobuiltin", cl::Hidden, cl::init(true),
cl::desc("Allow inlining when caller has a superset of callee's nobuiltin "
"attributes."));
static cl::opt<bool> DisableGEPConstOperand(
"disable-gep-const-evaluation", cl::Hidden, cl::init(false),
cl::desc("Disables evaluation of GetElementPtr with constant operands"));
namespace llvm {
std::optional<int> getStringFnAttrAsInt(const Attribute &Attr) { … }
std::optional<int> getStringFnAttrAsInt(CallBase &CB, StringRef AttrKind) { … }
std::optional<int> getStringFnAttrAsInt(Function *F, StringRef AttrKind) { … }
namespace InlineConstants {
int getInstrCost() { … }
}
}
namespace {
class InlineCostCallAnalyzer;
struct InstructionCostDetail { … };
class InlineCostAnnotationWriter : public AssemblyAnnotationWriter { … };
class CallAnalyzer : public InstVisitor<CallAnalyzer, bool> { … };
int64_t getExpectedNumberOfCompare(int NumCaseCluster) { … }
class InlineCostCallAnalyzer final : public CallAnalyzer { … };
static bool isSoleCallToLocalFunction(const CallBase &CB,
const Function &Callee) { … }
class InlineCostFeaturesAnalyzer final : public CallAnalyzer { … };
}
bool CallAnalyzer::isAllocaDerivedArg(Value *V) { … }
void CallAnalyzer::disableSROAForArg(AllocaInst *SROAArg) { … }
void InlineCostAnnotationWriter::emitInstructionAnnot(
const Instruction *I, formatted_raw_ostream &OS) { … }
void CallAnalyzer::disableSROA(Value *V) { … }
void CallAnalyzer::disableLoadElimination() { … }
bool CallAnalyzer::accumulateGEPOffset(GEPOperator &GEP, APInt &Offset) { … }
bool CallAnalyzer::isGEPFree(GetElementPtrInst &GEP) { … }
bool CallAnalyzer::visitAlloca(AllocaInst &I) { … }
bool CallAnalyzer::visitPHI(PHINode &I) { … }
bool CallAnalyzer::canFoldInboundsGEP(GetElementPtrInst &I) { … }
bool CallAnalyzer::visitGetElementPtr(GetElementPtrInst &I) { … }
bool CallAnalyzer::simplifyInstruction(Instruction &I) { … }
bool CallAnalyzer::simplifyIntrinsicCallIsConstant(CallBase &CB) { … }
bool CallAnalyzer::simplifyIntrinsicCallObjectSize(CallBase &CB) { … }
bool CallAnalyzer::visitBitCast(BitCastInst &I) { … }
bool CallAnalyzer::visitPtrToInt(PtrToIntInst &I) { … }
bool CallAnalyzer::visitIntToPtr(IntToPtrInst &I) { … }
bool CallAnalyzer::visitCastInst(CastInst &I) { … }
bool CallAnalyzer::paramHasAttr(Argument *A, Attribute::AttrKind Attr) { … }
bool CallAnalyzer::isKnownNonNullInCallee(Value *V) { … }
bool CallAnalyzer::allowSizeGrowth(CallBase &Call) { … }
bool InlineCostCallAnalyzer::isColdCallSite(CallBase &Call,
BlockFrequencyInfo *CallerBFI) { … }
std::optional<int>
InlineCostCallAnalyzer::getHotCallSiteThreshold(CallBase &Call,
BlockFrequencyInfo *CallerBFI) { … }
void InlineCostCallAnalyzer::updateThreshold(CallBase &Call, Function &Callee) { … }
bool CallAnalyzer::visitCmpInst(CmpInst &I) { … }
bool CallAnalyzer::visitSub(BinaryOperator &I) { … }
bool CallAnalyzer::visitBinaryOperator(BinaryOperator &I) { … }
bool CallAnalyzer::visitFNeg(UnaryOperator &I) { … }
bool CallAnalyzer::visitLoad(LoadInst &I) { … }
bool CallAnalyzer::visitStore(StoreInst &I) { … }
bool CallAnalyzer::visitExtractValue(ExtractValueInst &I) { … }
bool CallAnalyzer::visitInsertValue(InsertValueInst &I) { … }
bool CallAnalyzer::simplifyCallSite(Function *F, CallBase &Call) { … }
bool CallAnalyzer::visitCallBase(CallBase &Call) { … }
bool CallAnalyzer::visitReturnInst(ReturnInst &RI) { … }
bool CallAnalyzer::visitBranchInst(BranchInst &BI) { … }
bool CallAnalyzer::visitSelectInst(SelectInst &SI) { … }
bool CallAnalyzer::visitSwitchInst(SwitchInst &SI) { … }
bool CallAnalyzer::visitIndirectBrInst(IndirectBrInst &IBI) { … }
bool CallAnalyzer::visitResumeInst(ResumeInst &RI) { … }
bool CallAnalyzer::visitCleanupReturnInst(CleanupReturnInst &CRI) { … }
bool CallAnalyzer::visitCatchReturnInst(CatchReturnInst &CRI) { … }
bool CallAnalyzer::visitUnreachableInst(UnreachableInst &I) { … }
bool CallAnalyzer::visitInstruction(Instruction &I) { … }
InlineResult
CallAnalyzer::analyzeBlock(BasicBlock *BB,
SmallPtrSetImpl<const Value *> &EphValues) { … }
ConstantInt *CallAnalyzer::stripAndComputeInBoundsConstantOffsets(Value *&V) { … }
void CallAnalyzer::findDeadBlocks(BasicBlock *CurrBB, BasicBlock *NextBB) { … }
InlineResult CallAnalyzer::analyze() { … }
void InlineCostCallAnalyzer::print(raw_ostream &OS) { … }
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void InlineCostCallAnalyzer::dump() { print(dbgs()); }
#endif
static bool functionsHaveCompatibleAttributes(
Function *Caller, Function *Callee, TargetTransformInfo &TTI,
function_ref<const TargetLibraryInfo &(Function &)> &GetTLI) { … }
int llvm::getCallsiteCost(const TargetTransformInfo &TTI, const CallBase &Call,
const DataLayout &DL) { … }
InlineCost llvm::getInlineCost(
CallBase &Call, const InlineParams &Params, TargetTransformInfo &CalleeTTI,
function_ref<AssumptionCache &(Function &)> GetAssumptionCache,
function_ref<const TargetLibraryInfo &(Function &)> GetTLI,
function_ref<BlockFrequencyInfo &(Function &)> GetBFI,
ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { … }
std::optional<int> llvm::getInliningCostEstimate(
CallBase &Call, TargetTransformInfo &CalleeTTI,
function_ref<AssumptionCache &(Function &)> GetAssumptionCache,
function_ref<BlockFrequencyInfo &(Function &)> GetBFI,
ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { … }
std::optional<InlineCostFeatures> llvm::getInliningCostFeatures(
CallBase &Call, TargetTransformInfo &CalleeTTI,
function_ref<AssumptionCache &(Function &)> GetAssumptionCache,
function_ref<BlockFrequencyInfo &(Function &)> GetBFI,
ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { … }
std::optional<InlineResult> llvm::getAttributeBasedInliningDecision(
CallBase &Call, Function *Callee, TargetTransformInfo &CalleeTTI,
function_ref<const TargetLibraryInfo &(Function &)> GetTLI) { … }
InlineCost llvm::getInlineCost(
CallBase &Call, Function *Callee, const InlineParams &Params,
TargetTransformInfo &CalleeTTI,
function_ref<AssumptionCache &(Function &)> GetAssumptionCache,
function_ref<const TargetLibraryInfo &(Function &)> GetTLI,
function_ref<BlockFrequencyInfo &(Function &)> GetBFI,
ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { … }
InlineResult llvm::isInlineViable(Function &F) { … }
InlineParams llvm::getInlineParams(int Threshold) { … }
InlineParams llvm::getInlineParams() { … }
static int computeThresholdFromOptLevels(unsigned OptLevel,
unsigned SizeOptLevel) { … }
InlineParams llvm::getInlineParams(unsigned OptLevel, unsigned SizeOptLevel) { … }
PreservedAnalyses
InlineCostAnnotationPrinterPass::run(Function &F,
FunctionAnalysisManager &FAM) { … }