Index: include/llvm/Analysis/InlineCost.h =================================================================== --- include/llvm/Analysis/InlineCost.h +++ include/llvm/Analysis/InlineCost.h @@ -42,7 +42,6 @@ // Various magic constants used to adjust heuristics. const int InstrCost = 5; const int IndirectCallThreshold = 100; -const int CallPenalty = 25; const int LastCallToStaticBonus = 15000; const int ColdccPenalty = 2000; const int NoreturnPenalty = 10000; @@ -73,20 +72,24 @@ /// \brief The adjusted threshold against which this cost was computed. const int Threshold; + /// \brief The call penalty which was used to calculate the cost. + const int CallPenalty; + // Trivial constructor, interesting logic in the factory functions below. - InlineCost(int Cost, int Threshold) : Cost(Cost), Threshold(Threshold) {} + InlineCost(int Cost, int Threshold, int CallPenalty) + : Cost(Cost), Threshold(Threshold), CallPenalty(CallPenalty) {} public: - static InlineCost get(int Cost, int Threshold) { + static InlineCost get(int Cost, int Threshold, int CallPenalty) { assert(Cost > AlwaysInlineCost && "Cost crosses sentinel value"); assert(Cost < NeverInlineCost && "Cost crosses sentinel value"); - return InlineCost(Cost, Threshold); + return InlineCost(Cost, Threshold, CallPenalty); } static InlineCost getAlways() { - return InlineCost(AlwaysInlineCost, 0); + return InlineCost(AlwaysInlineCost, 0, INT_MAX); } static InlineCost getNever() { - return InlineCost(NeverInlineCost, 0); + return InlineCost(NeverInlineCost, 0, INT_MIN); } /// \brief Test whether the inline cost is low enough for inlining. @@ -105,6 +108,13 @@ return Cost; } + /// \brief Get the call penalty. + /// It is an error to call this on an "always" or "never" InlineCost. + int getCallPenalty() const { + assert(isVariable() && "Invalid access of InlineCost"); + return CallPenalty; + } + /// \brief Get the cost delta from the threshold for inlining. /// Only valid if the cost is of the variable kind. Returns a negative /// value if the cost is too high to inline. @@ -141,6 +151,9 @@ /// Threshold to use when the callsite is considered cold. Optional ColdCallSiteThreshold; + + /// The value of penalty to use for call penalties. + Optional CallPenalty; }; /// Generate the parameters to tune the inline cost analysis based only on the Index: lib/Analysis/InlineCost.cpp =================================================================== --- lib/Analysis/InlineCost.cpp +++ lib/Analysis/InlineCost.cpp @@ -66,6 +66,9 @@ cl::ZeroOrMore, cl::desc("Threshold for hot callsites ")); +static cl::opt CallPenalty("call-penalty", cl::Hidden, cl::init(25), + cl::desc("The penalty of a function call")); + namespace { class CallAnalyzer : public InstVisitor { @@ -97,6 +100,7 @@ int Threshold; int Cost; + int CallPenalty; bool IsCallerRecursive; bool IsRecursiveCall; @@ -166,6 +170,9 @@ /// analysis. void updateThreshold(CallSite CS, Function &Callee); + /// Update the value of CallPenalty if its value is passed via Params + void updateCallPenaltyValue(); + /// Return true if size growth is allowed when inlining the callee at CS. bool allowSizeGrowth(CallSite CS); @@ -233,6 +240,7 @@ int getThreshold() { return Threshold; } int getCost() { return Cost; } + int getCallPenalty() const { return CallPenalty; } // Keep a bunch of stats about the cost savings found so we can print them // out when debugging. @@ -939,7 +947,7 @@ // Everything other than inline ASM will also have a significant cost // merely from making the call. if (!isa(CS.getCalledValue())) - Cost += InlineConstants::CallPenalty; + Cost += CallPenalty; } return Base::visitCallSite(CS); @@ -1119,7 +1127,7 @@ if (TTI.getFPOpCost(I->getType()) == TargetTransformInfo::TCC_Expensive || hasSoftFloatAttr) - Cost += InlineConstants::CallPenalty; + Cost += CallPenalty; } // If the instruction simplified to a constant, there is no cost to this @@ -1192,6 +1200,12 @@ return cast(ConstantInt::get(IntPtrTy, Offset)); } +/// \brief Update the value of CallPenalty if its value is passed via Params +void CallAnalyzer::updateCallPenaltyValue() { + CallPenalty = (Params.CallPenalty) ? Params.CallPenalty.getValue() + : ::CallPenalty.getDefault().getValue(); +} + /// \brief Analyze a call site for potential inlining. /// /// Returns true if inlining this call is viable, and false if it is not @@ -1218,6 +1232,8 @@ // Update the threshold based on callsite properties updateThreshold(CS, F); + updateCallPenaltyValue(); + FiftyPercentVectorBonus = 3 * Threshold / 2; TenPercentVectorBonus = 3 * Threshold / 4; const DataLayout &DL = F.getParent()->getDataLayout(); @@ -1261,7 +1277,7 @@ } } // The call instruction also disappears after inlining. - Cost -= InlineConstants::InstrCost + InlineConstants::CallPenalty; + Cost -= InlineConstants::InstrCost + CallPenalty; // If there is only one call of the function, and it has internal linkage, // the cost of inlining it drops dramatically. @@ -1514,7 +1530,8 @@ if (ShouldInline && CA.getCost() >= CA.getThreshold()) return InlineCost::getAlways(); - return llvm::InlineCost::get(CA.getCost(), CA.getThreshold()); + return llvm::InlineCost::get(CA.getCost(), CA.getThreshold(), + CA.getCallPenalty()); } bool llvm::isInlineViable(Function &F) { @@ -1579,6 +1596,9 @@ // Set the ColdCallSiteThreshold knob from the -inline-cold-callsite-threshold. Params.ColdCallSiteThreshold = ColdCallSiteThreshold; + // Set the CallPenalty knob from the -call-penalty. + Params.CallPenalty = CallPenalty; + // Set the OptMinSizeThreshold and OptSizeThreshold params only if the // Set the OptMinSizeThreshold and OptSizeThreshold params only if the // -inlinehint-threshold commandline option is not explicitly given. If that Index: lib/Transforms/IPO/Inliner.cpp =================================================================== --- lib/Transforms/IPO/Inliner.cpp +++ lib/Transforms/IPO/Inliner.cpp @@ -289,7 +289,7 @@ // treating them as truly abstract units etc. TotalSecondaryCost = 0; // The candidate cost to be imposed upon the current function. - int CandidateCost = IC.getCost() - (InlineConstants::CallPenalty + 1); + int CandidateCost = IC.getCost() - (IC.getCallPenalty() + 1); // This bool tracks what happens if we do NOT inline C into B. bool callerWillBeRemoved = Caller->hasLocalLinkage(); // This bool tracks what happens if we DO inline C into B. Index: test/Transforms/Inline/call-penalty-knob.ll =================================================================== --- /dev/null +++ test/Transforms/Inline/call-penalty-knob.ll @@ -0,0 +1,29 @@ +; Check that calls are not inlined if the call penalty is low. The value of the +; call penalty is provided with the '-call-penalty' option. +; +; RUN: opt < %s -inline -call-penalty=0 -inline-threshold=5 -S | FileCheck %s +; RUN: opt < %s -inline -inline-threshold=5 -S | FileCheck %s -check-prefix=DEFAULT_CALL_PENALTY + +define i32 @X9(i32 %x) nounwind { + %x2 = add i32 %x, %x + %x3 = add i32 %x2, %x + %x4 = add i32 %x3, %x + %x5 = add i32 %x4, %x + %x6 = add i32 %x5, %x + %x7 = add i32 %x6, %x + %x8 = add i32 %x7, %x + %x9 = add i32 %x8, %x + + ret i32 %x9 +} + +define i32 @f1(i32 %x) nounwind { + %res = call i32 @X9(i32 %x) + ret i32 %res +; CHECK-LABEL: @f1( +; CHECK: %res = call i32 @X9 + +; DEFAULT_CALL_PENALTY-LABEL: @f1( +; DEFAULT_CALL_PENALTY-NOT: call +} +