diff --git a/lib/Transforms/IPO/Inliner.cpp b/lib/Transforms/IPO/Inliner.cpp index af26681df46..64a085c70b6 100644 --- a/lib/Transforms/IPO/Inliner.cpp +++ b/lib/Transforms/IPO/Inliner.cpp @@ -788,7 +788,13 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, // We also use a secondary worklist of call sites within a particular node to // allow quickly continuing to inline through newly inlined call sites where // possible. - SmallVector Calls; + SmallVector, 16> Calls; + + // When inlining a callee produces new call sites, we want to keep track of + // the fact that they were inlined from the callee. This allows us to avoid + // infinite inlining in some obscure cases. To represent this, we use an + // index into the InlineHistory vector. + SmallVector, 16> InlineHistory; // Track a set vector of inlined callees so that we can augment the caller // with all of their edges in the call graph before pruning out the ones that @@ -820,13 +826,19 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, if (auto CS = CallSite(&I)) if (Function *Callee = CS.getCalledFunction()) if (!Callee->isDeclaration()) - Calls.push_back(CS); + Calls.push_back({CS, -1}); bool DidInline = false; while (!Calls.empty()) { - CallSite CS = Calls.pop_back_val(); + int InlineHistoryID; + CallSite CS; + std::tie(CS, InlineHistoryID) = Calls.pop_back_val(); Function &Callee = *CS.getCalledFunction(); + if (InlineHistoryID != -1 && + InlineHistoryIncludes(&Callee, InlineHistoryID, InlineHistory)) + continue; + // Check whether we want to inline this callsite. if (!shouldInline(CS, GetInlineCost, ORE)) continue; @@ -837,10 +849,14 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, InlinedCallees.insert(&Callee); // Add any new callsites to defined functions to the worklist. - for (CallSite &CS : reverse(IFI.InlinedCallSites)) - if (Function *NewCallee = CS.getCalledFunction()) - if (!NewCallee->isDeclaration()) - Calls.push_back(CS); + if (!IFI.InlinedCallSites.empty()) { + int NewHistoryID = InlineHistory.size(); + InlineHistory.push_back({&Callee, InlineHistoryID}); + for (CallSite &CS : reverse(IFI.InlinedCallSites)) + if (Function *NewCallee = CS.getCalledFunction()) + if (!NewCallee->isDeclaration()) + Calls.push_back({CS, NewHistoryID}); + } // Merge the attributes based on the inlining. AttributeFuncs::mergeAttributesForInlining(F, Callee); diff --git a/test/Transforms/Inline/noinline-recursive-fn.ll b/test/Transforms/Inline/noinline-recursive-fn.ll index 2e581a7dbc4..2b1851bd46b 100644 --- a/test/Transforms/Inline/noinline-recursive-fn.ll +++ b/test/Transforms/Inline/noinline-recursive-fn.ll @@ -3,6 +3,7 @@ ; inliner heuristics are not set up for this. ; RUN: opt -inline -S < %s | FileCheck %s +; RUN: opt -passes='cgscc(inline)' -S < %s | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" target triple = "x86_64-apple-darwin10.3"