Index: include/llvm/Analysis/InlineCost.h =================================================================== --- include/llvm/Analysis/InlineCost.h +++ include/llvm/Analysis/InlineCost.h @@ -131,6 +131,9 @@ /// The default threshold to start with for a callee. int DefaultThreshold; + /// The maximum depth of recursion for analyzing a call. + Optional RecursionLimit; + /// Threshold to use for callees with inline hint. Optional HintThreshold; Index: lib/Analysis/InlineCost.cpp =================================================================== --- lib/Analysis/InlineCost.cpp +++ lib/Analysis/InlineCost.cpp @@ -89,6 +89,10 @@ cl::desc("Compute the full inline cost of a call site even when the cost " "exceeds the threshold.")); +static cl::opt InlineRecursionLimit( + "inline-recursion-limit", cl::Hidden, cl::init(2000), cl::ZeroOrMore, + cl::desc("Recursion limit for analyzing calls (default = 3000)")); + namespace { class CallAnalyzer : public InstVisitor { @@ -124,6 +128,12 @@ /// Tunable parameters that control the analysis. const InlineParams &Params; + /// The depth of recursion that this CallAnalyzer sits at. + int CallsAnalyzedRecursionDepth = 0; + + /// True if this CallAnalyzer hit its maximum recursion depth. + bool HitMaxNumAnalyzeCalls = false; + int Threshold; int Cost; bool ComputeFullInlineCost; @@ -271,12 +281,14 @@ std::function &GetAssumptionCache, Optional> &GetBFI, ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE, - Function &Callee, CallSite CSArg, const InlineParams &Params) + Function &Callee, CallSite CSArg, const InlineParams &Params, + const unsigned &Depth) : TTI(TTI), GetAssumptionCache(GetAssumptionCache), GetBFI(GetBFI), PSI(PSI), F(Callee), DL(F.getParent()->getDataLayout()), ORE(ORE), - CandidateCS(CSArg), Params(Params), Threshold(Params.DefaultThreshold), - Cost(0), ComputeFullInlineCost(OptComputeFullInlineCost || - Params.ComputeFullInlineCost || ORE), + CandidateCS(CSArg), Params(Params), CallsAnalyzedRecursionDepth(Depth), + Threshold(Params.DefaultThreshold), Cost(0), + ComputeFullInlineCost(OptComputeFullInlineCost || + Params.ComputeFullInlineCost || ORE), IsCallerRecursive(false), IsRecursiveCall(false), ExposesReturnsTwice(false), HasDynamicAlloca(false), ContainsNoDuplicateCall(false), HasReturn(false), HasIndirectBr(false), @@ -1191,6 +1203,10 @@ } bool CallAnalyzer::visitCallSite(CallSite CS) { + // If we've recursed too deep, then quit. + if (HitMaxNumAnalyzeCalls) + return false; + if (CS.hasFnAttr(Attribute::ReturnsTwice) && !F.hasFnAttribute(Attribute::ReturnsTwice)) { // This aborts the entire analysis. @@ -1279,13 +1295,20 @@ auto IndirectCallParams = Params; IndirectCallParams.DefaultThreshold = InlineConstants::IndirectCallThreshold; CallAnalyzer CA(TTI, GetAssumptionCache, GetBFI, PSI, ORE, *F, CS, - IndirectCallParams); + IndirectCallParams, CallsAnalyzedRecursionDepth); + + // Analyze CS and update the depth of recursion. if (CA.analyzeCall(CS)) { // We were able to inline the indirect call! Subtract the cost from the // threshold to get the bonus we want to apply, but don't go below zero. Cost -= std::max(0, CA.getThreshold() - CA.getCost()); } + // If we hit the maximum recursion when calling analyzeCall, update this + // CallAnalyzer's max recursion flag. + if (CA.HitMaxNumAnalyzeCalls) + HitMaxNumAnalyzeCalls = true; + if (!F->onlyReadsMemory()) disableLoadElimination(); return Base::visitCallSite(CS); @@ -1682,6 +1705,14 @@ /// is below the computed threshold, then inlining was forcibly disabled by /// some artifact of the routine. bool CallAnalyzer::analyzeCall(CallSite CS) { + ++CallsAnalyzedRecursionDepth; + + // Update the depth of recursion. If we've gone too deep, bail out. + if (CallsAnalyzedRecursionDepth >= Params.RecursionLimit) { + HitMaxNumAnalyzeCalls = true; + return false; + } + ++NumCallsAnalyzed; // Perform some tweaks to the cost and threshold based on the direct @@ -1883,6 +1914,7 @@ DEBUG_PRINT_STAT(ContainsNoDuplicateCall); DEBUG_PRINT_STAT(Cost); DEBUG_PRINT_STAT(Threshold); + DEBUG_PRINT_STAT(HitMaxNumAnalyzeCalls); #undef DEBUG_PRINT_STAT } #endif @@ -1978,7 +2010,7 @@ << "... (caller:" << Caller->getName() << ")\n"); CallAnalyzer CA(CalleeTTI, GetAssumptionCache, GetBFI, PSI, ORE, *Callee, CS, - Params); + Params, 0); bool ShouldInline = CA.analyzeCall(CS); DEBUG(CA.dump()); @@ -2051,6 +2083,9 @@ // Set the HotCallSiteThreshold knob from the -hot-callsite-threshold. Params.HotCallSiteThreshold = HotCallSiteThreshold; + // Set the inlining recursion limit using -inline-recursion-limit. + Params.RecursionLimit = InlineRecursionLimit; + // If the -locally-hot-callsite-threshold is explicitly specified, use it to // populate LocallyHotCallSiteThreshold. Later, we populate // Params.LocallyHotCallSiteThreshold from -locally-hot-callsite-threshold if Index: test/Transforms/Inline/inline-functionptr.ll =================================================================== --- /dev/null +++ test/Transforms/Inline/inline-functionptr.ll @@ -0,0 +1,29 @@ +; RUN: opt -passes='cgscc(inline)' -S %s | FileCheck %s + +;; The inliner should quit when trying to inline the call to Bar into Bar. +define void @Bar(i8* nocapture %FunctionPtr) #0 { +; CHECK-LABEL: Bar +; CHECK: %0 = bitcast i8* %FunctionPtr to void (i8*)* +; CHECK-NEXT: call void %0(i8* bitcast (void (i8*)* @Bar to i8*)) #0 +; CHECK-NEXT: call void %0(i8* bitcast (void (i8*)* @Bar to i8*)) #0 +; CHECK-NEXT: ret void +entry: + %0 = bitcast i8* %FunctionPtr to void (i8*)* + call void %0(i8* bitcast (void (i8*)* @Bar to i8*)) #0 + call void %0(i8* bitcast (void (i8*)* @Bar to i8*)) #0 + ret void +} + +;; The inliner should be able to inline Bar into main +define i32 @main(i32 %argc, i8** nocapture readnone %argv) +local_unnamed_addr #0 { +; CHECK-LABEL: main +; CHECK: call void @Bar(i8* bitcast (void (i8*)* @Bar to i8*)) #0 +; CHECK-NEXT: call void @Bar(i8* bitcast (void (i8*)* @Bar to i8*)) #0 +; CHECK-NEXT: ret i32 0 +entry: + tail call void @Bar(i8* bitcast (void (i8*)* @Bar to i8*)) #0 + ret i32 0 +} + +attributes #0 = { nounwind ssp uwtable }