Skip to content

Commit e06ef14

Browse files
committedNov 7, 2016
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 llvm-svn: 286147
1 parent 2b5ba7b commit e06ef14

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed
 

‎llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls) {
236236
if (!CI || CI->isTailCall())
237237
continue;
238238

239-
bool IsNoTail = CI->isNoTailCall();
239+
bool IsNoTail = CI->isNoTailCall() || CI->hasOperandBundles();
240240

241241
if (!IsNoTail && CI->doesNotAccessMemory()) {
242242
// A call to a readnone function whose arguments are all things computed
@@ -256,6 +256,7 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls) {
256256
SafeToTail = false;
257257
break;
258258
}
259+
SafeToTail &= CI->hasOperandBundles();
259260
if (SafeToTail) {
260261
emitOptimizationRemark(
261262
F.getContext(), "tailcallelim", F, CI->getDebugLoc(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
; RUN: opt < %s -tailcallelim -S | FileCheck %s
2+
3+
define i32 @f_1(i32 %x) {
4+
; CHECK-LABEL: @f_1(
5+
wentry:
6+
%cond = icmp ugt i32 %x, 0
7+
br i1 %cond, label %return, label %body
8+
9+
body:
10+
; CHECK: body:
11+
; CHECK: call i32 @f_1(i32 %y) [ "deopt"() ]
12+
%y = add i32 %x, 1
13+
%tmp = call i32 @f_1(i32 %y) [ "deopt"() ]
14+
ret i32 0
15+
16+
return:
17+
ret i32 1
18+
}
19+
20+
define i32 @f_2(i32 %x) {
21+
; CHECK-LABEL: @f_2
22+
23+
entry:
24+
%cond = icmp ugt i32 %x, 0
25+
br i1 %cond, label %return, label %body
26+
27+
body:
28+
; CHECK: body:
29+
; CHECK: call i32 @f_2(i32 %y) [ "unknown"() ]
30+
%y = add i32 %x, 1
31+
%tmp = call i32 @f_2(i32 %y) [ "unknown"() ]
32+
ret i32 0
33+
34+
return:
35+
ret i32 1
36+
}
37+
38+
declare void @func()
39+
40+
define void @f_3(i1 %B) personality i8 42 {
41+
; CHECK-LABEL: @f_3(
42+
entry:
43+
invoke void @func()
44+
to label %exit unwind label %merge
45+
merge:
46+
%cs1 = catchswitch within none [label %catch] unwind to caller
47+
48+
catch:
49+
; CHECK: catch:
50+
; CHECK: call void @f_3(i1 %B) [ "funclet"(token %cp) ]
51+
%cp = catchpad within %cs1 []
52+
call void @f_3(i1 %B) [ "funclet"(token %cp) ]
53+
ret void
54+
55+
exit:
56+
ret void
57+
}

0 commit comments

Comments
 (0)
Please sign in to comment.