xref: /llvm-project/mlir/test/Dialect/Arith/int-range-interface.mlir (revision 9ab16d49c99966f33900d68ed5370f19927ca52c)
1// RUN: mlir-opt -int-range-optimizations -canonicalize %s | FileCheck %s
2
3// CHECK-LABEL: func @add_min_max
4// CHECK: %[[c3:.*]] = arith.constant 3 : index
5// CHECK: return %[[c3]]
6func.func @add_min_max(%a: index, %b: index) -> index {
7    %c1 = arith.constant 1 : index
8    %c2 = arith.constant 2 : index
9    %0 = arith.minsi %a, %c1 : index
10    %1 = arith.maxsi %0, %c1 : index
11    %2 = arith.minui %b, %c2 : index
12    %3 = arith.maxui %2, %c2 : index
13    %4 = arith.addi %1, %3 : index
14    func.return %4 : index
15}
16
17// CHECK-LABEL: func @add_lower_bound
18// CHECK: %[[sge:.*]] = arith.cmpi sge
19// CHECK: return %[[sge]]
20func.func @add_lower_bound(%a : i32, %b : i32) -> i1 {
21    %c1 = arith.constant 1 : i32
22    %c2 = arith.constant 2 : i32
23    %0 = arith.maxsi %a, %c1 : i32
24    %1 = arith.maxsi %b, %c1 : i32
25    %2 = arith.addi %0, %1 : i32
26    %3 = arith.cmpi sge, %2, %c2 : i32
27    %4 = arith.cmpi uge, %2, %c2 : i32
28    %5 = arith.andi %3, %4 : i1
29    func.return %5 : i1
30}
31
32// CHECK-LABEL: func @sub_signed_vs_unsigned
33// CHECK-NOT: arith.cmpi sle
34// CHECK: %[[unsigned:.*]] = arith.cmpi ule
35// CHECK: return %[[unsigned]] : i1
36func.func @sub_signed_vs_unsigned(%v : i64) -> i1 {
37    %c0 = arith.constant 0 : i64
38    %c2 = arith.constant 2 : i64
39    %c-5 = arith.constant -5 : i64
40    %0 = arith.minsi %v, %c2 : i64
41    %1 = arith.maxsi %0, %c-5 : i64
42    %2 = arith.subi %1, %c2 : i64
43    %3 = arith.cmpi sle, %2, %c0 : i64
44    %4 = arith.cmpi ule, %2, %c0 : i64
45    %5 = arith.andi %3, %4 : i1
46    func.return %5 : i1
47}
48
49// CHECK-LABEL: func @multiply_negatives
50// CHECK: %[[false:.*]] = arith.constant false
51// CHECK: return %[[false]]
52func.func @multiply_negatives(%a : index, %b : index) -> i1 {
53    %c2 = arith.constant 2 : index
54    %c3 = arith.constant 3 : index
55    %c_1 = arith.constant -1 : index
56    %c_2 = arith.constant -2 : index
57    %c_4 = arith.constant -4 : index
58    %c_12 = arith.constant -12 : index
59    %0 = arith.maxsi %a, %c2 : index
60    %1 = arith.minsi %0, %c3 : index
61    %2 = arith.minsi %b, %c_1 : index
62    %3 = arith.maxsi %2, %c_4 : index
63    %4 = arith.muli %1, %3 : index
64    %5 = arith.cmpi slt, %4, %c_12 : index
65    %6 = arith.cmpi slt, %c_1, %4 : index
66    %7 = arith.ori %5, %6 : i1
67    func.return %7 : i1
68}
69
70// CHECK-LABEL: func @multiply_unsigned_bounds
71// CHECK: %[[true:.*]] = arith.constant true
72// CHECK: return %[[true]]
73func.func @multiply_unsigned_bounds(%a : i16, %b : i16) -> i1 {
74    %c0 = arith.constant 0 : i16
75    %c4 = arith.constant 4 : i16
76    %c_mask = arith.constant 0x3fff : i16
77    %c_bound = arith.constant 0xfffc : i16
78    %0 = arith.andi %a, %c_mask : i16
79    %1 = arith.minui %b, %c4 : i16
80    %2 = arith.muli %0, %1 : i16
81    %3 = arith.cmpi uge, %2, %c0 : i16
82    %4 = arith.cmpi ule, %2, %c_bound : i16
83    %5 = arith.andi %3, %4 : i1
84    func.return %5 : i1
85}
86
87// CHECK-LABEL: @for_loop_with_increasing_arg
88// CHECK: %[[ret:.*]] = arith.cmpi ule
89// CHECK: return %[[ret]]
90func.func @for_loop_with_increasing_arg() -> i1 {
91    %c0 = arith.constant 0 : index
92    %c1 = arith.constant 1 : index
93    %c4 = arith.constant 4 : index
94    %c16 = arith.constant 16 : index
95    %0 = scf.for %arg0 = %c0 to %c4 step %c1 iter_args(%arg1 = %c0) -> index {
96        %10 = arith.addi %arg0, %arg1 : index
97        scf.yield %10 : index
98    }
99    %1 = arith.cmpi ule, %0, %c16 : index
100    func.return %1 : i1
101}
102
103// CHECK-LABEL: @for_loop_with_constant_result
104// CHECK: %[[true:.*]] = arith.constant true
105// CHECK: return %[[true]]
106func.func @for_loop_with_constant_result() -> i1 {
107    %c0 = arith.constant 0 : index
108    %c1 = arith.constant 1 : index
109    %c4 = arith.constant 4 : index
110    %true = arith.constant true
111    %0 = scf.for %arg0 = %c0 to %c4 step %c1 iter_args(%arg1 = %true) -> i1 {
112        %10 = arith.cmpi ule, %arg0, %c4 : index
113        %11 = arith.andi %10, %arg1 : i1
114        scf.yield %11 : i1
115    }
116    func.return %0 : i1
117}
118
119// Test to catch a bug present in some versions of the data flow analysis
120// CHECK-LABEL: func @while_false
121// CHECK: %[[false:.*]] = arith.constant false
122// CHECK: scf.condition(%[[false]])
123func.func @while_false(%arg0 : index) -> index {
124    %c0 = arith.constant 0 : index
125    %c1 = arith.constant 1 : index
126    %c2 = arith.constant 2 : index
127    %0 = arith.divui %arg0, %c2 : index
128    %1 = scf.while (%arg1 = %0) : (index) -> index {
129        %2 = arith.cmpi slt, %arg1, %c0 : index
130        scf.condition(%2) %arg1 : index
131    } do {
132    ^bb0(%arg2 : index):
133        scf.yield %c2 : index
134    }
135    func.return %1 : index
136}
137
138// CHECK-LABEL: func @div_bounds_positive
139// CHECK: %[[true:.*]] = arith.constant true
140// CHECK: return %[[true]]
141func.func @div_bounds_positive(%arg0 : index) -> i1 {
142    %c0 = arith.constant 0 : index
143    %c2 = arith.constant 2 : index
144    %c4 = arith.constant 4 : index
145    %0 = arith.maxsi %arg0, %c2 : index
146    %1 = arith.divsi %c4, %0 : index
147    %2 = arith.divui %c4, %0 : index
148
149    %3 = arith.cmpi sge, %1, %c0 : index
150    %4 = arith.cmpi sle, %1, %c2 : index
151    %5 = arith.cmpi sge, %2, %c0 : index
152    %6 = arith.cmpi sle, %1, %c2 : index
153
154    %7 = arith.andi %3, %4 : i1
155    %8 = arith.andi %7, %5 : i1
156    %9 = arith.andi %8, %6 : i1
157    func.return %9 : i1
158}
159
160// CHECK-LABEL: func @div_bounds_negative
161// CHECK: %[[true:.*]] = arith.constant true
162// CHECK: return %[[true]]
163func.func @div_bounds_negative(%arg0 : index) -> i1 {
164    %c0 = arith.constant 0 : index
165    %c_2 = arith.constant -2 : index
166    %c4 = arith.constant 4 : index
167    %0 = arith.minsi %arg0, %c_2 : index
168    %1 = arith.divsi %c4, %0 : index
169    %2 = arith.divui %c4, %0 : index
170
171    %3 = arith.cmpi sle, %1, %c0 : index
172    %4 = arith.cmpi sge, %1, %c_2 : index
173    %5 = arith.cmpi eq, %2, %c0 : index
174
175    %7 = arith.andi %3, %4 : i1
176    %8 = arith.andi %7, %5 : i1
177    func.return %8 : i1
178}
179
180// CHECK-LABEL: func @div_zero_undefined
181// CHECK: %[[true:.*]] = arith.constant true
182// CHECK: return %[[true]]
183func.func @div_zero_undefined(%arg0 : index) -> i1 {
184    %c0 = arith.constant 0 : index
185    %c1 = arith.constant 1 : index
186    %c4 = arith.constant 4 : index
187    %0 = arith.andi %arg0, %c1 : index
188    %1 = arith.divui %c4, %0 : index
189    %2 = arith.cmpi ule, %1, %c4 : index
190    func.return %2 : i1
191}
192
193// CHECK-LABEL: func @div_refine_min
194// CHECK: %[[true:.*]] = arith.constant true
195// CHECK: return %[[true]]
196func.func @div_refine_min(%arg0 : index) -> i1 {
197    %c0 = arith.constant 1 : index
198    %c1 = arith.constant 2 : index
199    %c4 = arith.constant 4 : index
200    %0 = arith.andi %arg0, %c1 : index
201    %1 = arith.divui %c4, %0 : index
202    %2 = arith.cmpi uge, %1, %c0 : index
203    func.return %2 : i1
204}
205
206// CHECK-LABEL: func @ceil_divui
207// CHECK: %[[ret:.*]] = arith.cmpi eq
208// CHECK: return %[[ret]]
209func.func @ceil_divui(%arg0 : index) -> i1 {
210    %c0 = arith.constant 0 : index
211    %c1 = arith.constant 1 : index
212    %c3 = arith.constant 3 : index
213    %c4 = arith.constant 4 : index
214
215    %0 = arith.minui %arg0, %c3 : index
216    %1 = arith.maxui %0, %c1 : index
217    %2 = arith.ceildivui %1, %c4 : index
218    %3 = arith.cmpi eq, %2, %c1 : index
219
220    %4 = arith.maxui %0, %c0 : index
221    %5 = arith.ceildivui %4, %c4 : index
222    %6 = arith.cmpi eq, %5, %c1 : index
223    %7 = arith.andi %3, %6 : i1
224    func.return %7 : i1
225}
226
227// CHECK-LABEL: func @ceil_divsi
228// CHECK: %[[ret:.*]] = arith.cmpi eq
229// CHECK: return %[[ret]]
230func.func @ceil_divsi(%arg0 : index) -> i1 {
231    %c0 = arith.constant 0 : index
232    %c1 = arith.constant 1 : index
233    %c3 = arith.constant 3 : index
234    %c4 = arith.constant 4 : index
235    %c-4 = arith.constant -4 : index
236
237    %0 = arith.minsi %arg0, %c3 : index
238    %1 = arith.maxsi %0, %c1 : index
239    %2 = arith.ceildivsi %1, %c4 : index
240    %3 = arith.cmpi eq, %2, %c1 : index
241    %4 = arith.ceildivsi %1, %c-4 : index
242    %5 = arith.cmpi eq, %4, %c0 : index
243    %6 = arith.andi %3, %5 : i1
244
245    %7 = arith.maxsi %0, %c0 : index
246    %8 = arith.ceildivsi %7, %c4 : index
247    %9 = arith.cmpi eq, %8, %c1 : index
248    %10 = arith.andi %6, %9 : i1
249    func.return %10 : i1
250}
251
252// There was a bug, which was causing this expr errorneously fold to constant
253// CHECK-LABEL: func @ceil_divsi_full_range
254// CHECK-SAME: (%[[arg:.*]]: index)
255// CHECK: %[[c64:.*]] = arith.constant 64 : index
256// CHECK: %[[ret:.*]] = arith.ceildivsi %[[arg]], %[[c64]] : index
257// CHECK: return %[[ret]]
258func.func @ceil_divsi_full_range(%6: index) -> index {
259  %c64 = arith.constant 64 : index
260  %55 = arith.ceildivsi %6, %c64 : index
261  return %55 : index
262}
263
264// CHECK-LABEL: func @ceil_divsi_intmin_bug_115293
265// CHECK: %[[ret:.*]] = arith.constant true
266// CHECK: return %[[ret]]
267func.func @ceil_divsi_intmin_bug_115293() -> i1 {
268    %intMin_i64 = test.with_bounds { smin = -9223372036854775808 : si64, smax = -9223372036854775808 : si64, umin = 9223372036854775808 : ui64, umax = 9223372036854775808 : ui64 } : i64
269    %denom_i64 = test.with_bounds { smin = 1189465982 : si64, smax = 1189465982 : si64, umin = 1189465982 : ui64, umax = 1189465982 : ui64 } : i64
270    %res_i64 = test.with_bounds { smin = 7754212542 : si64, smax = 7754212542 : si64, umin = 7754212542 : ui64, umax = 7754212542 : ui64 }  : i64
271
272    %0 = arith.ceildivsi %intMin_i64, %denom_i64 : i64
273    %1 = arith.cmpi eq, %0, %res_i64 : i64
274    func.return %1 : i1
275}
276
277// CHECK-LABEL: func @floor_divsi
278// CHECK: %[[true:.*]] = arith.constant true
279// CHECK: return %[[true]]
280func.func @floor_divsi(%arg0 : index) -> i1 {
281    %c4 = arith.constant 4 : index
282    %c-1 = arith.constant -1 : index
283    %c-3 = arith.constant -3 : index
284    %c-4 = arith.constant -4 : index
285
286    %0 = arith.minsi %arg0, %c-1 : index
287    %1 = arith.maxsi %0, %c-4 : index
288    %2 = arith.floordivsi %1, %c4 : index
289    %3 = arith.cmpi eq, %2, %c-1 : index
290    func.return %3 : i1
291}
292
293// CHECK-LABEL: func @remui_base
294// CHECK: %[[true:.*]] = arith.constant true
295// CHECK: return %[[true]]
296func.func @remui_base(%arg0 : index, %arg1 : index ) -> i1 {
297    %c2 = arith.constant 2 : index
298    %c4 = arith.constant 4 : index
299
300    %0 = arith.minui %arg1, %c4 : index
301    %1 = arith.maxui %0, %c2 : index
302    %2 = arith.remui %arg0, %1 : index
303    %3 = arith.cmpi ult, %2, %c4 : index
304    func.return %3 : i1
305}
306
307// CHECK-LABEL: func @remui_base_maybe_zero
308// CHECK: %[[true:.*]] = arith.constant true
309// CHECK: return %[[true]]
310func.func @remui_base_maybe_zero(%arg0 : index, %arg1 : index ) -> i1 {
311    %c4 = arith.constant 4 : index
312    %c5 = arith.constant 5 : index
313
314    %0 = arith.minui %arg1, %c4 : index
315    %1 = arith.remui %arg0, %0 : index
316    %2 = arith.cmpi ult, %1, %c5 : index
317    func.return %2 : i1
318}
319
320// CHECK-LABEL: func @remsi_base
321// CHECK: %[[ret:.*]] = arith.cmpi sge
322// CHECK: return %[[ret]]
323func.func @remsi_base(%arg0 : index, %arg1 : index ) -> i1 {
324    %c0 = arith.constant 0 : index
325    %c2 = arith.constant 2 : index
326    %c4 = arith.constant 4 : index
327    %c-4 = arith.constant -4 : index
328    %true = arith.constant true
329
330    %0 = arith.minsi %arg1, %c4 : index
331    %1 = arith.maxsi %0, %c2 : index
332    %2 = arith.remsi %arg0, %1 : index
333    %3 = arith.cmpi sgt, %2, %c-4 : index
334    %4 = arith.cmpi slt, %2, %c4 : index
335    %5 = arith.cmpi sge, %2, %c0 : index
336    %6 = arith.andi %3, %4 : i1
337    %7 = arith.andi %5, %6 : i1
338    func.return %7 : i1
339}
340
341// CHECK-LABEL: func @remsi_positive
342// CHECK: %[[true:.*]] = arith.constant true
343// CHECK: return %[[true]]
344func.func @remsi_positive(%arg0 : index, %arg1 : index ) -> i1 {
345    %c0 = arith.constant 0 : index
346    %c2 = arith.constant 2 : index
347    %c4 = arith.constant 4 : index
348    %true = arith.constant true
349
350    %0 = arith.minsi %arg1, %c4 : index
351    %1 = arith.maxsi %0, %c2 : index
352    %2 = arith.maxsi %arg0, %c0 : index
353    %3 = arith.remsi %2, %1 : index
354    %4 = arith.cmpi sge, %3, %c0 : index
355    %5 = arith.cmpi slt, %3, %c4 : index
356    %6 = arith.andi %4, %5 : i1
357    func.return %6 : i1
358}
359
360// CHECK-LABEL: func @remui_restricted
361// CHECK: %[[true:.*]] = arith.constant true
362// CHECK: return %[[true]]
363func.func @remui_restricted(%arg0 : index) -> i1 {
364    %c2 = arith.constant 2 : index
365    %c3 = arith.constant 3 : index
366    %c4 = arith.constant 4 : index
367
368    %0 = arith.minui %arg0, %c3 : index
369    %1 = arith.maxui %0, %c2 : index
370    %2 = arith.remui %1, %c4 : index
371    %3 = arith.cmpi ule, %2, %c3 : index
372    %4 = arith.cmpi uge, %2, %c2 : index
373    %5 = arith.andi %3, %4 : i1
374    func.return %5 : i1
375}
376
377// CHECK-LABEL: func @remsi_restricted
378// CHECK: %[[true:.*]] = arith.constant true
379// CHECK: return %[[true]]
380func.func @remsi_restricted(%arg0 : index) -> i1 {
381    %c2 = arith.constant 2 : index
382    %c3 = arith.constant 3 : index
383    %c-4 = arith.constant -4 : index
384
385    %0 = arith.minsi %arg0, %c3 : index
386    %1 = arith.maxsi %0, %c2 : index
387    %2 = arith.remsi %1, %c-4 : index
388    %3 = arith.cmpi ule, %2, %c3 : index
389    %4 = arith.cmpi uge, %2, %c2 : index
390    %5 = arith.andi %3, %4 : i1
391    func.return %5 : i1
392}
393
394// CHECK-LABEL: func @remui_restricted_fails
395// CHECK: %[[ret:.*]] = arith.cmpi ne
396// CHECK: return %[[ret]]
397func.func @remui_restricted_fails(%arg0 : index) -> i1 {
398    %c2 = arith.constant 2 : index
399    %c3 = arith.constant 3 : index
400    %c4 = arith.constant 4 : index
401    %c5 = arith.constant 5 : index
402
403    %0 = arith.minui %arg0, %c5 : index
404    %1 = arith.maxui %0, %c3 : index
405    %2 = arith.remui %1, %c4 : index
406    %3 = arith.cmpi ne, %2, %c2 : index
407    func.return %3 : i1
408}
409
410// CHECK-LABEL: func @remsi_restricted_fails
411// CHECK: %[[ret:.*]] = arith.cmpi ne
412// CHECK: return %[[ret]]
413func.func @remsi_restricted_fails(%arg0 : index) -> i1 {
414    %c2 = arith.constant 2 : index
415    %c3 = arith.constant 3 : index
416    %c5 = arith.constant 5 : index
417    %c-4 = arith.constant -4 : index
418
419    %0 = arith.minsi %arg0, %c5 : index
420    %1 = arith.maxsi %0, %c3 : index
421    %2 = arith.remsi %1, %c-4 : index
422    %3 = arith.cmpi ne, %2, %c2 : index
423    func.return %3 : i1
424}
425
426// CHECK-LABEL: func @andi
427// CHECK: %[[ret:.*]] = arith.cmpi ugt
428// CHECK: return %[[ret]]
429func.func @andi(%arg0 : index) -> i1 {
430    %c2 = arith.constant 2 : index
431    %c5 = arith.constant 5 : index
432    %c7 = arith.constant 7 : index
433
434    %0 = arith.minsi %arg0, %c5 : index
435    %1 = arith.maxsi %0, %c2 : index
436    %2 = arith.andi %1, %c7 : index
437    %3 = arith.cmpi ugt, %2, %c5 : index
438    %4 = arith.cmpi ule, %2, %c7 : index
439    %5 = arith.andi %3, %4 : i1
440    func.return %5 : i1
441}
442
443// CHECK-LABEL: func @andi_doesnt_make_nonnegative
444// CHECK: %[[ret:.*]] = arith.cmpi sge
445// CHECK: return %[[ret]]
446func.func @andi_doesnt_make_nonnegative(%arg0 : index) -> i1 {
447    %c0 = arith.constant 0 : index
448    %c1 = arith.constant 1 : index
449    %0 = arith.addi %arg0, %c1 : index
450    %1 = arith.andi %arg0, %0 : index
451    %2 = arith.cmpi sge, %1, %c0 : index
452    func.return %2 : i1
453}
454
455
456// CHECK-LABEL: func @ori
457// CHECK: %[[true:.*]] = arith.constant true
458// CHECK: return %[[true]]
459func.func @ori(%arg0 : i128, %arg1 : i128) -> i1 {
460    %c-1 = arith.constant -1 : i128
461    %c0 = arith.constant 0 : i128
462
463    %0 = arith.minsi %arg1, %c-1 : i128
464    %1 = arith.ori %arg0, %0 : i128
465    %2 = arith.cmpi slt, %1, %c0 : i128
466    func.return %2 : i1
467}
468
469// CHECK-LABEL: func @xori_issue_82168
470// arith.cmpi was erroneously folded to %false, see Issue #82168.
471// CHECK: %[[R:.*]] = arith.cmpi eq, %{{.*}}, %{{.*}} : i64
472// CHECK: return %[[R]]
473func.func @xori_issue_82168() -> i1 {
474    %c0_i64 = arith.constant 0 : i64
475    %c2060639849_i64 = arith.constant 2060639849 : i64
476    %2 = test.with_bounds { umin = 2060639849 : i64, umax = 2060639850 : i64, smin = 2060639849 : i64, smax = 2060639850 : i64 } : i64
477    %3 = arith.xori %2, %c2060639849_i64 : i64
478    %4 = arith.cmpi eq, %3, %c0_i64 : i64
479    func.return %4 : i1
480}
481
482// CHECK-LABEL: func @xori_i1
483//   CHECK-DAG: %[[true:.*]] = arith.constant true
484//   CHECK-DAG: %[[false:.*]] = arith.constant false
485//       CHECK: return %[[true]], %[[false]]
486func.func @xori_i1() -> (i1, i1) {
487    %true = arith.constant true
488    %1 = test.with_bounds { umin = 0 : i1, umax = 0 : i1, smin = 0 : i1, smax = 0 : i1 } : i1
489    %2 = test.with_bounds { umin = 1 : i1, umax = 1 : i1, smin = 1 : i1, smax = 1 : i1 } : i1
490    %3 = arith.xori %1, %true : i1
491    %4 = arith.xori %2, %true : i1
492    func.return %3, %4 : i1, i1
493}
494
495// CHECK-LABEL: func @xori
496// CHECK: %[[false:.*]] = arith.constant false
497// CHECK: return %[[false]]
498func.func @xori(%arg0 : i64, %arg1 : i64) -> i1 {
499    %c0 = arith.constant 0 : i64
500    %c7 = arith.constant 7 : i64
501    %c15 = arith.constant 15 : i64
502    %true = arith.constant true
503
504    %0 = arith.minui %arg0, %c7 : i64
505    %1 = arith.minui %arg1, %c15 : i64
506    %2 = arith.xori %0, %1 : i64
507    %3 = arith.cmpi sle, %2, %c15 : i64
508    %4 = arith.xori %3, %true : i1
509    func.return %4 : i1
510}
511
512// CHECK-LABEL: func @extui
513// CHECK: %[[true:.*]] = arith.constant true
514// CHECK: return %[[true]]
515func.func @extui(%arg0 : i16) -> i1 {
516    %ci16_max = arith.constant 0xffff : i32
517    %0 = arith.extui %arg0 : i16 to i32
518    %1 = arith.cmpi ule, %0, %ci16_max : i32
519    func.return %1 : i1
520}
521
522// CHECK-LABEL: func @extsi
523// CHECK: %[[true:.*]] = arith.constant true
524// CHECK: return %[[true]]
525func.func @extsi(%arg0 : i16) -> i1 {
526    %ci16_smax = arith.constant 0x7fff : i32
527    %ci16_smin = arith.constant 0xffff8000 : i32
528    %0 = arith.extsi %arg0 : i16 to i32
529    %1 = arith.cmpi sle, %0, %ci16_smax : i32
530    %2 = arith.cmpi sge, %0, %ci16_smin : i32
531    %3 = arith.andi %1, %2 : i1
532    func.return %3 : i1
533}
534
535// CHECK-LABEL: func @trunci
536// CHECK: %[[true:.*]] = arith.constant true
537// CHECK: return %[[true]]
538func.func @trunci(%arg0 : i32) -> i1 {
539    %c-14_i32 = arith.constant -14 : i32
540    %c-14_i16 = arith.constant -14 : i16
541    %ci16_smin = arith.constant 0xffff8000 : i32
542    %0 = arith.minsi %arg0, %c-14_i32 : i32
543    %1 = arith.maxsi %0, %ci16_smin : i32
544    %2 = arith.trunci %1 : i32 to i16
545    %3 = arith.cmpi sle, %2, %c-14_i16 : i16
546    %4 = arith.extsi %2 : i16 to i32
547    %5 = arith.cmpi sle, %4, %c-14_i32 : i32
548    %6 = arith.cmpi sge, %4, %ci16_smin : i32
549    %7 = arith.andi %3, %5 : i1
550    %8 = arith.andi %7, %6 : i1
551    func.return %8 : i1
552}
553
554// CHECK-LABEL: func @index_cast
555// CHECK: %[[true:.*]] = arith.constant true
556// CHECK: return %[[true]]
557func.func @index_cast(%arg0 : index) -> i1 {
558    %ci32_smin = arith.constant 0xffffffff80000000 : i64
559    %0 = arith.index_cast %arg0 : index to i32
560    %1 = arith.index_cast %0 : i32 to index
561    %2 = arith.index_cast %ci32_smin : i64 to index
562    %3 = arith.cmpi sge, %1, %2 : index
563    func.return %3 : i1
564}
565
566// CHECK-LABEL: func @shli
567// CHECK: %[[ret:.*]] = arith.cmpi sgt
568// CHECK: return %[[ret]]
569func.func @shli(%arg0 : i32, %arg1 : i1) -> i1 {
570    %c2 = arith.constant 2 : i32
571    %c4 = arith.constant 4 : i32
572    %c8 = arith.constant 8 : i32
573    %c32 = arith.constant 32 : i32
574    %c-1 = arith.constant -1 : i32
575    %c-16 = arith.constant -16 : i32
576    %0 = arith.maxsi %arg0, %c-1 : i32
577    %1 = arith.minsi %0, %c2 : i32
578    %2 = arith.select %arg1, %c2, %c4 : i32
579    %3 = arith.shli %1, %2 : i32
580    %4 = arith.cmpi sge, %3, %c-16 : i32
581    %5 = arith.cmpi sle, %3, %c32 : i32
582    %6 = arith.cmpi sgt, %3, %c8 : i32
583    %7 = arith.andi %4, %5 : i1
584    %8 = arith.andi %7, %6 : i1
585    func.return %8 : i1
586}
587
588// CHECK-LABEL: func @shrui
589// CHECK: %[[ret:.*]] = arith.cmpi uge
590// CHECK: return %[[ret]]
591func.func @shrui(%arg0 : i1) -> i1 {
592    %c2 = arith.constant 2 : i32
593    %c4 = arith.constant 4 : i32
594    %c8 = arith.constant 8 : i32
595    %c32 = arith.constant 32 : i32
596    %0 = arith.select %arg0, %c2, %c4 : i32
597    %1 = arith.shrui %c32, %0 : i32
598    %2 = arith.cmpi ule, %1, %c8 : i32
599    %3 = arith.cmpi uge, %1, %c2 : i32
600    %4 = arith.cmpi uge, %1, %c8 : i32
601    %5 = arith.andi %2, %3 : i1
602    %6 = arith.andi %5, %4 : i1
603    func.return %6 : i1
604}
605
606// CHECK-LABEL: func @shrsi
607// CHECK: %[[ret:.*]] = arith.cmpi slt
608// CHECK: return %[[ret]]
609func.func @shrsi(%arg0 : i32, %arg1 : i1) -> i1 {
610    %c2 = arith.constant 2 : i32
611    %c4 = arith.constant 4 : i32
612    %c8 = arith.constant 8 : i32
613    %c32 = arith.constant 32 : i32
614    %c-8 = arith.constant -8 : i32
615    %c-32 = arith.constant -32 : i32
616    %0 = arith.maxsi %arg0, %c-32 : i32
617    %1 = arith.minsi %0, %c32 : i32
618    %2 = arith.select %arg1, %c2, %c4 : i32
619    %3 = arith.shrsi %1, %2 : i32
620    %4 = arith.cmpi sge, %3, %c-8 : i32
621    %5 = arith.cmpi sle, %3, %c8 : i32
622    %6 = arith.cmpi slt, %3, %c2 : i32
623    %7 = arith.andi %4, %5 : i1
624    %8 = arith.andi %7, %6 : i1
625    func.return %8 : i1
626}
627
628// CHECK-LABEL: func @no_aggressive_eq
629// CHECK: %[[ret:.*]] = arith.cmpi eq
630// CHECK: return %[[ret]]
631func.func @no_aggressive_eq(%arg0 : index) -> i1 {
632    %c1 = arith.constant 1 : index
633    %0 = arith.andi %arg0, %c1 : index
634    %1 = arith.minui %arg0, %c1 : index
635    %2 = arith.cmpi eq, %0, %1 : index
636    func.return %2 : i1
637}
638
639// CHECK-LABEL: func @select_union
640// CHECK: %[[ret:.*]] = arith.cmpi ne
641// CHECK: return %[[ret]]
642
643func.func @select_union(%arg0 : index, %arg1 : i1) -> i1 {
644    %c64 = arith.constant 64 : index
645    %c100 = arith.constant 100 : index
646    %c128 = arith.constant 128 : index
647    %c192 = arith.constant 192 : index
648    %0 = arith.remui %arg0, %c64 : index
649    %1 = arith.addi %0, %c128 : index
650    %2 = arith.select %arg1, %0, %1 : index
651    %3 = arith.cmpi slt, %2, %c192 : index
652    %4 = arith.cmpi ne, %c100, %2 : index
653    %5 = arith.andi %3, %4 : i1
654    func.return %5 : i1
655}
656
657// CHECK-LABEL: func @if_union
658// CHECK: %[[true:.*]] = arith.constant true
659// CHECK: return %[[true]]
660func.func @if_union(%arg0 : index, %arg1 : i1) -> i1 {
661    %c4 = arith.constant 4 : index
662    %c16 = arith.constant 16 : index
663    %c-1 = arith.constant -1 : index
664    %c-4 = arith.constant -4 : index
665    %0 = arith.minui %arg0, %c4 : index
666    %1 = scf.if %arg1 -> index {
667        %10 = arith.muli %0, %0 : index
668        scf.yield %10 : index
669    } else {
670        %20 = arith.muli %0, %c-1 : index
671        scf.yield %20 : index
672    }
673    %2 = arith.cmpi sle, %1, %c16 : index
674    %3 = arith.cmpi sge, %1, %c-4 : index
675    %4 = arith.andi %2, %3 : i1
676    func.return %4 : i1
677}
678
679// CHECK-LABEL: func @branch_union
680// CHECK: %[[true:.*]] = arith.constant true
681// CHECK: return %[[true]]
682func.func @branch_union(%arg0 : index, %arg1 : i1) -> i1 {
683    %c4 = arith.constant 4 : index
684    %c16 = arith.constant 16 : index
685    %c-1 = arith.constant -1 : index
686    %c-4 = arith.constant -4 : index
687    %0 = arith.minui %arg0, %c4 : index
688    cf.cond_br %arg1, ^bb1, ^bb2
689^bb1 :
690    %1 = arith.muli %0, %0 : index
691    cf.br ^bb3(%1 : index)
692^bb2 :
693    %2 = arith.muli %0, %c-1 : index
694    cf.br ^bb3(%2 : index)
695^bb3(%3 : index) :
696    %4 = arith.cmpi sle, %3, %c16 : index
697    %5 = arith.cmpi sge, %3, %c-4 : index
698    %6 = arith.andi %4, %5 : i1
699    func.return %6 : i1
700}
701
702// CHECK-LABEL: func @loop_bound_not_inferred_with_branch
703// CHECK-DAG: %[[min:.*]] = arith.cmpi sge
704// CHECK-DAG: %[[max:.*]] = arith.cmpi slt
705// CHECK-DAG: %[[ret:.*]] = arith.andi %[[min]], %[[max]]
706// CHECK: return %[[ret]]
707func.func @loop_bound_not_inferred_with_branch(%arg0 : index, %arg1 : i1) -> i1 {
708    %c0 = arith.constant 0 : index
709    %c1 = arith.constant 1 : index
710    %c4 = arith.constant 4 : index
711    %0 = arith.minui %arg0, %c4 : index
712    cf.br ^bb2(%c0 : index)
713^bb1(%1 : index) :
714    %2 = arith.addi %1, %c1 : index
715    cf.br ^bb2(%2 : index)
716^bb2(%3 : index):
717    %4 = arith.cmpi ult, %3, %c4 : index
718    cf.cond_br %4, ^bb1(%3 : index), ^bb3(%3 : index)
719^bb3(%5 : index) :
720    %6 = arith.cmpi sge, %5, %c0 : index
721    %7 = arith.cmpi slt, %5, %c4 : index
722    %8 = arith.andi %6, %7 : i1
723    func.return %8 : i1
724}
725
726// Test fon a bug where the noive implementation of trunctation led to the cast
727// value being set to [0, 0].
728// CHECK-LABEL: func.func @truncation_spillover
729// CHECK: %[[unreplaced:.*]] = arith.index_cast
730// CHECK: memref.store %[[unreplaced]]
731func.func @truncation_spillover(%arg0 : memref<?xi32>) -> index {
732    %c0 = arith.constant 0 : index
733    %c1 = arith.constant 1 : index
734    %c2 = arith.constant 2 : index
735    %c49 = arith.constant 49 : index
736    %0 = scf.for %arg1 = %c0 to %c2 step %c1 iter_args(%arg2 = %c0) -> index {
737        %1 = arith.divsi %arg2, %c49 : index
738        %2 = arith.index_cast %1 : index to i32
739        memref.store %2, %arg0[%c0] : memref<?xi32>
740        %3 = arith.addi %arg2, %arg1 : index
741        scf.yield %3 : index
742    }
743  func.return %0 : index
744}
745
746// CHECK-LABEL: func.func @trunc_catches_overflow
747// CHECK: %[[sge:.*]] = arith.cmpi sge
748// CHECK: return %[[sge]]
749func.func @trunc_catches_overflow(%arg0 : i16) -> i1 {
750    %c0_i16 = arith.constant 0 : i16
751    %c130_i16 = arith.constant 130 : i16
752    %c0_i8 = arith.constant 0 : i8
753    %0 = arith.maxui %arg0, %c0_i16 : i16
754    %1 = arith.minui %0, %c130_i16 : i16
755    %2 = arith.trunci %1 : i16 to i8
756    %3 = arith.cmpi sge, %2, %c0_i8 : i8
757    %4 = arith.cmpi uge, %2, %c0_i8 : i8
758    %5 = arith.andi %3, %4 : i1
759    func.return %5 : i1
760}
761
762// CHECK-LABEL: func.func @trunc_respects_same_high_half
763// CHECK: %[[false:.*]] = arith.constant false
764// CHECK: return %[[false]]
765func.func @trunc_respects_same_high_half(%arg0 : i16) -> i1 {
766    %c256_i16 = arith.constant 256 : i16
767    %c257_i16 = arith.constant 257 : i16
768    %c2_i8 = arith.constant 2 : i8
769    %0 = arith.maxui %arg0, %c256_i16 : i16
770    %1 = arith.minui %0, %c257_i16 : i16
771    %2 = arith.trunci %1 : i16 to i8
772    %3 = arith.cmpi sge, %2, %c2_i8 : i8
773    func.return %3 : i1
774}
775
776// CHECK-LABEL: func.func @trunc_handles_small_signed_ranges
777// CHECK: %[[true:.*]] = arith.constant true
778// CHECK: return %[[true]]
779func.func @trunc_handles_small_signed_ranges(%arg0 : i16) -> i1 {
780    %c-2_i16 = arith.constant -2 : i16
781    %c2_i16 = arith.constant 2 : i16
782    %c-2_i8 = arith.constant -2 : i8
783    %c2_i8 = arith.constant 2 : i8
784    %0 = arith.maxsi %arg0, %c-2_i16 : i16
785    %1 = arith.minsi %0, %c2_i16 : i16
786    %2 = arith.trunci %1 : i16 to i8
787    %3 = arith.cmpi sge, %2, %c-2_i8 : i8
788    %4 = arith.cmpi sle, %2, %c2_i8 : i8
789    %5 = arith.andi %3, %4 : i1
790    func.return %5 : i1
791}
792
793/// Catch a bug that crept in during an earlier refactoring that made unsigned
794/// extension use the signed ranges
795
796// CHECK-LABEL: func.func @extui_uses_unsigned
797// CHECK: %[[true:.*]] = arith.constant true
798// CHECK: return %[[true]]
799func.func @extui_uses_unsigned(%arg0 : i32) -> i1 {
800    %ci32_smin = arith.constant 0x80000000 : i32
801    %ci32_smin_64 = arith.constant 0x80000000 : i64
802    %c0_i64 = arith.constant 0 : i64
803    %0 = arith.minui %arg0, %ci32_smin : i32
804    %1 = arith.extui %0 : i32 to i64
805    %2 = arith.cmpi sge, %1, %c0_i64 : i64
806    %3 = arith.cmpi ule, %1, %ci32_smin_64 : i64
807    %4 = arith.andi %2, %3 : i1
808    func.return %4 : i1
809}
810
811/// Catch a bug that caused a crash in getLoopBoundFromFold when
812/// SparseConstantPropagation is loaded in the solver.
813
814// CHECK-LABEL:   func.func @caller(
815// CHECK-SAME:                      %[[VAL_0:.*]]: memref<?xindex, 4>) {
816// CHECK:           call @callee(%[[VAL_0]]) : (memref<?xindex, 4>) -> ()
817// CHECK:           return
818// CHECK:         }
819func.func @caller(%arg0: memref<?xindex, 4>) {
820  call @callee(%arg0) : (memref<?xindex, 4>) -> ()
821  return
822}
823
824// CHECK-LABEL:   func.func private @callee(
825// CHECK-SAME:                              %[[VAL_0:.*]]: memref<?xindex, 4>) {
826// CHECK:           return
827// CHECK:         }
828func.func private @callee(%arg0: memref<?xindex, 4>) {
829  %c1 = arith.constant 1 : index
830  %c0 = arith.constant 0 : index
831  %0 = affine.load %arg0[0] : memref<?xindex, 4>
832  scf.for %arg1 = %c0 to %0 step %c1 {
833  }
834  return
835}
836
837// CHECK-LABEL: func @test_i8_bounds
838// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 255 : ui8, umin = 0 : ui8}
839func.func @test_i8_bounds() -> i8 {
840  %cst1 = arith.constant 1 : i8
841  %0 = test.with_bounds { umin = 0 : i8, umax = 255 : i8, smin = -128 : i8, smax = 127 : i8 } : i8
842  %1 = arith.addi %0, %cst1 : i8
843  %2 = test.reflect_bounds %1 : i8
844  return %2: i8
845}
846
847// CHECK-LABEL: func @test_add_1
848// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 255 : ui8, umin = 0 : ui8}
849func.func @test_add_1() -> i8 {
850  %cst1 = arith.constant 1 : i8
851  %0 = test.with_bounds { umin = 0 : i8, umax = 255 : i8, smin = -128 : i8, smax = 127 : i8 } : i8
852  %1 = arith.addi %0, %cst1 : i8
853  %2 = test.reflect_bounds %1 : i8
854  return %2: i8
855}
856
857// Tests below check inference with overflow flags.
858
859// CHECK-LABEL: func @test_add_i8_wrap1
860// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 128 : ui8, umin = 1 : ui8}
861func.func @test_add_i8_wrap1() -> i8 {
862  %cst1 = arith.constant 1 : i8
863  %0 = test.with_bounds { umin = 0 : i8, umax = 127 : i8, smin = 0 : i8, smax = 127 : i8 } : i8
864  // smax overflow
865  %1 = arith.addi %0, %cst1 : i8
866  %2 = test.reflect_bounds %1 : i8
867  return %2: i8
868}
869
870// CHECK-LABEL: func @test_add_i8_wrap2
871// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 128 : ui8, umin = 1 : ui8}
872func.func @test_add_i8_wrap2() -> i8 {
873  %cst1 = arith.constant 1 : i8
874  %0 = test.with_bounds { umin = 0 : i8, umax = 127 : i8, smin = 0 : i8, smax = 127 : i8 } : i8
875  // smax overflow
876  %1 = arith.addi %0, %cst1 overflow<nuw> : i8
877  %2 = test.reflect_bounds %1 : i8
878  return %2: i8
879}
880
881// CHECK-LABEL: func @test_add_i8_nowrap
882// CHECK: test.reflect_bounds {smax = 127 : si8, smin = 1 : si8, umax = 127 : ui8, umin = 1 : ui8}
883func.func @test_add_i8_nowrap() -> i8 {
884  %cst1 = arith.constant 1 : i8
885  %0 = test.with_bounds { umin = 0 : i8, umax = 127 : i8, smin = 0 : i8, smax = 127 : i8 } : i8
886  // nsw flag stops smax from overflowing
887  %1 = arith.addi %0, %cst1 overflow<nsw> : i8
888  %2 = test.reflect_bounds %1 : i8
889  return %2: i8
890}
891
892// CHECK-LABEL: func @test_sub_i8_wrap1
893// CHECK: test.reflect_bounds {smax = 5 : si8, smin = -10 : si8, umax = 255 : ui8, umin = 0 : ui8} %1 : i8
894func.func @test_sub_i8_wrap1() -> i8 {
895  %cst10 = arith.constant 10 : i8
896  %0 = test.with_bounds { umin = 0 : i8, umax = 15 : i8, smin = 0 : i8, smax = 15 : i8 } : i8
897  // umin underflows
898  %1 = arith.subi %0, %cst10 : i8
899  %2 = test.reflect_bounds %1 : i8
900  return %2: i8
901}
902
903// CHECK-LABEL: func @test_sub_i8_wrap2
904// CHECK: test.reflect_bounds {smax = 5 : si8, smin = -10 : si8, umax = 255 : ui8, umin = 0 : ui8} %1 : i8
905func.func @test_sub_i8_wrap2() -> i8 {
906  %cst10 = arith.constant 10 : i8
907  %0 = test.with_bounds { umin = 0 : i8, umax = 15 : i8, smin = 0 : i8, smax = 15 : i8 } : i8
908  // umin underflows
909  %1 = arith.subi %0, %cst10 overflow<nsw> : i8
910  %2 = test.reflect_bounds %1 : i8
911  return %2: i8
912}
913
914// CHECK-LABEL: func @test_sub_i8_nowrap
915// CHECK: test.reflect_bounds {smax = 5 : si8, smin = 0 : si8, umax = 5 : ui8, umin = 0 : ui8}
916func.func @test_sub_i8_nowrap() -> i8 {
917  %cst10 = arith.constant 10 : i8
918  %0 = test.with_bounds { umin = 0 : i8, umax = 15 : i8, smin = 0 : i8, smax = 15 : i8 } : i8
919  // nuw flag stops umin from underflowing
920  %1 = arith.subi %0, %cst10 overflow<nuw> : i8
921  %2 = test.reflect_bounds %1 : i8
922  return %2: i8
923}
924
925// CHECK-LABEL: func @test_mul_i8_wrap
926// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 200 : ui8, umin = 100 : ui8}
927func.func @test_mul_i8_wrap() -> i8 {
928  %cst10 = arith.constant 10 : i8
929  %0 = test.with_bounds { umin = 10 : i8, umax = 20 : i8, smin = 10 : i8, smax = 20 : i8 } : i8
930  // smax overflows
931  %1 = arith.muli %0, %cst10 : i8
932  %2 = test.reflect_bounds %1 : i8
933  return %2: i8
934}
935
936// CHECK-LABEL: func @test_mul_i8_nowrap
937// CHECK: test.reflect_bounds {smax = 127 : si8, smin = 100 : si8, umax = 127 : ui8, umin = 100 : ui8}
938func.func @test_mul_i8_nowrap() -> i8 {
939  %cst10 = arith.constant 10 : i8
940  %0 = test.with_bounds { umin = 10 : i8, umax = 20 : i8, smin = 10 : i8, smax = 20 : i8 } : i8
941  // nsw stops overflow
942  %1 = arith.muli %0, %cst10 overflow<nsw> : i8
943  %2 = test.reflect_bounds %1 : i8
944  return %2: i8
945}
946
947// CHECK-LABEL: func @test_shl_i8_wrap1
948// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 160 : ui8, umin = 80 : ui8}
949func.func @test_shl_i8_wrap1() -> i8 {
950  %cst3 = arith.constant 3 : i8
951  %0 = test.with_bounds { umin = 10 : i8, umax = 20 : i8, smin = 10 : i8, smax = 20 : i8 } : i8
952  // smax overflows
953  %1 = arith.shli %0, %cst3 : i8
954  %2 = test.reflect_bounds %1 : i8
955  return %2: i8
956}
957
958// CHECK-LABEL: func @test_shl_i8_wrap2
959// CHECK: test.reflect_bounds {smax = 127 : si8, smin = -128 : si8, umax = 160 : ui8, umin = 80 : ui8}
960func.func @test_shl_i8_wrap2() -> i8 {
961  %cst3 = arith.constant 3 : i8
962  %0 = test.with_bounds { umin = 10 : i8, umax = 20 : i8, smin = 10 : i8, smax = 20 : i8 } : i8
963  // smax overflows
964  %1 = arith.shli %0, %cst3 overflow<nuw> : i8
965  %2 = test.reflect_bounds %1 : i8
966  return %2: i8
967}
968
969// CHECK-LABEL: func @test_shl_i8_nowrap
970// CHECK: test.reflect_bounds {smax = 127 : si8, smin = 80 : si8, umax = 127 : ui8, umin = 80 : ui8}
971func.func @test_shl_i8_nowrap() -> i8 {
972  %cst3 = arith.constant 3 : i8
973  %0 = test.with_bounds { umin = 10 : i8, umax = 20 : ui8, smin = 10 : i8, smax = 20 : i8 } : i8
974  // nsw stops smax overflow
975  %1 = arith.shli %0, %cst3 overflow<nsw> : i8
976  %2 = test.reflect_bounds %1 : i8
977  return %2: i8
978}
979
980/// A test case to ensure that the ranges for unsupported ops are initialized
981/// properly to maxRange, rather than left uninitialized.
982/// In this test case, the previous behavior would leave the ranges for %a and
983/// %b uninitialized, resulting in arith.cmpf's range not being updated, even
984/// though it has an integer valued result.
985
986// CHECK-LABEL: func @test_cmpf_propagates
987// CHECK: test.reflect_bounds {smax = 2 : index, smin = 1 : index, umax = 2 : index, umin = 1 : index}
988func.func @test_cmpf_propagates(%a: f32, %b: f32) -> index {
989  %c1 = arith.constant 1 : index
990  %c2 = arith.constant 2 : index
991
992  %0 = arith.cmpf ueq, %a, %b : f32
993  %1 = arith.select %0, %c1, %c2 : index
994  %2 = test.reflect_bounds %1 : index
995  func.return %2 : index
996}
997
998// CHECK-LABEL: func @zero_trip_loop
999func.func @zero_trip_loop() {
1000  %idx1 = arith.constant 1 : index
1001  scf.for %arg0 = %idx1 to %idx1 step %idx1 {
1002    %138 = index.floordivs %arg0, %arg0
1003  }
1004  return
1005}
1006
1007// CHECK-LABEL: func @zero_trip_loop2
1008func.func @zero_trip_loop2() {
1009  %idx1 = arith.constant 1 : index
1010  %idxm1 = arith.constant -1 : index
1011  scf.for %arg0 = %idx1 to %idx1 step %idxm1 {
1012    %138 = index.floordivs %arg0, %arg0
1013  }
1014  return
1015}
1016