xref: /llvm-project/llvm/test/Transforms/TailCallElim/tre-minmax-intrinsic.ll (revision 72ffaa915623e337abb5c689b5087d7e1d4477ae)
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
3
4%struct.ListNode = type { i32, ptr }
5
6define i32 @umin(ptr readonly %a) {
7; CHECK-LABEL: define i32 @umin
8; CHECK-SAME: (ptr readonly [[A:%.*]]) {
9; CHECK-NEXT:  entry:
10; CHECK-NEXT:    br label [[TAILRECURSE:%.*]]
11; CHECK:       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]]
16; CHECK:       common.ret6:
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]]
19; CHECK:       if.end:
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]]
25;
26entry:
27  %tobool.not = icmp eq ptr %a, null
28  br i1 %tobool.not, label %common.ret6, label %if.end
29
30common.ret6:                                      ; preds = %entry, %if.end
31  %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -1, %entry ]
32  ret i32 %common.ret6.op
33
34if.end:                                           ; preds = %entry
35  %0 = load i32, ptr %a
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)
40  br label %common.ret6
41}
42
43define i32 @umin2(ptr readonly %a) {
44; CHECK-LABEL: define i32 @umin2
45; CHECK-SAME: (ptr readonly [[A:%.*]]) {
46; CHECK-NEXT:  entry:
47; CHECK-NEXT:    br label [[TAILRECURSE:%.*]]
48; CHECK:       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]]
53; CHECK:       common.ret6:
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]]
56; CHECK:       if.end:
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]]
62;
63entry:
64  %tobool.not = icmp eq ptr %a, null
65  br i1 %tobool.not, label %common.ret6, label %if.end
66
67common.ret6:                                      ; preds = %entry, %if.end
68  %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -1, %entry ]
69  ret i32 %common.ret6.op
70
71if.end:                                           ; preds = %entry
72  %0 = load i32, ptr %a
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)
77  br label %common.ret6
78}
79
80define i32 @umax(ptr readonly %a) {
81; CHECK-LABEL: define i32 @umax
82; CHECK-SAME: (ptr readonly [[A:%.*]]) {
83; CHECK-NEXT:  entry:
84; CHECK-NEXT:    br label [[TAILRECURSE:%.*]]
85; CHECK:       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]]
90; CHECK:       common.ret6:
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]]
93; CHECK:       if.end:
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]]
99;
100entry:
101  %tobool.not = icmp eq ptr %a, null
102  br i1 %tobool.not, label %common.ret6, label %if.end
103
104common.ret6:                                      ; preds = %entry, %if.end
105  %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 0, %entry ]
106  ret i32 %common.ret6.op
107
108if.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
115}
116
117define i32 @umax2(ptr readonly %a) {
118; CHECK-LABEL: define i32 @umax2
119; CHECK-SAME: (ptr readonly [[A:%.*]]) {
120; CHECK-NEXT:  entry:
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]]
130; CHECK:       if.end:
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]]
136;
137entry:
138  %tobool.not = icmp eq ptr %a, null
139  br i1 %tobool.not, label %common.ret6, label %if.end
140
141common.ret6:                                      ; preds = %entry, %if.end
142  %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 0, %entry ]
143  ret i32 %common.ret6.op
144
145if.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
152}
153
154define i32 @smin(ptr readonly %a) {
155; CHECK-LABEL: define i32 @smin
156; CHECK-SAME: (ptr readonly [[A:%.*]]) {
157; CHECK-NEXT:  entry:
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]]
167; CHECK:       if.end:
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]]
173;
174entry:
175  %tobool.not = icmp eq ptr %a, null
176  br i1 %tobool.not, label %common.ret6, label %if.end
177
178common.ret6:                                      ; preds = %entry, %if.end
179  %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 2147483647, %entry ]
180  ret i32 %common.ret6.op
181
182if.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
189}
190
191define i32 @smin2(ptr readonly %a) {
192; CHECK-LABEL: define i32 @smin2
193; CHECK-SAME: (ptr readonly [[A:%.*]]) {
194; CHECK-NEXT:  entry:
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]]
204; CHECK:       if.end:
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]]
210;
211entry:
212  %tobool.not = icmp eq ptr %a, null
213  br i1 %tobool.not, label %common.ret6, label %if.end
214
215common.ret6:                                      ; preds = %entry, %if.end
216  %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ 2147483647, %entry ]
217  ret i32 %common.ret6.op
218
219if.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
226}
227
228define i32 @smax(ptr readonly %a) {
229; CHECK-LABEL: define i32 @smax
230; CHECK-SAME: (ptr readonly [[A:%.*]]) {
231; CHECK-NEXT:  entry:
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]]
241; CHECK:       if.end:
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]]
247;
248entry:
249  %tobool.not = icmp eq ptr %a, null
250  br i1 %tobool.not, label %common.ret6, label %if.end
251
252common.ret6:                                      ; preds = %entry, %if.end
253  %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -2147483648, %entry ]
254  ret i32 %common.ret6.op
255
256if.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
263}
264
265define i32 @smax2(ptr readonly %a) {
266; CHECK-LABEL: define i32 @smax2
267; CHECK-SAME: (ptr readonly [[A:%.*]]) {
268; CHECK-NEXT:  entry:
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]]
278; CHECK:       if.end:
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]]
284;
285entry:
286  %tobool.not = icmp eq ptr %a, null
287  br i1 %tobool.not, label %common.ret6, label %if.end
288
289common.ret6:                                      ; preds = %entry, %if.end
290  %common.ret6.op = phi i32 [ %.sroa.speculated, %if.end ], [ -2147483648, %entry ]
291  ret i32 %common.ret6.op
292
293if.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
300}
301
302declare i32 @llvm.umin.i32(i32, i32)
303declare i32 @llvm.umax.i32(i32, i32)
304declare i32 @llvm.smin.i32(i32, i32)
305declare i32 @llvm.smax.i32(i32, i32)
306