[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / InstCombine / unsigned-add-overflow-check-via-add.ll
blob86eeea93fc15abed4f64fb6f2ea932b84e4409f9
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -instcombine -S | FileCheck %s
4 ; Should fold
5 ;   (%x + %y) u< %x
6 ; or
7 ;   (%x + %y) u< %y
8 ; to
9 ;   @llvm.uadd.with.overflow(%x, %y) + extractvalue
11 ; All tests here have extra uses, to ensure that the pattern isn't perturbed.
13 declare void @use8(i8)
14 declare void @use2x8(<2 x i8>)
16 define i1 @t0_basic(i8 %x, i8 %y) {
17 ; CHECK-LABEL: @t0_basic(
18 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
19 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
20 ; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T0]], [[Y]]
21 ; CHECK-NEXT:    ret i1 [[R]]
23   %t0 = add i8 %x, %y
24   call void @use8(i8 %t0)
25   %r = icmp ult i8 %t0, %y
26   ret i1 %r
29 define <2 x i1> @t1_vec(<2 x i8> %x, <2 x i8> %y) {
30 ; CHECK-LABEL: @t1_vec(
31 ; CHECK-NEXT:    [[T0:%.*]] = add <2 x i8> [[X:%.*]], [[Y:%.*]]
32 ; CHECK-NEXT:    call void @use2x8(<2 x i8> [[T0]])
33 ; CHECK-NEXT:    [[R:%.*]] = icmp ult <2 x i8> [[T0]], [[Y]]
34 ; CHECK-NEXT:    ret <2 x i1> [[R]]
36   %t0 = add <2 x i8> %x, %y
37   call void @use2x8(<2 x i8> %t0)
38   %r = icmp ult <2 x i8> %t0, %y
39   ret <2 x i1> %r
42 ; Commutativity
44 define i1 @t2_symmetry(i8 %x, i8 %y) {
45 ; CHECK-LABEL: @t2_symmetry(
46 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
47 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
48 ; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T0]], [[X]]
49 ; CHECK-NEXT:    ret i1 [[R]]
51   %t0 = add i8 %x, %y
52   call void @use8(i8 %t0)
53   %r = icmp ult i8 %t0, %x ; can check against either of `add` arguments
54   ret i1 %r
57 declare i8 @gen8()
59 define i1 @t3_commutative(i8 %x) {
60 ; CHECK-LABEL: @t3_commutative(
61 ; CHECK-NEXT:    [[Y:%.*]] = call i8 @gen8()
62 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[Y]], [[X:%.*]]
63 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
64 ; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T0]], [[Y]]
65 ; CHECK-NEXT:    ret i1 [[R]]
67   %y = call i8 @gen8()
68   %t0 = add i8 %y, %x ; swapped
69   call void @use8(i8 %t0)
70   %r = icmp ult i8 %t0, %y
71   ret i1 %r
74 define i1 @t4_commutative(i8 %x, i8 %y) {
75 ; CHECK-LABEL: @t4_commutative(
76 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
77 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
78 ; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T0]], [[Y]]
79 ; CHECK-NEXT:    ret i1 [[R]]
81   %t0 = add i8 %x, %y
82   call void @use8(i8 %t0)
83   %r = icmp ugt i8 %y, %t0 ; swapped
84   ret i1 %r
87 define i1 @t5_commutative(i8 %x) {
88 ; CHECK-LABEL: @t5_commutative(
89 ; CHECK-NEXT:    [[Y:%.*]] = call i8 @gen8()
90 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[Y]], [[X:%.*]]
91 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
92 ; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[Y]], [[T0]]
93 ; CHECK-NEXT:    ret i1 [[R]]
95   %y = call i8 @gen8()
96   %t0 = add i8 %y, %x ; swapped
97   call void @use8(i8 %t0)
98   %r = icmp ugt i8 %y, %t0 ; swapped
99   ret i1 %r
102 ; Extra-use tests
104 define i1 @t6_no_extrause(i8 %x, i8 %y) {
105 ; CHECK-LABEL: @t6_no_extrause(
106 ; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[Y:%.*]], -1
107 ; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[TMP1]], [[X:%.*]]
108 ; CHECK-NEXT:    ret i1 [[R]]
110   %t0 = add i8 %x, %y
111   %r = icmp ult i8 %t0, %y
112   ret i1 %r
115 ; Negative tests
117 define i1 @n7_different_y(i8 %x, i8 %y0, i8 %y1) {
118 ; CHECK-LABEL: @n7_different_y(
119 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y0:%.*]]
120 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
121 ; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[T0]], [[Y1:%.*]]
122 ; CHECK-NEXT:    ret i1 [[R]]
124   %t0 = add i8 %x, %y0
125   call void @use8(i8 %t0)
126   %r = icmp ult i8 %t0, %y1
127   ret i1 %r
130 define i1 @n8_wrong_pred0(i8 %x, i8 %y) {
131 ; CHECK-LABEL: @n8_wrong_pred0(
132 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
133 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
134 ; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[T0]], [[Y]]
135 ; CHECK-NEXT:    ret i1 [[R]]
137   %t0 = add i8 %x, %y
138   call void @use8(i8 %t0)
139   %r = icmp ule i8 %t0, %y
140   ret i1 %r
143 define i1 @n9_wrong_pred1(i8 %x, i8 %y) {
144 ; CHECK-LABEL: @n9_wrong_pred1(
145 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
146 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
147 ; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[T0]], [[Y]]
148 ; CHECK-NEXT:    ret i1 [[R]]
150   %t0 = add i8 %x, %y
151   call void @use8(i8 %t0)
152   %r = icmp ugt i8 %t0, %y
153   ret i1 %r
156 define i1 @n10_wrong_pred2(i8 %x, i8 %y) {
157 ; CHECK-LABEL: @n10_wrong_pred2(
158 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
159 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
160 ; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X]], 0
161 ; CHECK-NEXT:    ret i1 [[R]]
163   %t0 = add i8 %x, %y
164   call void @use8(i8 %t0)
165   %r = icmp eq i8 %t0, %y
166   ret i1 %r
169 define i1 @n11_wrong_pred3(i8 %x, i8 %y) {
170 ; CHECK-LABEL: @n11_wrong_pred3(
171 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
172 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
173 ; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[X]], 0
174 ; CHECK-NEXT:    ret i1 [[R]]
176   %t0 = add i8 %x, %y
177   call void @use8(i8 %t0)
178   %r = icmp ne i8 %t0, %y
179   ret i1 %r
182 define i1 @n12_wrong_pred4(i8 %x, i8 %y) {
183 ; CHECK-LABEL: @n12_wrong_pred4(
184 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
185 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
186 ; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[T0]], [[Y]]
187 ; CHECK-NEXT:    ret i1 [[R]]
189   %t0 = add i8 %x, %y
190   call void @use8(i8 %t0)
191   %r = icmp slt i8 %t0, %y
192   ret i1 %r
195 define i1 @n13_wrong_pred5(i8 %x, i8 %y) {
196 ; CHECK-LABEL: @n13_wrong_pred5(
197 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
198 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
199 ; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[T0]], [[Y]]
200 ; CHECK-NEXT:    ret i1 [[R]]
202   %t0 = add i8 %x, %y
203   call void @use8(i8 %t0)
204   %r = icmp sle i8 %t0, %y
205   ret i1 %r
208 define i1 @n14_wrong_pred6(i8 %x, i8 %y) {
209 ; CHECK-LABEL: @n14_wrong_pred6(
210 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
211 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
212 ; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[T0]], [[Y]]
213 ; CHECK-NEXT:    ret i1 [[R]]
215   %t0 = add i8 %x, %y
216   call void @use8(i8 %t0)
217   %r = icmp sgt i8 %t0, %y
218   ret i1 %r
221 define i1 @n15_wrong_pred7(i8 %x, i8 %y) {
222 ; CHECK-LABEL: @n15_wrong_pred7(
223 ; CHECK-NEXT:    [[T0:%.*]] = add i8 [[X:%.*]], [[Y:%.*]]
224 ; CHECK-NEXT:    call void @use8(i8 [[T0]])
225 ; CHECK-NEXT:    [[R:%.*]] = icmp sge i8 [[T0]], [[Y]]
226 ; CHECK-NEXT:    ret i1 [[R]]
228   %t0 = add i8 %x, %y
229   call void @use8(i8 %t0)
230   %r = icmp sge i8 %t0, %y
231   ret i1 %r