diff --git a/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp index 6650a680f15..b3ce42c8597 100644 --- a/lib/Analysis/InlineCost.cpp +++ b/lib/Analysis/InlineCost.cpp @@ -263,6 +263,13 @@ InlineCost InlineCostAnalyzer::getInlineCost(CallSite CS, CS.isNoInline()) return llvm::InlineCost::getNever(); + // Don't inline directly recursive calls, for now. Inlining a directly + // recursive call is effectively unrolling a loop, so it calls for different + // heuristics, which aren't implemented yet. Until then, err on the + // conservative side. + if (Callee == Caller) + return llvm::InlineCost::getNever(); + // InlineCost - This value measures how good of an inline candidate this call // site is to inline. A lower inline cost make is more likely for the call to // be inlined. This value may go negative. diff --git a/test/Transforms/Inline/tail-recursion.ll b/test/Transforms/Inline/tail-recursion.ll new file mode 100644 index 00000000000..146bed4cd07 --- /dev/null +++ b/test/Transforms/Inline/tail-recursion.ll @@ -0,0 +1,29 @@ +; RUN: opt -inline -tailcallelim -indvars -loop-deletion -S < %s | FileCheck %s + +; Inline shouldn't inline foo into itself because it's a tailcallelim +; candidate. Tailcallelim should convert the call into a loop. Indvars +; should calculate the exit value, making the loop dead. Loop deletion +; should delete the loop. +; PR6842 + +; CHECK: define i32 @bar() nounwind { +; CHECK-NEXT: ret i32 10000 +; CHECK-NEXT: } + +define internal i32 @foo(i32 %x) nounwind { + %i = add i32 %x, 1 ; [#uses=3] + %a = icmp slt i32 %i, 10000 ; [#uses=1] + br i1 %a, label %more, label %done + +done: ; preds = %0 + ret i32 %i + +more: ; preds = %0 + %z = tail call i32 @foo(i32 %i) ; [#uses=1] + ret i32 %z +} + +define i32 @bar() nounwind { + %z = call i32 @foo(i32 0) ; [#uses=1] + ret i32 %z +}