1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -instcombine -S < %s | FileCheck %s
3
4; Canonicalization of unsigned saturated subtraction idioms to
5; usub.sat() intrinsics is tested here.
6
7declare void @use(i64)
8declare void @usei32(i32)
9declare void @usei1(i1)
10
11; (a > b) ? a - b : 0 -> usub.sat(a, b)
12
13define i64 @max_sub_ugt(i64 %a, i64 %b) {
14; CHECK-LABEL: @max_sub_ugt(
15; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
16; CHECK-NEXT:    ret i64 [[TMP1]]
17;
18  %cmp = icmp ugt i64 %a, %b
19  %sub = sub i64 %a, %b
20  %sel = select i1 %cmp, i64 %sub ,i64 0
21  ret i64 %sel
22}
23
24; (a >= b) ? a - b : 0 -> usub.sat(a, b)
25
26define i64 @max_sub_uge(i64 %a, i64 %b) {
27; CHECK-LABEL: @max_sub_uge(
28; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
29; CHECK-NEXT:    ret i64 [[TMP1]]
30;
31  %cmp = icmp uge i64 %a, %b
32  %sub = sub i64 %a, %b
33  %sel = select i1 %cmp, i64 %sub ,i64 0
34  ret i64 %sel
35}
36
37define i64 @max_sub_uge_extrause1(i64 %a, i64 %b) {
38; CHECK-LABEL: @max_sub_uge_extrause1(
39; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[A:%.*]], [[B:%.*]]
40; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
41; CHECK-NEXT:    call void @use(i64 [[SUB]])
42; CHECK-NEXT:    ret i64 [[TMP1]]
43;
44  %cmp = icmp uge i64 %a, %b
45  %sub = sub i64 %a, %b
46  %sel = select i1 %cmp, i64 %sub ,i64 0
47  call void @use(i64 %sub)
48  ret i64 %sel
49}
50
51define i64 @max_sub_uge_extrause2(i64 %a, i64 %b) {
52; CHECK-LABEL: @max_sub_uge_extrause2(
53; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i64 [[A:%.*]], [[B:%.*]]
54; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
55; CHECK-NEXT:    call void @usei1(i1 [[CMP]])
56; CHECK-NEXT:    ret i64 [[TMP1]]
57;
58  %cmp = icmp uge i64 %a, %b
59  %sub = sub i64 %a, %b
60  %sel = select i1 %cmp, i64 %sub ,i64 0
61  call void @usei1(i1 %cmp)
62  ret i64 %sel
63}
64
65define i64 @max_sub_uge_extrause3(i64 %a, i64 %b) {
66; CHECK-LABEL: @max_sub_uge_extrause3(
67; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i64 [[A:%.*]], [[B:%.*]]
68; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[A]], [[B]]
69; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
70; CHECK-NEXT:    call void @use(i64 [[SUB]])
71; CHECK-NEXT:    call void @usei1(i1 [[CMP]])
72; CHECK-NEXT:    ret i64 [[TMP1]]
73;
74  %cmp = icmp uge i64 %a, %b
75  %sub = sub i64 %a, %b
76  %sel = select i1 %cmp, i64 %sub ,i64 0
77  call void @use(i64 %sub)
78  call void @usei1(i1 %cmp)
79  ret i64 %sel
80}
81
82; Again, with vectors:
83; (a > b) ? a - b : 0 -> usub.sat(a, b)
84
85define <4 x i32> @max_sub_ugt_vec(<4 x i32> %a, <4 x i32> %b) {
86; CHECK-LABEL: @max_sub_ugt_vec(
87; CHECK-NEXT:    [[TMP1:%.*]] = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]])
88; CHECK-NEXT:    ret <4 x i32> [[TMP1]]
89;
90  %cmp = icmp ugt <4 x i32> %a, %b
91  %sub = sub <4 x i32> %a, %b
92  %sel = select <4 x i1> %cmp, <4 x i32> %sub, <4 x i32> zeroinitializer
93  ret <4 x i32> %sel
94}
95
96; Use extra ops to thwart icmp swapping canonicalization.
97; (b < a) ? a - b : 0 -> usub.sat(a, b)
98
99define i64 @max_sub_ult(i64 %a, i64 %b) {
100; CHECK-LABEL: @max_sub_ult(
101; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
102; CHECK-NEXT:    [[EXTRASUB:%.*]] = sub i64 [[B]], [[A]]
103; CHECK-NEXT:    call void @use(i64 [[EXTRASUB]])
104; CHECK-NEXT:    ret i64 [[TMP1]]
105;
106  %cmp = icmp ult i64 %b, %a
107  %sub = sub i64 %a, %b
108  %sel = select i1 %cmp, i64 %sub ,i64 0
109  %extrasub = sub i64 %b, %a
110  call void @use(i64 %extrasub)
111  ret i64 %sel
112}
113
114; (b > a) ? 0 : a - b -> usub.sat(a, b)
115
116define i64 @max_sub_ugt_sel_swapped(i64 %a, i64 %b) {
117; CHECK-LABEL: @max_sub_ugt_sel_swapped(
118; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
119; CHECK-NEXT:    [[EXTRASUB:%.*]] = sub i64 [[B]], [[A]]
120; CHECK-NEXT:    call void @use(i64 [[EXTRASUB]])
121; CHECK-NEXT:    ret i64 [[TMP1]]
122;
123  %cmp = icmp ugt i64 %b, %a
124  %sub = sub i64 %a, %b
125  %sel = select i1 %cmp, i64 0 ,i64 %sub
126  %extrasub = sub i64 %b, %a
127  call void @use(i64 %extrasub)
128  ret i64 %sel
129}
130
131; (a < b) ? 0 : a - b -> usub.sat(a, b)
132
133define i64 @max_sub_ult_sel_swapped(i64 %a, i64 %b) {
134; CHECK-LABEL: @max_sub_ult_sel_swapped(
135; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
136; CHECK-NEXT:    ret i64 [[TMP1]]
137;
138  %cmp = icmp ult i64 %a, %b
139  %sub = sub i64 %a, %b
140  %sel = select i1 %cmp, i64 0 ,i64 %sub
141  ret i64 %sel
142}
143
144; ((a > b) ? b - a : 0) -> -usub.sat(a, b)
145
146define i64 @neg_max_sub_ugt(i64 %a, i64 %b) {
147; CHECK-LABEL: @neg_max_sub_ugt(
148; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
149; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
150; CHECK-NEXT:    [[EXTRASUB:%.*]] = sub i64 [[A]], [[B]]
151; CHECK-NEXT:    call void @use(i64 [[EXTRASUB]])
152; CHECK-NEXT:    ret i64 [[TMP2]]
153;
154  %cmp = icmp ugt i64 %a, %b
155  %sub = sub i64 %b, %a
156  %sel = select i1 %cmp, i64 %sub ,i64 0
157  %extrasub = sub i64 %a, %b
158  call void @use(i64 %extrasub)
159  ret i64 %sel
160}
161
162; ((b < a) ? b - a : 0) -> -usub.sat(a, b)
163
164define i64 @neg_max_sub_ult(i64 %a, i64 %b) {
165; CHECK-LABEL: @neg_max_sub_ult(
166; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
167; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
168; CHECK-NEXT:    ret i64 [[TMP2]]
169;
170  %cmp = icmp ult i64 %b, %a
171  %sub = sub i64 %b, %a
172  %sel = select i1 %cmp, i64 %sub ,i64 0
173  ret i64 %sel
174}
175
176; ((b > a) ? 0 : b - a) -> -usub.sat(a, b)
177
178define i64 @neg_max_sub_ugt_sel_swapped(i64 %a, i64 %b) {
179; CHECK-LABEL: @neg_max_sub_ugt_sel_swapped(
180; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
181; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
182; CHECK-NEXT:    ret i64 [[TMP2]]
183;
184  %cmp = icmp ugt i64 %b, %a
185  %sub = sub i64 %b, %a
186  %sel = select i1 %cmp, i64 0 ,i64 %sub
187  ret i64 %sel
188}
189
190define i64 @neg_max_sub_ugt_sel_swapped_extrause1(i64 %a, i64 %b) {
191; CHECK-LABEL: @neg_max_sub_ugt_sel_swapped_extrause1(
192; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[B:%.*]], [[A:%.*]]
193; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
194; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
195; CHECK-NEXT:    call void @usei1(i1 [[CMP]])
196; CHECK-NEXT:    ret i64 [[TMP2]]
197;
198  %cmp = icmp ugt i64 %b, %a
199  %sub = sub i64 %b, %a
200  %sel = select i1 %cmp, i64 0 ,i64 %sub
201  call void @usei1(i1 %cmp)
202  ret i64 %sel
203}
204
205define i64 @neg_max_sub_ugt_sel_swapped_extrause2(i64 %a, i64 %b) {
206; CHECK-LABEL: @neg_max_sub_ugt_sel_swapped_extrause2(
207; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[B:%.*]], [[A:%.*]]
208; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
209; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
210; CHECK-NEXT:    call void @use(i64 [[SUB]])
211; CHECK-NEXT:    ret i64 [[TMP2]]
212;
213  %cmp = icmp ugt i64 %b, %a
214  %sub = sub i64 %b, %a
215  %sel = select i1 %cmp, i64 0 ,i64 %sub
216  call void @use(i64 %sub)
217  ret i64 %sel
218}
219
220define i64 @neg_max_sub_ugt_sel_swapped_extrause3(i64 %a, i64 %b) {
221; CHECK-LABEL: @neg_max_sub_ugt_sel_swapped_extrause3(
222; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[B:%.*]], [[A:%.*]]
223; CHECK-NEXT:    [[SUB:%.*]] = sub i64 [[B]], [[A]]
224; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i64 0, i64 [[SUB]]
225; CHECK-NEXT:    call void @use(i64 [[SUB]])
226; CHECK-NEXT:    call void @usei1(i1 [[CMP]])
227; CHECK-NEXT:    ret i64 [[SEL]]
228;
229  %cmp = icmp ugt i64 %b, %a
230  %sub = sub i64 %b, %a
231  %sel = select i1 %cmp, i64 0 ,i64 %sub
232  call void @use(i64 %sub)
233  call void @usei1(i1 %cmp)
234  ret i64 %sel
235}
236
237; ((a < b) ? 0 : b - a) -> -usub.sat(a, b)
238
239define i64 @neg_max_sub_ult_sel_swapped(i64 %a, i64 %b) {
240; CHECK-LABEL: @neg_max_sub_ult_sel_swapped(
241; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
242; CHECK-NEXT:    [[TMP2:%.*]] = sub i64 0, [[TMP1]]
243; CHECK-NEXT:    [[EXTRASUB:%.*]] = sub i64 [[A]], [[B]]
244; CHECK-NEXT:    call void @use(i64 [[EXTRASUB]])
245; CHECK-NEXT:    ret i64 [[TMP2]]
246;
247  %cmp = icmp ult i64 %a, %b
248  %sub = sub i64 %b, %a
249  %sel = select i1 %cmp, i64 0 ,i64 %sub
250  %extrasub = sub i64 %a, %b
251  call void @use(i64 %extrasub)
252  ret i64 %sel
253}
254
255define i32 @max_sub_ugt_c1(i32 %a) {
256; CHECK-LABEL: @max_sub_ugt_c1(
257; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 1)
258; CHECK-NEXT:    ret i32 [[TMP1]]
259;
260  %cmp = icmp ugt i32 %a, 1
261  %sub = add i32 %a, -1
262  %sel = select i1 %cmp, i32 %sub ,i32 0
263  ret i32 %sel
264}
265
266define i32 @max_sub_ugt_c01(i32 %a) {
267; CHECK-LABEL: @max_sub_ugt_c01(
268; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
269; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -1
270; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 0, i32 [[SUB]]
271; CHECK-NEXT:    ret i32 [[SEL]]
272;
273  %cmp = icmp ugt i32 %a, 0
274  %sub = add i32 %a, -1
275  %sel = select i1 %cmp, i32 %sub ,i32 0
276  ret i32 %sel
277}
278
279define i32 @max_sub_ugt_c10(i32 %a) {
280; CHECK-LABEL: @max_sub_ugt_c10(
281; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 10)
282; CHECK-NEXT:    ret i32 [[TMP1]]
283;
284  %cmp = icmp ugt i32 %a, 10
285  %sub = add i32 %a, -10
286  %sel = select i1 %cmp, i32 %sub, i32 0
287  ret i32 %sel
288}
289
290define i32 @max_sub_ugt_c910(i32 %a) {
291; CHECK-LABEL: @max_sub_ugt_c910(
292; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 9
293; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -10
294; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
295; CHECK-NEXT:    ret i32 [[SEL]]
296;
297  %cmp = icmp ugt i32 %a, 9
298  %sub = add i32 %a, -10
299  %sel = select i1 %cmp, i32 %sub, i32 0
300  ret i32 %sel
301}
302
303define i32 @max_sub_ugt_c1110(i32 %a) {
304; CHECK-LABEL: @max_sub_ugt_c1110(
305; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 11
306; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -10
307; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
308; CHECK-NEXT:    ret i32 [[SEL]]
309;
310  %cmp = icmp ugt i32 %a, 11
311  %sub = add i32 %a, -10
312  %sel = select i1 %cmp, i32 %sub, i32 0
313  ret i32 %sel
314}
315
316define i32 @max_sub_ugt_c0(i32 %a) {
317; CHECK-LABEL: @max_sub_ugt_c0(
318; CHECK-NEXT:    ret i32 0
319;
320  %cmp = icmp ugt i32 %a, -1
321  %sub = add i32 %a, 0
322  %sel = select i1 %cmp, i32 %sub, i32 0
323  ret i32 %sel
324}
325
326define i32 @max_sub_ugt_cmiss(i32 %a) {
327; CHECK-LABEL: @max_sub_ugt_cmiss(
328; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 1
329; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -2
330; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
331; CHECK-NEXT:    ret i32 [[SEL]]
332;
333  %cmp = icmp ugt i32 %a, 1
334  %sub = add i32 %a, -2
335  %sel = select i1 %cmp, i32 %sub, i32 0
336  ret i32 %sel
337}
338
339define i32 @max_sub_ult_c1(i32 %a) {
340; CHECK-LABEL: @max_sub_ult_c1(
341; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
342; CHECK-NEXT:    [[SEL:%.*]] = sext i1 [[CMP]] to i32
343; CHECK-NEXT:    ret i32 [[SEL]]
344;
345  %cmp = icmp ult i32 %a, 1
346  %sub = add i32 %a, -1
347  %sel = select i1 %cmp, i32 %sub, i32 0
348  ret i32 %sel
349}
350
351define i32 @max_sub_ult_c2(i32 %a) {
352; CHECK-LABEL: @max_sub_ult_c2(
353; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 2, i32 [[A:%.*]])
354; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i32 0, [[TMP1]]
355; CHECK-NEXT:    ret i32 [[TMP2]]
356;
357  %cmp = icmp ult i32 %a, 2
358  %sub = add i32 %a, -2
359  %sel = select i1 %cmp, i32 %sub, i32 0
360  ret i32 %sel
361}
362
363define i32 @max_sub_ult_c2_oneuseicmp(i32 %a) {
364; CHECK-LABEL: @max_sub_ult_c2_oneuseicmp(
365; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 2
366; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 2, i32 [[A]])
367; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i32 0, [[TMP1]]
368; CHECK-NEXT:    call void @usei1(i1 [[CMP]])
369; CHECK-NEXT:    ret i32 [[TMP2]]
370;
371  %cmp = icmp ult i32 %a, 2
372  %sub = add i32 %a, -2
373  %sel = select i1 %cmp, i32 %sub, i32 0
374  call void @usei1(i1 %cmp)
375  ret i32 %sel
376}
377
378define i32 @max_sub_ult_c2_oneusesub(i32 %a) {
379; CHECK-LABEL: @max_sub_ult_c2_oneusesub(
380; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A:%.*]], -2
381; CHECK-NEXT:    [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 2, i32 [[A]])
382; CHECK-NEXT:    [[TMP2:%.*]] = sub nsw i32 0, [[TMP1]]
383; CHECK-NEXT:    call void @usei32(i32 [[SUB]])
384; CHECK-NEXT:    ret i32 [[TMP2]]
385;
386  %cmp = icmp ult i32 %a, 2
387  %sub = add i32 %a, -2
388  %sel = select i1 %cmp, i32 %sub, i32 0
389  call void @usei32(i32 %sub)
390  ret i32 %sel
391}
392
393define i32 @max_sub_ult_c32(i32 %a) {
394; CHECK-LABEL: @max_sub_ult_c32(
395; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3
396; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -2
397; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
398; CHECK-NEXT:    ret i32 [[SEL]]
399;
400  %cmp = icmp ult i32 %a, 3
401  %sub = add i32 %a, -2
402  %sel = select i1 %cmp, i32 %sub, i32 0
403  ret i32 %sel
404}
405
406define i32 @max_sub_ugt_c32(i32 %a) {
407; CHECK-LABEL: @max_sub_ugt_c32(
408; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3
409; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -2
410; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
411; CHECK-NEXT:    ret i32 [[SEL]]
412;
413  %cmp = icmp ugt i32 3, %a
414  %sub = add i32 %a, -2
415  %sel = select i1 %cmp, i32 %sub, i32 0
416  ret i32 %sel
417}
418
419define i32 @max_sub_uge_c32(i32 %a) {
420; CHECK-LABEL: @max_sub_uge_c32(
421; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3
422; CHECK-NEXT:    [[SUB:%.*]] = add i32 [[A]], -2
423; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
424; CHECK-NEXT:    ret i32 [[SEL]]
425;
426  %cmp = icmp uge i32 2, %a
427  %sub = add i32 %a, -2
428  %sel = select i1 %cmp, i32 %sub, i32 0
429  ret i32 %sel
430}
431
432define i32 @max_sub_ult_c12(i32 %a) {
433; CHECK-LABEL: @max_sub_ult_c12(
434; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
435; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP]], i32 -2, i32 0
436; CHECK-NEXT:    ret i32 [[SEL]]
437;
438  %cmp = icmp ult i32 %a, 1
439  %sub = add i32 %a, -2
440  %sel = select i1 %cmp, i32 %sub, i32 0
441  ret i32 %sel
442}
443
444define i32 @max_sub_ult_c0(i32 %a) {
445; CHECK-LABEL: @max_sub_ult_c0(
446; CHECK-NEXT:    ret i32 0
447;
448  %cmp = icmp ult i32 %a, 0
449  %sub = add i32 %a, -1
450  %sel = select i1 %cmp, i32 %sub, i32 0
451  ret i32 %sel
452}
453
454