1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -passes=instcombine -S < %s | FileCheck %s
4 ; Canonicalization of unsigned saturated subtraction idioms to
5 ; usub.sat() intrinsics is tested here.
8 declare void @usei32(i32)
9 declare void @usei1(i1)
11 ; (a > b) ? a - b : 0 -> usub.sat(a, b)
13 define i64 @max_sub_ugt(i64 %a, i64 %b) {
14 ; CHECK-LABEL: @max_sub_ugt(
15 ; CHECK-NEXT: [[SEL:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
16 ; CHECK-NEXT: ret i64 [[SEL]]
18 %cmp = icmp ugt i64 %a, %b
20 %sel = select i1 %cmp, i64 %sub ,i64 0
24 ; (a >= b) ? a - b : 0 -> usub.sat(a, b)
26 define i64 @max_sub_uge(i64 %a, i64 %b) {
27 ; CHECK-LABEL: @max_sub_uge(
28 ; CHECK-NEXT: [[SEL:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
29 ; CHECK-NEXT: ret i64 [[SEL]]
31 %cmp = icmp uge i64 %a, %b
33 %sel = select i1 %cmp, i64 %sub ,i64 0
37 define 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: [[SEL:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
41 ; CHECK-NEXT: call void @use(i64 [[SUB]])
42 ; CHECK-NEXT: ret i64 [[SEL]]
44 %cmp = icmp uge i64 %a, %b
46 %sel = select i1 %cmp, i64 %sub ,i64 0
47 call void @use(i64 %sub)
51 define 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: [[SEL:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
55 ; CHECK-NEXT: call void @usei1(i1 [[CMP]])
56 ; CHECK-NEXT: ret i64 [[SEL]]
58 %cmp = icmp uge i64 %a, %b
60 %sel = select i1 %cmp, i64 %sub ,i64 0
61 call void @usei1(i1 %cmp)
65 define 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: [[SEL:%.*]] = 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 [[SEL]]
74 %cmp = icmp uge i64 %a, %b
76 %sel = select i1 %cmp, i64 %sub ,i64 0
77 call void @use(i64 %sub)
78 call void @usei1(i1 %cmp)
82 ; Again, with vectors:
83 ; (a > b) ? a - b : 0 -> usub.sat(a, b)
85 define <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: [[SEL:%.*]] = call <4 x i32> @llvm.usub.sat.v4i32(<4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]])
88 ; CHECK-NEXT: ret <4 x i32> [[SEL]]
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
96 ; Use extra ops to thwart icmp swapping canonicalization.
97 ; (b < a) ? a - b : 0 -> usub.sat(a, b)
99 define i64 @max_sub_ult(i64 %a, i64 %b) {
100 ; CHECK-LABEL: @max_sub_ult(
101 ; CHECK-NEXT: [[SEL:%.*]] = 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 [[SEL]]
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)
114 ; (b > a) ? 0 : a - b -> usub.sat(a, b)
116 define i64 @max_sub_ugt_sel_swapped(i64 %a, i64 %b) {
117 ; CHECK-LABEL: @max_sub_ugt_sel_swapped(
118 ; CHECK-NEXT: [[SEL:%.*]] = 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 [[SEL]]
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)
131 ; (a < b) ? 0 : a - b -> usub.sat(a, b)
133 define i64 @max_sub_ult_sel_swapped(i64 %a, i64 %b) {
134 ; CHECK-LABEL: @max_sub_ult_sel_swapped(
135 ; CHECK-NEXT: [[SEL:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A:%.*]], i64 [[B:%.*]])
136 ; CHECK-NEXT: ret i64 [[SEL]]
138 %cmp = icmp ult i64 %a, %b
139 %sub = sub i64 %a, %b
140 %sel = select i1 %cmp, i64 0 ,i64 %sub
144 ; ((a > b) ? b - a : 0) -> -usub.sat(a, b)
146 define 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: [[SEL:%.*]] = 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 [[SEL]]
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)
162 ; ((b < a) ? b - a : 0) -> -usub.sat(a, b)
164 define 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: [[SEL:%.*]] = sub i64 0, [[TMP1]]
168 ; CHECK-NEXT: ret i64 [[SEL]]
170 %cmp = icmp ult i64 %b, %a
171 %sub = sub i64 %b, %a
172 %sel = select i1 %cmp, i64 %sub ,i64 0
176 ; ((b > a) ? 0 : b - a) -> -usub.sat(a, b)
178 define 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: [[SEL:%.*]] = sub i64 0, [[TMP1]]
182 ; CHECK-NEXT: ret i64 [[SEL]]
184 %cmp = icmp ugt i64 %b, %a
185 %sub = sub i64 %b, %a
186 %sel = select i1 %cmp, i64 0 ,i64 %sub
190 define 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: [[SEL:%.*]] = sub i64 0, [[TMP1]]
195 ; CHECK-NEXT: call void @usei1(i1 [[CMP]])
196 ; CHECK-NEXT: ret i64 [[SEL]]
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)
205 define 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: [[SEL:%.*]] = sub i64 0, [[TMP1]]
210 ; CHECK-NEXT: call void @use(i64 [[SUB]])
211 ; CHECK-NEXT: ret i64 [[SEL]]
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)
220 define 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]]
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)
237 ; ((a < b) ? 0 : b - a) -> -usub.sat(a, b)
239 define 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: [[SEL:%.*]] = 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 [[SEL]]
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)
255 define i32 @max_sub_ugt_c1(i32 %a) {
256 ; CHECK-LABEL: @max_sub_ugt_c1(
257 ; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 1)
258 ; CHECK-NEXT: ret i32 [[SEL]]
260 %cmp = icmp ugt i32 %a, 1
261 %sub = add i32 %a, -1
262 %sel = select i1 %cmp, i32 %sub ,i32 0
266 define i32 @max_sub_ugt_c01(i32 %a) {
267 ; CHECK-LABEL: @max_sub_ugt_c01(
268 ; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 1)
269 ; CHECK-NEXT: ret i32 [[SEL]]
271 %cmp = icmp ugt i32 %a, 0
272 %sub = add i32 %a, -1
273 %sel = select i1 %cmp, i32 %sub ,i32 0
277 define i32 @max_sub_ugt_c10(i32 %a) {
278 ; CHECK-LABEL: @max_sub_ugt_c10(
279 ; CHECK-NEXT: [[SEL:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[A:%.*]], i32 10)
280 ; CHECK-NEXT: ret i32 [[SEL]]
282 %cmp = icmp ugt i32 %a, 10
283 %sub = add i32 %a, -10
284 %sel = select i1 %cmp, i32 %sub, i32 0
288 define i32 @max_sub_ugt_c910(i32 %a) {
289 ; CHECK-LABEL: @max_sub_ugt_c910(
290 ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 9
291 ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -10
292 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
293 ; CHECK-NEXT: ret i32 [[SEL]]
295 %cmp = icmp ugt i32 %a, 9
296 %sub = add i32 %a, -10
297 %sel = select i1 %cmp, i32 %sub, i32 0
301 define i32 @max_sub_ugt_c1110(i32 %a) {
302 ; CHECK-LABEL: @max_sub_ugt_c1110(
303 ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 11
304 ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -10
305 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
306 ; CHECK-NEXT: ret i32 [[SEL]]
308 %cmp = icmp ugt i32 %a, 11
309 %sub = add i32 %a, -10
310 %sel = select i1 %cmp, i32 %sub, i32 0
314 define i32 @max_sub_ugt_c0(i32 %a) {
315 ; CHECK-LABEL: @max_sub_ugt_c0(
316 ; CHECK-NEXT: ret i32 0
318 %cmp = icmp ugt i32 %a, -1
320 %sel = select i1 %cmp, i32 %sub, i32 0
324 define i32 @max_sub_ugt_cmiss(i32 %a) {
325 ; CHECK-LABEL: @max_sub_ugt_cmiss(
326 ; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[A:%.*]], 1
327 ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2
328 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
329 ; CHECK-NEXT: ret i32 [[SEL]]
331 %cmp = icmp ugt i32 %a, 1
332 %sub = add i32 %a, -2
333 %sel = select i1 %cmp, i32 %sub, i32 0
337 define i32 @max_sub_ult_c1(i32 %a) {
338 ; CHECK-LABEL: @max_sub_ult_c1(
339 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
340 ; CHECK-NEXT: [[SEL:%.*]] = sext i1 [[CMP]] to i32
341 ; CHECK-NEXT: ret i32 [[SEL]]
343 %cmp = icmp ult i32 %a, 1
344 %sub = add i32 %a, -1
345 %sel = select i1 %cmp, i32 %sub, i32 0
349 define i32 @max_sub_ult_c2(i32 %a) {
350 ; CHECK-LABEL: @max_sub_ult_c2(
351 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 2, i32 [[A:%.*]])
352 ; CHECK-NEXT: [[SEL:%.*]] = sub nsw i32 0, [[TMP1]]
353 ; CHECK-NEXT: ret i32 [[SEL]]
355 %cmp = icmp ult i32 %a, 2
356 %sub = add i32 %a, -2
357 %sel = select i1 %cmp, i32 %sub, i32 0
361 define i32 @max_sub_ult_c2_oneuseicmp(i32 %a) {
362 ; CHECK-LABEL: @max_sub_ult_c2_oneuseicmp(
363 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 2
364 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 2, i32 [[A]])
365 ; CHECK-NEXT: [[SEL:%.*]] = sub nsw i32 0, [[TMP1]]
366 ; CHECK-NEXT: call void @usei1(i1 [[CMP]])
367 ; CHECK-NEXT: ret i32 [[SEL]]
369 %cmp = icmp ult i32 %a, 2
370 %sub = add i32 %a, -2
371 %sel = select i1 %cmp, i32 %sub, i32 0
372 call void @usei1(i1 %cmp)
376 define i32 @max_sub_ult_c2_oneusesub(i32 %a) {
377 ; CHECK-LABEL: @max_sub_ult_c2_oneusesub(
378 ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A:%.*]], -2
379 ; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.usub.sat.i32(i32 2, i32 [[A]])
380 ; CHECK-NEXT: [[SEL:%.*]] = sub nsw i32 0, [[TMP1]]
381 ; CHECK-NEXT: call void @usei32(i32 [[SUB]])
382 ; CHECK-NEXT: ret i32 [[SEL]]
384 %cmp = icmp ult i32 %a, 2
385 %sub = add i32 %a, -2
386 %sel = select i1 %cmp, i32 %sub, i32 0
387 call void @usei32(i32 %sub)
391 define i32 @max_sub_ult_c32(i32 %a) {
392 ; CHECK-LABEL: @max_sub_ult_c32(
393 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3
394 ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2
395 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
396 ; CHECK-NEXT: ret i32 [[SEL]]
398 %cmp = icmp ult i32 %a, 3
399 %sub = add i32 %a, -2
400 %sel = select i1 %cmp, i32 %sub, i32 0
404 define i32 @max_sub_ugt_c32(i32 %a) {
405 ; CHECK-LABEL: @max_sub_ugt_c32(
406 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3
407 ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2
408 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
409 ; CHECK-NEXT: ret i32 [[SEL]]
411 %cmp = icmp ugt i32 3, %a
412 %sub = add i32 %a, -2
413 %sel = select i1 %cmp, i32 %sub, i32 0
417 define i32 @max_sub_uge_c32(i32 %a) {
418 ; CHECK-LABEL: @max_sub_uge_c32(
419 ; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A:%.*]], 3
420 ; CHECK-NEXT: [[SUB:%.*]] = add i32 [[A]], -2
421 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 [[SUB]], i32 0
422 ; CHECK-NEXT: ret i32 [[SEL]]
424 %cmp = icmp uge i32 2, %a
425 %sub = add i32 %a, -2
426 %sel = select i1 %cmp, i32 %sub, i32 0
430 define i32 @max_sub_ult_c12(i32 %a) {
431 ; CHECK-LABEL: @max_sub_ult_c12(
432 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], 0
433 ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i32 -2, i32 0
434 ; CHECK-NEXT: ret i32 [[SEL]]
436 %cmp = icmp ult i32 %a, 1
437 %sub = add i32 %a, -2
438 %sel = select i1 %cmp, i32 %sub, i32 0
442 define i32 @max_sub_ult_c0(i32 %a) {
443 ; CHECK-LABEL: @max_sub_ult_c0(
444 ; CHECK-NEXT: ret i32 0
446 %cmp = icmp ult i32 %a, 0
447 %sub = add i32 %a, -1
448 %sel = select i1 %cmp, i32 %sub, i32 0