Skip to content

Commit 4042fb8

Browse files
committed
[TRE] Generate tests for accumulator recursion
1 parent 21a9c7e commit 4042fb8

File tree

1 file changed

+171
-102
lines changed

1 file changed

+171
-102
lines changed

llvm/test/Transforms/TailCallElim/accum_recursion.ll

Lines changed: 171 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,95 @@
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

34
define 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+
;
422
entry:
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
725
then:
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
1230
else:
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

2937
define 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+
;
3055
entry:
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
3358
endif:
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
3863
return:
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-
5267
define 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+
;
5389
entry:
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

5995
bb1:
@@ -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-
81107
define 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+
;
82126
entry:
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

90134
sw.default:
@@ -99,17 +143,28 @@ cleanup:
99143

100144
declare 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-
112146
define 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+
;
113168
entry:
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-
141186
define 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+
;
142215
entry:
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

148221
case0:
@@ -163,26 +236,36 @@ default:
163236

164237
declare 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

185242
define 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+
;
186269
entry:
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

Comments
 (0)