From daf21289b6de229e22a853a0a140682e039d3b8e Mon Sep 17 00:00:00 2001 From: Sanjoy Das Date: Mon, 7 Nov 2016 21:01:49 +0000 Subject: [PATCH] Avoid tail recursion elimination across calls with operand bundles Summary: In some specific scenarios with well understood operand bundle types (like `"deopt"`) it may be possible to go ahead and convert recursion to iteration, but TailRecursionElimination does not have that logic today so avoid doing the right thing for now. I need some input on whether `"funclet"` operand bundles should also block tail recursion elimination. If not, I'll allow TRE across calls with `"funclet"` operand bundles and add a test case. Reviewers: rnk, majnemer, nlewycky, ahatanak Subscribers: mcrosier, llvm-commits Differential Revision: https://reviews.llvm.org/D26270 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@286147 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Scalar/TailRecursionElimination.cpp | 3 +- test/Transforms/TailCallElim/deopt-bundle.ll | 57 +++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 test/Transforms/TailCallElim/deopt-bundle.ll diff --git a/lib/Transforms/Scalar/TailRecursionElimination.cpp b/lib/Transforms/Scalar/TailRecursionElimination.cpp index 16c88270a84..2c0294ccc38 100644 --- a/lib/Transforms/Scalar/TailRecursionElimination.cpp +++ b/lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -236,7 +236,7 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls) { if (!CI || CI->isTailCall()) continue; - bool IsNoTail = CI->isNoTailCall(); + bool IsNoTail = CI->isNoTailCall() || CI->hasOperandBundles(); if (!IsNoTail && CI->doesNotAccessMemory()) { // A call to a readnone function whose arguments are all things computed @@ -256,6 +256,7 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls) { SafeToTail = false; break; } + SafeToTail &= CI->hasOperandBundles(); if (SafeToTail) { emitOptimizationRemark( F.getContext(), "tailcallelim", F, CI->getDebugLoc(), diff --git a/test/Transforms/TailCallElim/deopt-bundle.ll b/test/Transforms/TailCallElim/deopt-bundle.ll new file mode 100644 index 00000000000..a98c47e9e6f --- /dev/null +++ b/test/Transforms/TailCallElim/deopt-bundle.ll @@ -0,0 +1,57 @@ +; RUN: opt < %s -tailcallelim -S | FileCheck %s + +define i32 @f_1(i32 %x) { +; CHECK-LABEL: @f_1( +wentry: + %cond = icmp ugt i32 %x, 0 + br i1 %cond, label %return, label %body + +body: +; CHECK: body: +; CHECK: call i32 @f_1(i32 %y) [ "deopt"() ] + %y = add i32 %x, 1 + %tmp = call i32 @f_1(i32 %y) [ "deopt"() ] + ret i32 0 + +return: + ret i32 1 +} + +define i32 @f_2(i32 %x) { +; CHECK-LABEL: @f_2 + +entry: + %cond = icmp ugt i32 %x, 0 + br i1 %cond, label %return, label %body + +body: +; CHECK: body: +; CHECK: call i32 @f_2(i32 %y) [ "unknown"() ] + %y = add i32 %x, 1 + %tmp = call i32 @f_2(i32 %y) [ "unknown"() ] + ret i32 0 + +return: + ret i32 1 +} + +declare void @func() + +define void @f_3(i1 %B) personality i8 42 { +; CHECK-LABEL: @f_3( +entry: + invoke void @func() + to label %exit unwind label %merge +merge: + %cs1 = catchswitch within none [label %catch] unwind to caller + +catch: +; CHECK: catch: +; CHECK: call void @f_3(i1 %B) [ "funclet"(token %cp) ] + %cp = catchpad within %cs1 [] + call void @f_3(i1 %B) [ "funclet"(token %cp) ] + ret void + +exit: + ret void +} -- 2.40.0