1+ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
12; RUN: opt < %s -passes=tailcallelim -verify-dom-info -S | FileCheck %s
23
34define i32 @test1_factorial (i32 %x ) {
5+ ; CHECK-LABEL: define i32 @test1_factorial(
6+ ; CHECK-SAME: i32 [[X:%.*]]) {
7+ ; CHECK-NEXT: entry:
8+ ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
9+ ; CHECK: tailrecurse:
10+ ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[ACCUMULATE:%.*]], [[THEN:%.*]] ]
11+ ; CHECK-NEXT: [[X_TR:%.*]] = phi i32 [ [[X]], [[ENTRY]] ], [ [[TMP_6:%.*]], [[THEN]] ]
12+ ; CHECK-NEXT: [[TMP_1:%.*]] = icmp sgt i32 [[X_TR]], 0
13+ ; CHECK-NEXT: br i1 [[TMP_1]], label [[THEN]], label [[ELSE:%.*]]
14+ ; CHECK: then:
15+ ; CHECK-NEXT: [[TMP_6]] = add i32 [[X_TR]], -1
16+ ; CHECK-NEXT: [[ACCUMULATE]] = mul i32 [[ACCUMULATOR_TR]], [[X_TR]]
17+ ; CHECK-NEXT: br label [[TAILRECURSE]]
18+ ; CHECK: else:
19+ ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = mul i32 [[ACCUMULATOR_TR]], 1
20+ ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
21+ ;
422entry:
5- %tmp.1 = icmp sgt i32 %x , 0
6- br i1 %tmp.1 , label %then , label %else
23+ %tmp.1 = icmp sgt i32 %x , 0
24+ br i1 %tmp.1 , label %then , label %else
725then:
8- %tmp.6 = add i32 %x , -1
9- %recurse = call i32 @test1_factorial ( i32 %tmp.6 )
10- %accumulate = mul i32 %recurse , %x
11- ret i32 %accumulate
26+ %tmp.6 = add i32 %x , -1
27+ %recurse = call i32 @test1_factorial ( i32 %tmp.6 )
28+ %accumulate = mul i32 %recurse , %x
29+ ret i32 %accumulate
1230else:
13- ret i32 1
31+ ret i32 1
1432}
1533
16- ; CHECK-LABEL: define i32 @test1_factorial(
17- ; CHECK: tailrecurse:
18- ; CHECK: %accumulator.tr = phi i32 [ 1, %entry ], [ %accumulate, %then ]
19- ; CHECK: then:
20- ; CHECK-NOT: %recurse
21- ; CHECK: %accumulate = mul i32 %accumulator.tr, %x.tr
22- ; CHECK: else:
23- ; CHECK: %accumulator.ret.tr = mul i32 %accumulator.tr, 1
24- ; CHECK: ret i32 %accumulator.ret.tr
25-
26- ; This is a more aggressive form of accumulator recursion insertion, which
34+ ; This is a more aggressive form of accumulator recursion insertion, which
2735; requires noticing that X doesn't change as we perform the tailcall.
2836
2937define i32 @test2_mul (i32 %x , i32 %y ) {
38+ ; CHECK-LABEL: define i32 @test2_mul(
39+ ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
40+ ; CHECK-NEXT: entry:
41+ ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
42+ ; CHECK: tailrecurse:
43+ ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ACCUMULATE:%.*]], [[ENDIF:%.*]] ]
44+ ; CHECK-NEXT: [[Y_TR:%.*]] = phi i32 [ [[Y]], [[ENTRY]] ], [ [[TMP_8:%.*]], [[ENDIF]] ]
45+ ; CHECK-NEXT: [[TMP_1:%.*]] = icmp eq i32 [[Y_TR]], 0
46+ ; CHECK-NEXT: br i1 [[TMP_1]], label [[RETURN:%.*]], label [[ENDIF]]
47+ ; CHECK: endif:
48+ ; CHECK-NEXT: [[TMP_8]] = add i32 [[Y_TR]], -1
49+ ; CHECK-NEXT: [[ACCUMULATE]] = add i32 [[ACCUMULATOR_TR]], [[X]]
50+ ; CHECK-NEXT: br label [[TAILRECURSE]]
51+ ; CHECK: return:
52+ ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = add i32 [[ACCUMULATOR_TR]], [[X]]
53+ ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
54+ ;
3055entry:
31- %tmp.1 = icmp eq i32 %y , 0
32- br i1 %tmp.1 , label %return , label %endif
56+ %tmp.1 = icmp eq i32 %y , 0
57+ br i1 %tmp.1 , label %return , label %endif
3358endif:
34- %tmp.8 = add i32 %y , -1
35- %recurse = call i32 @test2_mul ( i32 %x , i32 %tmp.8 )
36- %accumulate = add i32 %recurse , %x
37- ret i32 %accumulate
59+ %tmp.8 = add i32 %y , -1
60+ %recurse = call i32 @test2_mul ( i32 %x , i32 %tmp.8 )
61+ %accumulate = add i32 %recurse , %x
62+ ret i32 %accumulate
3863return:
39- ret i32 %x
64+ ret i32 %x
4065}
4166
42- ; CHECK-LABEL: define i32 @test2_mul(
43- ; CHECK: tailrecurse:
44- ; CHECK: %accumulator.tr = phi i32 [ 0, %entry ], [ %accumulate, %endif ]
45- ; CHECK: endif:
46- ; CHECK-NOT: %recurse
47- ; CHECK: %accumulate = add i32 %accumulator.tr, %x
48- ; CHECK: return:
49- ; CHECK: %accumulator.ret.tr = add i32 %accumulator.tr, %x
50- ; CHECK: ret i32 %accumulator.ret.tr
51-
5267define i64 @test3_fib (i64 %n ) nounwind readnone {
68+ ; CHECK-LABEL: define i64 @test3_fib(
69+ ; CHECK-SAME: i64 [[N:%.*]]) #[[ATTR0:[0-9]+]] {
70+ ; CHECK-NEXT: entry:
71+ ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
72+ ; CHECK: tailrecurse:
73+ ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[ACCUMULATE:%.*]], [[BB1:%.*]] ]
74+ ; CHECK-NEXT: [[N_TR:%.*]] = phi i64 [ [[N]], [[ENTRY]] ], [ [[TMP1:%.*]], [[BB1]] ]
75+ ; CHECK-NEXT: switch i64 [[N_TR]], label [[BB1]] [
76+ ; CHECK-NEXT: i64 0, label [[BB2:%.*]]
77+ ; CHECK-NEXT: i64 1, label [[BB2]]
78+ ; CHECK-NEXT: ]
79+ ; CHECK: bb1:
80+ ; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[N_TR]], -1
81+ ; CHECK-NEXT: [[RECURSE1:%.*]] = tail call i64 @test3_fib(i64 [[TMP0]]) #[[ATTR1:[0-9]+]]
82+ ; CHECK-NEXT: [[TMP1]] = add i64 [[N_TR]], -2
83+ ; CHECK-NEXT: [[ACCUMULATE]] = add nsw i64 [[ACCUMULATOR_TR]], [[RECURSE1]]
84+ ; CHECK-NEXT: br label [[TAILRECURSE]]
85+ ; CHECK: bb2:
86+ ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = add nsw i64 [[ACCUMULATOR_TR]], [[N_TR]]
87+ ; CHECK-NEXT: ret i64 [[ACCUMULATOR_RET_TR]]
88+ ;
5389entry:
5490 switch i64 %n , label %bb1 [
55- i64 0 , label %bb2
56- i64 1 , label %bb2
91+ i64 0 , label %bb2
92+ i64 1 , label %bb2
5793 ]
5894
5995bb1:
@@ -68,23 +104,31 @@ bb2:
68104 ret i64 %n
69105}
70106
71- ; CHECK-LABEL: define i64 @test3_fib(
72- ; CHECK: tailrecurse:
73- ; CHECK: %accumulator.tr = phi i64 [ 0, %entry ], [ %accumulate, %bb1 ]
74- ; CHECK: bb1:
75- ; CHECK-NOT: %recurse2
76- ; CHECK: %accumulate = add nsw i64 %accumulator.tr, %recurse1
77- ; CHECK: bb2:
78- ; CHECK: %accumulator.ret.tr = add nsw i64 %accumulator.tr, %n.tr
79- ; CHECK: ret i64 %accumulator.ret.tr
80-
81107define i32 @test4_base_case_call () local_unnamed_addr {
108+ ; CHECK-LABEL: define i32 @test4_base_case_call() local_unnamed_addr {
109+ ; CHECK-NEXT: entry:
110+ ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
111+ ; CHECK: tailrecurse:
112+ ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ACCUMULATE:%.*]], [[SW_DEFAULT:%.*]] ]
113+ ; CHECK-NEXT: [[BASE:%.*]] = tail call i32 @test4_helper()
114+ ; CHECK-NEXT: switch i32 [[BASE]], label [[SW_DEFAULT]] [
115+ ; CHECK-NEXT: i32 1, label [[CLEANUP:%.*]]
116+ ; CHECK-NEXT: i32 5, label [[CLEANUP]]
117+ ; CHECK-NEXT: i32 7, label [[CLEANUP]]
118+ ; CHECK-NEXT: ]
119+ ; CHECK: sw.default:
120+ ; CHECK-NEXT: [[ACCUMULATE]] = add nsw i32 [[ACCUMULATOR_TR]], 1
121+ ; CHECK-NEXT: br label [[TAILRECURSE]]
122+ ; CHECK: cleanup:
123+ ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = add nsw i32 [[ACCUMULATOR_TR]], [[BASE]]
124+ ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
125+ ;
82126entry:
83127 %base = call i32 @test4_helper ()
84128 switch i32 %base , label %sw.default [
85- i32 1 , label %cleanup
86- i32 5 , label %cleanup
87- i32 7 , label %cleanup
129+ i32 1 , label %cleanup
130+ i32 5 , label %cleanup
131+ i32 7 , label %cleanup
88132 ]
89133
90134sw.default:
@@ -99,17 +143,28 @@ cleanup:
99143
100144declare i32 @test4_helper ()
101145
102- ; CHECK-LABEL: define i32 @test4_base_case_call(
103- ; CHECK: tailrecurse:
104- ; CHECK: %accumulator.tr = phi i32 [ 0, %entry ], [ %accumulate, %sw.default ]
105- ; CHECK: sw.default:
106- ; CHECK-NOT: %recurse
107- ; CHECK: %accumulate = add nsw i32 %accumulator.tr, 1
108- ; CHECK: cleanup:
109- ; CHECK: %accumulator.ret.tr = add nsw i32 %accumulator.tr, %base
110- ; CHECK: ret i32 %accumulator.ret.tr
111-
112146define i32 @test5_base_case_load (ptr nocapture %A , i32 %n ) local_unnamed_addr {
147+ ; CHECK-LABEL: define i32 @test5_base_case_load(
148+ ; CHECK-SAME: ptr nocapture [[A:%.*]], i32 [[N:%.*]]) local_unnamed_addr {
149+ ; CHECK-NEXT: entry:
150+ ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
151+ ; CHECK: tailrecurse:
152+ ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ACCUMULATE:%.*]], [[IF_END:%.*]] ]
153+ ; CHECK-NEXT: [[N_TR:%.*]] = phi i32 [ [[N]], [[ENTRY]] ], [ [[SUB:%.*]], [[IF_END]] ]
154+ ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[N_TR]], 0
155+ ; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END]]
156+ ; CHECK: if.then:
157+ ; CHECK-NEXT: [[BASE:%.*]] = load i32, ptr [[A]], align 4
158+ ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = add i32 [[ACCUMULATOR_TR]], [[BASE]]
159+ ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
160+ ; CHECK: if.end:
161+ ; CHECK-NEXT: [[IDXPROM:%.*]] = zext i32 [[N_TR]] to i64
162+ ; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[IDXPROM]]
163+ ; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4
164+ ; CHECK-NEXT: [[SUB]] = add i32 [[N_TR]], -1
165+ ; CHECK-NEXT: [[ACCUMULATE]] = add i32 [[ACCUMULATOR_TR]], [[LOAD]]
166+ ; CHECK-NEXT: br label [[TAILRECURSE]]
167+ ;
113168entry:
114169 %cmp = icmp eq i32 %n , 0
115170 br i1 %cmp , label %if.then , label %if.end
@@ -128,21 +183,39 @@ if.end:
128183 ret i32 %accumulate
129184}
130185
131- ; CHECK-LABEL: define i32 @test5_base_case_load(
132- ; CHECK: tailrecurse:
133- ; CHECK: %accumulator.tr = phi i32 [ 0, %entry ], [ %accumulate, %if.end ]
134- ; CHECK: if.then:
135- ; CHECK: %accumulator.ret.tr = add i32 %accumulator.tr, %base
136- ; CHECK: ret i32 %accumulator.ret.tr
137- ; CHECK: if.end:
138- ; CHECK-NOT: %recurse
139- ; CHECK: %accumulate = add i32 %accumulator.tr, %load
140-
141186define i32 @test6_multiple_returns (i32 %x , i32 %y ) local_unnamed_addr {
187+ ; CHECK-LABEL: define i32 @test6_multiple_returns(
188+ ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) local_unnamed_addr {
189+ ; CHECK-NEXT: entry:
190+ ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
191+ ; CHECK: tailrecurse:
192+ ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ [[ACCUMULATOR_TR]], [[CASE99:%.*]] ], [ 0, [[ENTRY:%.*]] ], [ [[ACCUMULATE:%.*]], [[DEFAULT:%.*]] ]
193+ ; CHECK-NEXT: [[X_TR:%.*]] = phi i32 [ [[X]], [[ENTRY]] ], [ [[SUB1:%.*]], [[CASE99]] ], [ [[SUB2:%.*]], [[DEFAULT]] ]
194+ ; CHECK-NEXT: [[RET_TR:%.*]] = phi i32 [ poison, [[ENTRY]] ], [ [[CURRENT_RET_TR:%.*]], [[CASE99]] ], [ [[RET_TR]], [[DEFAULT]] ]
195+ ; CHECK-NEXT: [[RET_KNOWN_TR:%.*]] = phi i1 [ false, [[ENTRY]] ], [ true, [[CASE99]] ], [ [[RET_KNOWN_TR]], [[DEFAULT]] ]
196+ ; CHECK-NEXT: switch i32 [[X_TR]], label [[DEFAULT]] [
197+ ; CHECK-NEXT: i32 0, label [[CASE0:%.*]]
198+ ; CHECK-NEXT: i32 99, label [[CASE99]]
199+ ; CHECK-NEXT: ]
200+ ; CHECK: case0:
201+ ; CHECK-NEXT: [[HELPER:%.*]] = tail call i32 @test6_helper()
202+ ; CHECK-NEXT: [[ACCUMULATOR_RET_TR2:%.*]] = add i32 [[ACCUMULATOR_TR]], [[HELPER]]
203+ ; CHECK-NEXT: [[CURRENT_RET_TR1:%.*]] = select i1 [[RET_KNOWN_TR]], i32 [[RET_TR]], i32 [[ACCUMULATOR_RET_TR2]]
204+ ; CHECK-NEXT: ret i32 [[CURRENT_RET_TR1]]
205+ ; CHECK: case99:
206+ ; CHECK-NEXT: [[SUB1]] = add i32 [[X_TR]], -1
207+ ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = add i32 [[ACCUMULATOR_TR]], 18
208+ ; CHECK-NEXT: [[CURRENT_RET_TR]] = select i1 [[RET_KNOWN_TR]], i32 [[RET_TR]], i32 [[ACCUMULATOR_RET_TR]]
209+ ; CHECK-NEXT: br label [[TAILRECURSE]]
210+ ; CHECK: default:
211+ ; CHECK-NEXT: [[SUB2]] = add i32 [[X_TR]], -1
212+ ; CHECK-NEXT: [[ACCUMULATE]] = add i32 [[ACCUMULATOR_TR]], [[Y]]
213+ ; CHECK-NEXT: br label [[TAILRECURSE]]
214+ ;
142215entry:
143216 switch i32 %x , label %default [
144- i32 0 , label %case0
145- i32 99 , label %case99
217+ i32 0 , label %case0
218+ i32 99 , label %case99
146219 ]
147220
148221case0:
@@ -163,26 +236,36 @@ default:
163236
164237declare i32 @test6_helper ()
165238
166- ; CHECK-LABEL: define i32 @test6_multiple_returns(
167- ; CHECK: tailrecurse:
168- ; CHECK: %accumulator.tr = phi i32 [ %accumulator.tr, %case99 ], [ 0, %entry ], [ %accumulate, %default ]
169- ; CHECK: %ret.tr = phi i32 [ poison, %entry ], [ %current.ret.tr, %case99 ], [ %ret.tr, %default ]
170- ; CHECK: %ret.known.tr = phi i1 [ false, %entry ], [ true, %case99 ], [ %ret.known.tr, %default ]
171- ; CHECK: case0:
172- ; CHECK: %accumulator.ret.tr2 = add i32 %accumulator.tr, %helper
173- ; CHECK: %current.ret.tr1 = select i1 %ret.known.tr, i32 %ret.tr, i32 %accumulator.ret.tr2
174- ; CHECK: case99:
175- ; CHECK-NOT: %recurse
176- ; CHECK: %accumulator.ret.tr = add i32 %accumulator.tr, 18
177- ; CHECK: %current.ret.tr = select i1 %ret.known.tr, i32 %ret.tr, i32 %accumulator.ret.tr
178- ; CHECK: default:
179- ; CHECK-NOT: %recurse
180- ; CHECK: %accumulate = add i32 %accumulator.tr, %y
181-
182239; It is only safe to transform one accumulator per function, make sure we don't
183240; try to remove more.
184241
185242define i32 @test7_multiple_accumulators (i32 %a ) local_unnamed_addr {
243+ ; CHECK-LABEL: define i32 @test7_multiple_accumulators(
244+ ; CHECK-SAME: i32 [[A:%.*]]) local_unnamed_addr {
245+ ; CHECK-NEXT: entry:
246+ ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
247+ ; CHECK: tailrecurse:
248+ ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ACCUMULATE1:%.*]], [[IF_THEN2:%.*]] ]
249+ ; CHECK-NEXT: [[A_TR:%.*]] = phi i32 [ [[A]], [[ENTRY]] ], [ [[SUB:%.*]], [[IF_THEN2]] ]
250+ ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A_TR]], 0
251+ ; CHECK-NEXT: br i1 [[TOBOOL]], label [[RETURN:%.*]], label [[IF_END:%.*]]
252+ ; CHECK: if.end:
253+ ; CHECK-NEXT: [[AND:%.*]] = and i32 [[A_TR]], 1
254+ ; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i32 [[AND]], 0
255+ ; CHECK-NEXT: [[SUB]] = add nsw i32 [[A_TR]], -1
256+ ; CHECK-NEXT: br i1 [[TOBOOL1]], label [[IF_END3:%.*]], label [[IF_THEN2]]
257+ ; CHECK: if.then2:
258+ ; CHECK-NEXT: [[ACCUMULATE1]] = add nsw i32 [[ACCUMULATOR_TR]], 1
259+ ; CHECK-NEXT: br label [[TAILRECURSE]]
260+ ; CHECK: if.end3:
261+ ; CHECK-NEXT: [[RECURSE2:%.*]] = tail call i32 @test7_multiple_accumulators(i32 [[SUB]])
262+ ; CHECK-NEXT: [[ACCUMULATE2:%.*]] = mul nsw i32 [[RECURSE2]], 2
263+ ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = add nsw i32 [[ACCUMULATOR_TR]], [[ACCUMULATE2]]
264+ ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
265+ ; CHECK: return:
266+ ; CHECK-NEXT: [[ACCUMULATOR_RET_TR1:%.*]] = add nsw i32 [[ACCUMULATOR_TR]], 0
267+ ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR1]]
268+ ;
186269entry:
187270 %tobool = icmp eq i32 %a , 0
188271 br i1 %tobool , label %return , label %if.end
@@ -207,17 +290,3 @@ return:
207290 %retval.0 = phi i32 [ %accumulate1 , %if.then2 ], [ %accumulate2 , %if.end3 ], [ 0 , %entry ]
208291 ret i32 %retval.0
209292}
210-
211- ; CHECK-LABEL: define i32 @test7_multiple_accumulators(
212- ; CHECK: tailrecurse:
213- ; CHECK: %accumulator.tr = phi i32 [ 0, %entry ], [ %accumulate1, %if.then2 ]
214- ; CHECK: if.then2:
215- ; CHECK-NOT: %recurse1
216- ; CHECK: %accumulate1 = add nsw i32 %accumulator.tr, 1
217- ; CHECK: if.end3:
218- ; CHECK: %recurse2
219- ; CHECK: %accumulator.ret.tr = add nsw i32 %accumulator.tr, %accumulate2
220- ; CHECK: ret i32 %accumulator.ret.tr
221- ; CHECK: return:
222- ; CHECK: %accumulator.ret.tr1 = add nsw i32 %accumulator.tr, 0
223- ; CHECK: ret i32 %accumulator.ret.tr1
0 commit comments