diff --git a/llvm/include/llvm/Analysis/InlineAdvisor.h b/llvm/include/llvm/Analysis/InlineAdvisor.h --- a/llvm/include/llvm/Analysis/InlineAdvisor.h +++ b/llvm/include/llvm/Analysis/InlineAdvisor.h @@ -10,9 +10,10 @@ #define LLVM_ANALYSIS_INLINEADVISOR_H #include "llvm/Analysis/InlineCost.h" +#include "llvm/Analysis/LazyCallGraph.h" +#include "llvm/Analysis/Utils/ImportedFunctionsInliningStatistics.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/PassManager.h" -#include "llvm/Analysis/Utils/ImportedFunctionsInliningStatistics.h" #include #include @@ -36,11 +37,7 @@ /// requires the full C Tensorflow API library, and evaluates models /// dynamically. This mode also permits generating training logs, for offline /// training. -enum class InliningAdvisorMode : int { - Default, - Release, - Development -}; +enum class InliningAdvisorMode : int { Default, Release, Development }; class InlineAdvisor; /// Capture state between an inlining decision having had been made, and diff --git a/llvm/include/llvm/Analysis/InlineCost.h b/llvm/include/llvm/Analysis/InlineCost.h --- a/llvm/include/llvm/Analysis/InlineCost.h +++ b/llvm/include/llvm/Analysis/InlineCost.h @@ -15,6 +15,7 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/InlineModelFeatureMaps.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include #include @@ -270,6 +271,15 @@ ProfileSummaryInfo *PSI = nullptr, OptimizationRemarkEmitter *ORE = nullptr); +/// Get the expanded cost features. The features are returned unconditionally, +/// even if inlining is impossible. +InlineCostFeaturesArray getInliningCostFeatures( + CallBase &Call, TargetTransformInfo &CalleeTTI, + function_ref GetAssumptionCache, + function_ref GetBFI = nullptr, + ProfileSummaryInfo *PSI = nullptr, + OptimizationRemarkEmitter *ORE = nullptr); + /// Minimal filter to detect invalid constructs for inlining. InlineResult isInlineViable(Function &Callee); diff --git a/llvm/include/llvm/Analysis/InlineModelFeatureMaps.h b/llvm/include/llvm/Analysis/InlineModelFeatureMaps.h --- a/llvm/include/llvm/Analysis/InlineModelFeatureMaps.h +++ b/llvm/include/llvm/Analysis/InlineModelFeatureMaps.h @@ -16,6 +16,60 @@ namespace llvm { +// List of cost features. A "cost" feature is a summand of the heuristic-based +// inline cost, and we define them separately to preserve the original heuristic +// behavior. +#define INLINE_COST_FEATURE_ITERATOR(M) \ + M(SROASavings, "sroa_savings") \ + M(SROALosses, "sroa_losses") \ + M(LoadElimination, "load_elimination") \ + M(CallPenalty, "call_penalty") \ + M(CallArgumentSetup, "call_argument_setup") \ + M(LoadRelativeIntrinsic, "load_relative_intrinsic") \ + M(LoweredCallArgSetup, "lowered_call_arg_setup") \ + M(IndirectCallPenalty, "indirect_call_penalty") \ + M(JumpTablePenalty, "jump_table_penalty") \ + M(CaseClusterPenalty, "case_cluster_penalty") \ + M(SwitchPenalty, "switch_penalty") \ + M(UnsimplifiedCommonInstructions, "unsimplified_common_instructions") \ + M(NumLoops, "num_loops") \ + M(DeadBlocks, "dead_blocks") \ + M(SimplifiedInstructions, "simplified_instructions") \ + M(ConstantArgs, "constant_args") \ + M(ConstantOffsetPtrArgs, "constant_offset_ptr_args") \ + M(CallSiteCost, "callsite_cost") \ + M(ColdCcPenalty, "cold_cc_penalty") \ + M(LastCallToStaticBonus, "last_call_to_static_bonus") \ + M(IsMultipleBlocks, "is_multiple_blocks") \ + M(NestedInlines, "nested_inlines") \ + M(NestedInlineBonus, "nested_inline_bonus") \ + M(Threshold, "threshold") + +// clang-format off +enum class InlineCostFeatures : size_t { +#define POPULATE_INDICES(INDEX_NAME, NAME) INDEX_NAME, + INLINE_COST_FEATURE_ITERATOR(POPULATE_INDICES) +#undef POPULATE_INDICES + + NumberOfFeatures +}; +// clang-format on + +using InlineCostFeaturesArray = + std::array(InlineCostFeatures::NumberOfFeatures)>; + +constexpr bool isHeuristicInlineCostFeature(InlineCostFeatures Feature) { + return Feature != InlineCostFeatures::SROASavings && + Feature != InlineCostFeatures::IsMultipleBlocks && + Feature != InlineCostFeatures::DeadBlocks && + Feature != InlineCostFeatures::SimplifiedInstructions && + Feature != InlineCostFeatures::ConstantArgs && + Feature != InlineCostFeatures::ConstantOffsetPtrArgs && + Feature != InlineCostFeatures::NestedInlines && + Feature != InlineCostFeatures::NestedInlineBonus && + Feature != InlineCostFeatures::Threshold; +} + // List of features. Each feature is defined through a triple: // - the name of an enum member, which will be the feature index // - a textual name, used for Tensorflow model binding (so it needs to match the @@ -33,7 +87,6 @@ "total current number of defined functions in the module") \ M(NrCtantParams, "nr_ctant_params", \ "number of parameters in the call site that are constants") \ - M(CostEstimate, "cost_estimate", "total cost estimate (threshold - free)") \ M(EdgeCount, "edge_count", "total number of calls in the module") \ M(CallerUsers, "caller_users", \ "number of module-internal users of the caller, +1 if the caller is " \ @@ -46,14 +99,29 @@ "number of blocks reached from a conditional instruction, in the callee") \ M(CalleeUsers, "callee_users", \ "number of module-internal users of the callee, +1 if the callee is " \ - "exposed externally") + "exposed externally") \ + M(CostEstimate, "cost_estimate", "total cost estimate (threshold - free)") +// clang-format off enum class FeatureIndex : size_t { +// InlineCost features - these must come first +#define POPULATE_INDICES(INDEX_NAME, NAME) INDEX_NAME, + INLINE_COST_FEATURE_ITERATOR(POPULATE_INDICES) +#undef POPULATE_INDICES + +// Non-cost features #define POPULATE_INDICES(INDEX_NAME, NAME, COMMENT) INDEX_NAME, INLINE_FEATURE_ITERATOR(POPULATE_INDICES) #undef POPULATE_INDICES - NumberOfFeatures + + NumberOfFeatures }; +// clang-format on + +constexpr FeatureIndex +inlineCostFeatureToMlFeature(InlineCostFeatures Feature) { + return static_cast(static_cast(Feature)); +} constexpr size_t NumberOfFeatures = static_cast(FeatureIndex::NumberOfFeatures); diff --git a/llvm/lib/Analysis/CMakeLists.txt b/llvm/lib/Analysis/CMakeLists.txt --- a/llvm/lib/Analysis/CMakeLists.txt +++ b/llvm/lib/Analysis/CMakeLists.txt @@ -5,7 +5,7 @@ # This url points to the most recent most which is known to be compatible with # LLVM. When better models are published, this url should be updated to aid # discoverability. - set(LLVM_INLINER_MODEL_CURRENT_URL "https://github.com/google/ml-compiler-opt/releases/download/inlining-Oz-v0.1/inlining-Oz-acabaf6-v0.1.tar.gz") + set(LLVM_INLINER_MODEL_CURRENT_URL "asedf") if (DEFINED LLVM_HAVE_TF_AOT) # If the path is empty, autogenerate the model diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -129,6 +129,7 @@ cl::desc("Disables evaluation of GetElementPtr with constant operands")); namespace { + class InlineCostCallAnalyzer; // This struct is used to store information about inline cost of a @@ -410,19 +411,18 @@ bool visitUnreachableInst(UnreachableInst &I); public: - CallAnalyzer( - Function &Callee, CallBase &Call, const TargetTransformInfo &TTI, - function_ref GetAssumptionCache, - function_ref GetBFI = nullptr, - ProfileSummaryInfo *PSI = nullptr, - OptimizationRemarkEmitter *ORE = nullptr) + CallAnalyzer(Function &Callee, CallBase &Call, const TargetTransformInfo &TTI, + function_ref GetAssumptionCache, + function_ref GetBFI = nullptr, + ProfileSummaryInfo *PSI = nullptr, + OptimizationRemarkEmitter *ORE = nullptr) : TTI(TTI), GetAssumptionCache(GetAssumptionCache), GetBFI(GetBFI), PSI(PSI), F(Callee), DL(F.getParent()->getDataLayout()), ORE(ORE), CandidateCall(Call), EnableLoadElimination(true) {} InlineResult analyze(); - Optional getSimplifiedValue(Instruction *I) { + Optional getSimplifiedValue(Instruction *I) { if (SimplifiedValues.find(I) != SimplifiedValues.end()) return SimplifiedValues[I]; return None; @@ -439,7 +439,6 @@ void dump(); }; - /// FIXME: if it is necessary to derive from InlineCostCallAnalyzer, note /// the FIXME in onLoweredCall, when instantiating an InlineCostCallAnalyzer class InlineCostCallAnalyzer final : public CallAnalyzer { @@ -937,6 +936,210 @@ int getCost() { return Cost; } bool wasDecidedByCostBenefit() { return DecidedByCostBenefit; } }; + +class InlineCostFeaturesAnalyzer final : public CallAnalyzer { +private: + InlineCostFeaturesArray Cost = {}; + int LoadEliminationCost = 0; + unsigned SROACostSavings = 0; + int VectorBonus = 0; + int SingleBBBonus = 0; + int Threshold = 5; + + DenseMap SROACosts; + + void update(InlineCostFeatures Feature, int64_t Delta) { + Cost[static_cast(Feature)] += Delta; + } + + void set(InlineCostFeatures Feature, int64_t Value) { + Cost[static_cast(Feature)] = Value; + } + + void onDisableSROA(AllocaInst *Arg) override { + auto CostIt = SROACosts.find(Arg); + if (CostIt == SROACosts.end()) + return; + + update(InlineCostFeatures::SROALosses, CostIt->second); + SROACostSavings -= CostIt->second; + SROACosts.erase(CostIt); + } + + void onDisableLoadElimination() override { + update(InlineCostFeatures::LoadElimination, LoadEliminationCost); + LoadEliminationCost = 0; + } + + void onCallPenalty() override { + update(InlineCostFeatures::CallPenalty, InlineConstants::CallPenalty); + } + + void onCallArgumentSetup(const CallBase &Call) override { + update(InlineCostFeatures::CallArgumentSetup, + Call.arg_size() * InlineConstants::InstrCost); + } + + void onLoadRelativeIntrinsic() override { + update(InlineCostFeatures::LoadRelativeIntrinsic, + 3 * InlineConstants::InstrCost); + } + + void onLoweredCall(Function *F, CallBase &Call, + bool IsIndirectCall) override { + update(InlineCostFeatures::LoweredCallArgSetup, + Call.arg_size() * InlineConstants::InstrCost); + + if (IsIndirectCall) { + InlineParams IndirectCallParams = {/* DefaultThreshold*/ 0, + /*HintThreshold*/ {}, + /*ColdThreshold*/ {}, + /*OptSizeThreshold*/ {}, + /*OptMinSizeThreshold*/ {}, + /*HotCallSiteThreshold*/ {}, + /*LocallyHotCallSiteThreshold*/ {}, + /*ColdCallSiteThreshold*/ {}, + /*ComputeFullInlineCost*/ true, + /*EnableDeferral*/ true}; + IndirectCallParams.DefaultThreshold = + InlineConstants::IndirectCallThreshold; + + InlineCostCallAnalyzer CA(*F, Call, IndirectCallParams, TTI, + GetAssumptionCache, GetBFI, PSI, ORE, false, + true); + if (CA.analyze().isSuccess()) { + update(InlineCostFeatures::NestedInlineBonus, CA.getCost()); + update(InlineCostFeatures::NestedInlines, 1); + } + } else { + onCallPenalty(); + } + } + + void accumulateBonus(const InlineCostFeaturesArray &OtherCost) { + size_t NestedInlineIdx = + static_cast(InlineCostFeatures::NestedInlines); + set(InlineCostFeatures::NestedInlines, + std::max(Cost[NestedInlineIdx], OtherCost[NestedInlineIdx] + 1)); + + int64_t Bonus = 0; + for (int I = 0; I < static_cast(InlineCostFeatures::NumberOfFeatures); + ++I) { + if (isHeuristicInlineCostFeature(static_cast(I)) || + static_cast(I) == + InlineCostFeatures::NestedInlineBonus) { + Bonus += Cost[I]; + } + } + update(InlineCostFeatures::NestedInlineBonus, Bonus); + } + + void onFinalizeSwitch(unsigned JumpTableSize, + unsigned NumCaseCluster) override { + + if (JumpTableSize) { + int64_t JTCost = (int64_t)JumpTableSize * InlineConstants::InstrCost + + 4 * InlineConstants::InstrCost; + update(InlineCostFeatures::JumpTablePenalty, JTCost); + return; + } + + if (NumCaseCluster <= 3) { + update(InlineCostFeatures::CaseClusterPenalty, + NumCaseCluster * 2 * InlineConstants::InstrCost); + return; + } + + int64_t ExpectedNumberOfCompare = 3 * (int64_t)NumCaseCluster / 2 - 1; + int64_t SwitchCost = + ExpectedNumberOfCompare * 2 * InlineConstants::InstrCost; + update(InlineCostFeatures::SwitchPenalty, SwitchCost); + } + + void onMissedSimplification() override { + update(InlineCostFeatures::UnsimplifiedCommonInstructions, + InlineConstants::InstrCost); + } + + void onInitializeSROAArg(AllocaInst *Arg) override { SROACosts[Arg] = 0; } + void onAggregateSROAUse(AllocaInst *Arg) override { + SROACosts.find(Arg)->second += InlineConstants::InstrCost; + SROACostSavings += InlineConstants::InstrCost; + } + + void onBlockAnalyzed(const BasicBlock *BB) override { + if (BB->getTerminator()->getNumSuccessors() > 1) + set(InlineCostFeatures::IsMultipleBlocks, 1); + Threshold -= SingleBBBonus; + } + + InlineResult finalizeAnalysis() override { + auto *Caller = CandidateCall.getFunction(); + if (Caller->hasMinSize()) { + DominatorTree DT(F); + LoopInfo LI(DT); + for (Loop *L : LI) { + // Ignore loops that will not be executed + if (DeadBlocks.count(L->getHeader())) + continue; + update(InlineCostFeatures::NumLoops, InlineConstants::CallPenalty); + } + } + set(InlineCostFeatures::DeadBlocks, DeadBlocks.size()); + set(InlineCostFeatures::SimplifiedInstructions, NumInstructionsSimplified); + set(InlineCostFeatures::ConstantArgs, NumConstantArgs); + set(InlineCostFeatures::ConstantOffsetPtrArgs, NumConstantOffsetPtrArgs); + set(InlineCostFeatures::SROASavings, SROACostSavings); + + if (NumVectorInstructions <= NumInstructions / 10) + update(InlineCostFeatures::Threshold, -1 * VectorBonus); + else if (NumVectorInstructions <= NumInstructions / 2) + update(InlineCostFeatures::Threshold, -1 * (VectorBonus / 2)); + + set(InlineCostFeatures::Threshold, Threshold); + + return InlineResult::success(); + } + + bool shouldStop() override { return false; } + + void onLoadEliminationOpportunity() override { + update(InlineCostFeatures::LoadElimination, 1); + } + + InlineResult onAnalysisStart() override { + update(InlineCostFeatures::CallSiteCost, + -1 * getCallsiteCost(this->CandidateCall, DL)); + + set(InlineCostFeatures::ColdCcPenalty, + (F.getCallingConv() == CallingConv::Cold)); + + // FIXME: we shouldn't repeat this logic in both the Features and Cost + // analyzer - instead, we should abstract it to a common method in the + // CallAnalyzer + int SingleBBBonusPercent = 50; + int VectorBonusPercent = TTI.getInlinerVectorBonusPercent(); + Threshold += TTI.adjustInliningThreshold(&CandidateCall); + Threshold *= TTI.getInliningThresholdMultiplier(); + SingleBBBonus = Threshold * SingleBBBonusPercent / 100; + VectorBonus = Threshold * VectorBonusPercent / 100; + Threshold += (SingleBBBonus + VectorBonus); + + return InlineResult::success(); + } + +public: + InlineCostFeaturesAnalyzer( + const TargetTransformInfo &TTI, + function_ref &GetAssumptionCache, + function_ref GetBFI, + ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE, Function &Callee, + CallBase &Call) + : CallAnalyzer(Callee, Call, TTI, GetAssumptionCache, GetBFI, PSI) {} + + const InlineCostFeaturesArray &features() const { return Cost; } +}; + } // namespace /// Test whether the given value is an Alloca-derived function argument. @@ -950,8 +1153,8 @@ disableLoadElimination(); } -void InlineCostAnnotationWriter::emitInstructionAnnot(const Instruction *I, - formatted_raw_ostream &OS) { +void InlineCostAnnotationWriter::emitInstructionAnnot( + const Instruction *I, formatted_raw_ostream &OS) { // The cost of inlining of the given instruction is printed always. // The threshold delta is printed only when it is non-zero. It happens // when we decided to give a bonus at a particular instruction. @@ -1056,8 +1259,8 @@ // is needed to track stack usage during inlining. Type *Ty = I.getAllocatedType(); AllocatedSize = SaturatingMultiplyAdd( - AllocSize->getLimitedValue(), DL.getTypeAllocSize(Ty).getKnownMinSize(), - AllocatedSize); + AllocSize->getLimitedValue(), + DL.getTypeAllocSize(Ty).getKnownMinSize(), AllocatedSize); if (AllocatedSize > InlineConstants::MaxSimplifiedDynamicAllocaToInline) HasDynamicAlloca = true; return false; @@ -1210,11 +1413,11 @@ if (!DisableGEPConstOperand) if (simplifyInstruction(I, [&](SmallVectorImpl &COps) { - SmallVector Indices; - for (unsigned int Index = 1 ; Index < COps.size() ; ++Index) + SmallVector Indices; + for (unsigned int Index = 1; Index < COps.size(); ++Index) Indices.push_back(COps[Index]); - return ConstantExpr::getGetElementPtr(I.getSourceElementType(), COps[0], - Indices, I.isInBounds()); + return ConstantExpr::getGetElementPtr( + I.getSourceElementType(), COps[0], Indices, I.isInBounds()); })) return true; @@ -1949,9 +2152,9 @@ } // Select condition is a constant. - Value *SelectedV = CondC->isAllOnesValue() - ? TrueVal - : (CondC->isNullValue()) ? FalseVal : nullptr; + Value *SelectedV = CondC->isAllOnesValue() ? TrueVal + : (CondC->isNullValue()) ? FalseVal + : nullptr; if (!SelectedV) { // Condition is a vector constant that is not all 1s or all 0s. If all // operands are constants, ConstantExpr::getSelect() can handle the cases @@ -2416,9 +2619,7 @@ #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) /// Dump stats about this call's analysis. -LLVM_DUMP_METHOD void InlineCostCallAnalyzer::dump() { - print(); -} +LLVM_DUMP_METHOD void InlineCostCallAnalyzer::dump() { print(); } #endif /// Test that there are no attribute conflicts between Caller and Callee @@ -2505,6 +2706,20 @@ return CA.getCost(); } +InlineCostFeaturesArray llvm::getInliningCostFeatures( + CallBase &Call, TargetTransformInfo &CalleeTTI, + function_ref GetAssumptionCache, + function_ref GetBFI, + ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { + InlineCostFeaturesAnalyzer CFA(CalleeTTI, GetAssumptionCache, GetBFI, PSI, + ORE, *Call.getCalledFunction(), Call); + auto R = CFA.analyze(); + (void)R; // Explicitly ignore the result. In any case where we are computing + // the features, we will also be computing the cost estimate, and we + // can check for inlining success at that point. + return CFA.features(); +} + Optional llvm::getAttributeBasedInliningDecision( CallBase &Call, Function *Callee, TargetTransformInfo &CalleeTTI, function_ref GetTLI) { @@ -2772,8 +2987,8 @@ InlineCostAnnotationPrinterPass::run(Function &F, FunctionAnalysisManager &FAM) { PrintInstructionComments = true; - std::function GetAssumptionCache = [&]( - Function &F) -> AssumptionCache & { + std::function GetAssumptionCache = + [&](Function &F) -> AssumptionCache & { return FAM.getResult(F); }; Module *M = F.getParent(); diff --git a/llvm/lib/Analysis/MLInlineAdvisor.cpp b/llvm/lib/Analysis/MLInlineAdvisor.cpp --- a/llvm/lib/Analysis/MLInlineAdvisor.cpp +++ b/llvm/lib/Analysis/MLInlineAdvisor.cpp @@ -43,11 +43,19 @@ "blocking any further inlining."), cl::init(2.0)); +// clang-format off const std::array llvm::FeatureNameMap{ +// InlineCost features - these must come first +#define POPULATE_NAMES(INDEX_NAME, NAME) NAME, + INLINE_COST_FEATURE_ITERATOR(POPULATE_NAMES) +#undef POPULATE_NAMES + +// Non-cost features #define POPULATE_NAMES(INDEX_NAME, NAME, COMMENT) NAME, - INLINE_FEATURE_ITERATOR(POPULATE_NAMES) + INLINE_FEATURE_ITERATOR(POPULATE_NAMES) #undef POPULATE_NAMES }; +// clang-format on const char *const llvm::DecisionName = "inlining_decision"; const char *const llvm::DefaultDecisionName = "inlining_default"; @@ -217,6 +225,9 @@ CostEstimate = *IsCallSiteInlinable; } + const auto CostFeatures = + llvm::getInliningCostFeatures(CB, TIR, GetAssumptionCache); + if (Mandatory) return getMandatoryAdvice(CB, true); @@ -234,7 +245,6 @@ FunctionLevels[&Caller]); ModelRunner->setFeature(FeatureIndex::NodeCount, NodeCount); ModelRunner->setFeature(FeatureIndex::NrCtantParams, NrCtantParams); - ModelRunner->setFeature(FeatureIndex::CostEstimate, CostEstimate); ModelRunner->setFeature(FeatureIndex::EdgeCount, EdgeCount); ModelRunner->setFeature(FeatureIndex::CallerUsers, CallerBefore.Uses); ModelRunner->setFeature(FeatureIndex::CallerConditionallyExecutedBlocks, @@ -244,6 +254,16 @@ ModelRunner->setFeature(FeatureIndex::CalleeConditionallyExecutedBlocks, CalleeBefore.BlocksReachedFromConditionalInstruction); ModelRunner->setFeature(FeatureIndex::CalleeUsers, CalleeBefore.Uses); + ModelRunner->setFeature(FeatureIndex::CostEstimate, CostEstimate); + + // Add the cost features + for (size_t I = 0; + I < static_cast(InlineCostFeatures::NumberOfFeatures); ++I) { + ModelRunner->setFeature( + inlineCostFeatureToMlFeature(static_cast(I)), + CostFeatures[I]); + } + return getAdviceFromModel(CB, ORE); } diff --git a/llvm/lib/Analysis/models/inlining/config.py b/llvm/lib/Analysis/models/inlining/config.py --- a/llvm/lib/Analysis/models/inlining/config.py +++ b/llvm/lib/Analysis/models/inlining/config.py @@ -26,11 +26,42 @@ # int64 features inputs = [ tf.TensorSpec(dtype=tf.int64, shape=(), name=key) for key in [ - 'caller_basic_block_count', 'caller_conditionally_executed_blocks', - 'caller_users', 'callee_basic_block_count', - 'callee_conditionally_executed_blocks', 'callee_users', - 'nr_ctant_params', 'node_count', 'edge_count', 'callsite_height', - 'cost_estimate', 'inlining_default' + 'caller_basic_block_count', + 'caller_conditionally_executed_blocks', + 'caller_users', + 'callee_basic_block_count', + 'callee_conditionally_executed_blocks', + 'callee_users', + 'nr_ctant_params', + 'node_count', + 'edge_count', + 'callsite_height', + 'cost_estimate', + 'inlining_default', + 'sroa_savings', + 'sroa_losses', + 'load_elimination', + 'call_penalty', + 'call_argument_setup', + 'load_relative_intrinsic', + 'lowered_call_arg_setup', + 'indirect_call_penalty', + 'jump_table_penalty', + 'case_cluster_penalty', + 'switch_penalty', + 'unsimplified_common_instructions', + 'num_loops', + 'dead_blocks', + 'simplified_instructions', + 'constant_args', + 'constant_offset_ptr_args', + 'callsite_cost', + 'cold_cc_penalty', + 'last_call_to_static_bonus', + 'is_multiple_blocks', + 'nested_inlines', + 'nested_inline_bonus', + 'threshold', ] ]