1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
2 ; RUN: opt < %s -passes=tailcallelim -verify-dom-info -S | FileCheck %s
4 %struct.ListNode = type { i32, ptr }
6 define i32 @umin(ptr readonly %a) {
7 ; CHECK-LABEL: define i32 @umin
8 ; CHECK-SAME: (ptr readonly [[A:%.*]]) {
10 ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
12 ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ]
13 ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ]
14 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null
15 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]]
17 ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umin.i32(i32 -1, i32 [[ACCUMULATOR_TR]])
18 ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
20 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4
21 ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1
22 ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8
23 ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umin.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]])
24 ; CHECK-NEXT: br label [[TAILRECURSE]]
27 %tobool.not = icmp eq ptr %a, null
28 br i1 %tobool.not, label %common.ret6, label %if.end
30 common.ret6: ; preds = %entry, %if.end
31 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -1, %entry ]
32 ret i32 %common.ret6.op
34 if.end: ; preds = %entry
36 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1
37 %1 = load ptr, ptr %next
38 %call = tail call i32 @umin(ptr %1)
39 %.sroa.speculated = tail call i32 @llvm.umin.i32(i32 %0, i32 %call)
43 define i32 @umin2(ptr readonly %a) {
44 ; CHECK-LABEL: define i32 @umin2
45 ; CHECK-SAME: (ptr readonly [[A:%.*]]) {
47 ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
49 ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ]
50 ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ]
51 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null
52 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]]
54 ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umin.i32(i32 [[ACCUMULATOR_TR]], i32 -1)
55 ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
57 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4
58 ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1
59 ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8
60 ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umin.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]])
61 ; CHECK-NEXT: br label [[TAILRECURSE]]
64 %tobool.not = icmp eq ptr %a, null
65 br i1 %tobool.not, label %common.ret6, label %if.end
67 common.ret6: ; preds = %entry, %if.end
68 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -1, %entry ]
69 ret i32 %common.ret6.op
71 if.end: ; preds = %entry
73 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1
74 %1 = load ptr, ptr %next
75 %call = tail call i32 @umin2(ptr %1)
76 %.sroa.speculated = tail call i32 @llvm.umin.i32(i32 %call, i32 %0)
80 define i32 @umax(ptr readonly %a) {
81 ; CHECK-LABEL: define i32 @umax
82 ; CHECK-SAME: (ptr readonly [[A:%.*]]) {
84 ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
86 ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ]
87 ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ]
88 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null
89 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]]
91 ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umax.i32(i32 0, i32 [[ACCUMULATOR_TR]])
92 ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
94 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4
95 ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1
96 ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8
97 ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umax.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]])
98 ; CHECK-NEXT: br label [[TAILRECURSE]]
101 %tobool.not = icmp eq ptr %a, null
102 br i1 %tobool.not, label %common.ret6, label %if.end
104 common.ret6: ; preds = %entry, %if.end
105 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 0, %entry ]
106 ret i32 %common.ret6.op
108 if.end: ; preds = %entry
109 %0 = load i32, ptr %a
110 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1
111 %1 = load ptr, ptr %next
112 %call = tail call i32 @umax(ptr %1)
113 %.sroa.speculated = tail call i32 @llvm.umax.i32(i32 %0, i32 %call)
114 br label %common.ret6
117 define i32 @umax2(ptr readonly %a) {
118 ; CHECK-LABEL: define i32 @umax2
119 ; CHECK-SAME: (ptr readonly [[A:%.*]]) {
121 ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
122 ; CHECK: tailrecurse:
123 ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ]
124 ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ]
125 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null
126 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]]
127 ; CHECK: common.ret6:
128 ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.umax.i32(i32 [[ACCUMULATOR_TR]], i32 0)
129 ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
131 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4
132 ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1
133 ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8
134 ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.umax.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]])
135 ; CHECK-NEXT: br label [[TAILRECURSE]]
138 %tobool.not = icmp eq ptr %a, null
139 br i1 %tobool.not, label %common.ret6, label %if.end
141 common.ret6: ; preds = %entry, %if.end
142 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 0, %entry ]
143 ret i32 %common.ret6.op
145 if.end: ; preds = %entry
146 %0 = load i32, ptr %a
147 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1
148 %1 = load ptr, ptr %next
149 %call = tail call i32 @umax2(ptr %1)
150 %.sroa.speculated = tail call i32 @llvm.umax.i32(i32 %call, i32 %0)
151 br label %common.ret6
154 define i32 @smin(ptr readonly %a) {
155 ; CHECK-LABEL: define i32 @smin
156 ; CHECK-SAME: (ptr readonly [[A:%.*]]) {
158 ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
159 ; CHECK: tailrecurse:
160 ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 2147483647, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ]
161 ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ]
162 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null
163 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]]
164 ; CHECK: common.ret6:
165 ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smin.i32(i32 2147483647, i32 [[ACCUMULATOR_TR]])
166 ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
168 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4
169 ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1
170 ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8
171 ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smin.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]])
172 ; CHECK-NEXT: br label [[TAILRECURSE]]
175 %tobool.not = icmp eq ptr %a, null
176 br i1 %tobool.not, label %common.ret6, label %if.end
178 common.ret6: ; preds = %entry, %if.end
179 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 2147483647, %entry ]
180 ret i32 %common.ret6.op
182 if.end: ; preds = %entry
183 %0 = load i32, ptr %a
184 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1
185 %1 = load ptr, ptr %next
186 %call = tail call i32 @smin(ptr %1)
187 %.sroa.speculated = tail call i32 @llvm.smin.i32(i32 %0, i32 %call)
188 br label %common.ret6
191 define i32 @smin2(ptr readonly %a) {
192 ; CHECK-LABEL: define i32 @smin2
193 ; CHECK-SAME: (ptr readonly [[A:%.*]]) {
195 ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
196 ; CHECK: tailrecurse:
197 ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ 2147483647, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ]
198 ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ]
199 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null
200 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]]
201 ; CHECK: common.ret6:
202 ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smin.i32(i32 [[ACCUMULATOR_TR]], i32 2147483647)
203 ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
205 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4
206 ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1
207 ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8
208 ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smin.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]])
209 ; CHECK-NEXT: br label [[TAILRECURSE]]
212 %tobool.not = icmp eq ptr %a, null
213 br i1 %tobool.not, label %common.ret6, label %if.end
215 common.ret6: ; preds = %entry, %if.end
216 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 2147483647, %entry ]
217 ret i32 %common.ret6.op
219 if.end: ; preds = %entry
220 %0 = load i32, ptr %a
221 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1
222 %1 = load ptr, ptr %next
223 %call = tail call i32 @smin2(ptr %1)
224 %.sroa.speculated = tail call i32 @llvm.smin.i32(i32 %call, i32 %0)
225 br label %common.ret6
228 define i32 @smax(ptr readonly %a) {
229 ; CHECK-LABEL: define i32 @smax
230 ; CHECK-SAME: (ptr readonly [[A:%.*]]) {
232 ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
233 ; CHECK: tailrecurse:
234 ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ]
235 ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ]
236 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null
237 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]]
238 ; CHECK: common.ret6:
239 ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smax.i32(i32 -2147483648, i32 [[ACCUMULATOR_TR]])
240 ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
242 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4
243 ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1
244 ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8
245 ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smax.i32(i32 [[TMP0]], i32 [[ACCUMULATOR_TR]])
246 ; CHECK-NEXT: br label [[TAILRECURSE]]
249 %tobool.not = icmp eq ptr %a, null
250 br i1 %tobool.not, label %common.ret6, label %if.end
252 common.ret6: ; preds = %entry, %if.end
253 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -2147483648, %entry ]
254 ret i32 %common.ret6.op
256 if.end: ; preds = %entry
257 %0 = load i32, ptr %a
258 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1
259 %1 = load ptr, ptr %next
260 %call = tail call i32 @smax(ptr %1)
261 %.sroa.speculated = tail call i32 @llvm.smax.i32(i32 %0, i32 %call)
262 br label %common.ret6
265 define i32 @smax2(ptr readonly %a) {
266 ; CHECK-LABEL: define i32 @smax2
267 ; CHECK-SAME: (ptr readonly [[A:%.*]]) {
269 ; CHECK-NEXT: br label [[TAILRECURSE:%.*]]
270 ; CHECK: tailrecurse:
271 ; CHECK-NEXT: [[ACCUMULATOR_TR:%.*]] = phi i32 [ -2147483648, [[ENTRY:%.*]] ], [ [[DOTSROA_SPECULATED:%.*]], [[IF_END:%.*]] ]
272 ; CHECK-NEXT: [[A_TR:%.*]] = phi ptr [ [[A]], [[ENTRY]] ], [ [[TMP1:%.*]], [[IF_END]] ]
273 ; CHECK-NEXT: [[TOBOOL_NOT:%.*]] = icmp eq ptr [[A_TR]], null
274 ; CHECK-NEXT: br i1 [[TOBOOL_NOT]], label [[COMMON_RET6:%.*]], label [[IF_END]]
275 ; CHECK: common.ret6:
276 ; CHECK-NEXT: [[ACCUMULATOR_RET_TR:%.*]] = tail call i32 @llvm.smax.i32(i32 [[ACCUMULATOR_TR]], i32 -2147483648)
277 ; CHECK-NEXT: ret i32 [[ACCUMULATOR_RET_TR]]
279 ; CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[A_TR]], align 4
280 ; CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds [[STRUCT_LISTNODE:%.*]], ptr [[A_TR]], i64 0, i32 1
281 ; CHECK-NEXT: [[TMP1]] = load ptr, ptr [[NEXT]], align 8
282 ; CHECK-NEXT: [[DOTSROA_SPECULATED]] = tail call i32 @llvm.smax.i32(i32 [[ACCUMULATOR_TR]], i32 [[TMP0]])
283 ; CHECK-NEXT: br label [[TAILRECURSE]]
286 %tobool.not = icmp eq ptr %a, null
287 br i1 %tobool.not, label %common.ret6, label %if.end
289 common.ret6: ; preds = %entry, %if.end
290 %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -2147483648, %entry ]
291 ret i32 %common.ret6.op
293 if.end: ; preds = %entry
294 %0 = load i32, ptr %a
295 %next = getelementptr inbounds %struct.ListNode, ptr %a, i64 0, i32 1
296 %1 = load ptr, ptr %next
297 %call = tail call i32 @smax2(ptr %1)
298 %.sroa.speculated = tail call i32 @llvm.smax.i32(i32 %call, i32 %0)
299 br label %common.ret6
302 declare i32 @llvm.umin.i32(i32, i32)
303 declare i32 @llvm.umax.i32(i32, i32)
304 declare i32 @llvm.smin.i32(i32, i32)
305 declare i32 @llvm.smax.i32(i32, i32)