xref: /llvm-project/llvm/test/Transforms/InstCombine/and-or-icmp-const-icmp.ll (revision 38fffa630ee80163dc65e759392ad29798905679)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4; Tests for foldAndOrOfICmpEqConstantAndICmp
5; https://github.com/llvm/llvm-project/issues/63749
6
7; ==============================================================================
8; (icmp eq X, C) | (icmp ult Other, (X - C)) -> (icmp ule Other, (X - (C + 1)))
9; (icmp ne X, C) & (icmp uge Other, (X - C)) -> (icmp ugt Other, (X - (C + 1)))
10; ==============================================================================
11
12; ==============================================================================
13; Basic tests
14; ==============================================================================
15define i1 @eq_basic(i8 %x, i8 %y) {
16; CHECK-LABEL: define i1 @eq_basic(
17; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
18; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], -1
19; CHECK-NEXT:    [[OR:%.*]] = icmp uge i8 [[TMP1]], [[Y]]
20; CHECK-NEXT:    ret i1 [[OR]]
21;
22  %c1 = icmp eq i8 %x, 0
23  %c2 = icmp ugt i8 %x, %y
24  %or = or i1 %c1, %c2
25  ret i1 %or
26}
27
28define i1 @ne_basic_equal_5(i8 %x, i8 %y) {
29; CHECK-LABEL: define i1 @ne_basic_equal_5(
30; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
31; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], -6
32; CHECK-NEXT:    [[AND:%.*]] = icmp ult i8 [[TMP1]], [[Y]]
33; CHECK-NEXT:    ret i1 [[AND]]
34;
35  %sub = add i8 %x, -5
36  %c1 = icmp ne i8 %x, 5
37  %c2 = icmp ule i8 %sub, %y
38  %and = and i1 %c1, %c2
39  ret i1 %and
40}
41
42define i1 @eq_basic_equal_minus_1(i8 %x, i8 %y) {
43; CHECK-LABEL: define i1 @eq_basic_equal_minus_1(
44; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
45; CHECK-NEXT:    [[OR:%.*]] = icmp uge i8 [[X]], [[Y]]
46; CHECK-NEXT:    ret i1 [[OR]]
47;
48  %add = add i8 %x, 1
49  %c1 = icmp eq i8 %x, -1
50  %c2 = icmp ugt i8 %add, %y
51  %or = or i1 %c1, %c2
52  ret i1 %or
53}
54
55define i1 @ne_basic_equal_minus_7(i8 %x, i8 %y) {
56; CHECK-LABEL: define i1 @ne_basic_equal_minus_7(
57; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
58; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], 6
59; CHECK-NEXT:    [[AND:%.*]] = icmp ult i8 [[TMP1]], [[Y]]
60; CHECK-NEXT:    ret i1 [[AND]]
61;
62  %add = add i8 %x, 7
63  %c1 = icmp ne i8 %x, -7
64  %c2 = icmp ule i8 %add, %y
65  %and = and i1 %c1, %c2
66  ret i1 %and
67}
68
69define i1 @eq_basic_unequal(i8 %x, i8 %y) {
70; CHECK-LABEL: define i1 @eq_basic_unequal(
71; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
72; CHECK-NEXT:    [[SUB:%.*]] = add i8 [[X]], -5
73; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[X]], 6
74; CHECK-NEXT:    [[C2:%.*]] = icmp ugt i8 [[SUB]], [[Y]]
75; CHECK-NEXT:    [[OR:%.*]] = or i1 [[C1]], [[C2]]
76; CHECK-NEXT:    ret i1 [[OR]]
77;
78  %sub = add i8 %x, -5
79  %c1 = icmp eq i8 %x, 6
80  %c2 = icmp ugt i8 %sub, %y
81  %or = or i1 %c1, %c2
82  ret i1 %or
83}
84
85define i1 @ne_basic_unequal(i8 %x, i8 %y) {
86; CHECK-LABEL: define i1 @ne_basic_unequal(
87; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
88; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[X]], 7
89; CHECK-NEXT:    [[C1:%.*]] = icmp ne i8 [[X]], -4
90; CHECK-NEXT:    [[C2:%.*]] = icmp ule i8 [[ADD]], [[Y]]
91; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C1]], [[C2]]
92; CHECK-NEXT:    ret i1 [[AND]]
93;
94  %add = add i8 %x, 7
95  %c1 = icmp ne i8 %x, -4
96  %c2 = icmp ule i8 %add, %y
97  %and = and i1 %c1, %c2
98  ret i1 %and
99}
100
101; ==============================================================================
102; Tests with multiple uses
103; ==============================================================================
104define i1 @eq_multi_c1(i8 %x, i8 %y) {
105; CHECK-LABEL: define i1 @eq_multi_c1(
106; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
107; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[X]], 0
108; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], -1
109; CHECK-NEXT:    [[OR:%.*]] = icmp uge i8 [[TMP1]], [[Y]]
110; CHECK-NEXT:    call void @use(i1 [[C1]])
111; CHECK-NEXT:    ret i1 [[OR]]
112;
113  %c1 = icmp eq i8 %x, 0
114  %c2 = icmp ugt i8 %x, %y
115  %or = or i1 %c1, %c2
116  call void @use(i1 %c1)
117  ret i1 %or
118}
119
120define i1 @ne_multi_c2(i8 %x, i8 %y) {
121; CHECK-LABEL: define i1 @ne_multi_c2(
122; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
123; CHECK-NEXT:    [[C2:%.*]] = icmp ule i8 [[X]], [[Y]]
124; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], -1
125; CHECK-NEXT:    [[AND:%.*]] = icmp ult i8 [[TMP1]], [[Y]]
126; CHECK-NEXT:    call void @use(i1 [[C2]])
127; CHECK-NEXT:    ret i1 [[AND]]
128;
129  %c1 = icmp ne i8 %x, 0
130  %c2 = icmp ule i8 %x, %y
131  %and = and i1 %c1, %c2
132  call void @use(i1 %c2)
133  ret i1 %and
134}
135
136; ==============================================================================
137; Tests with vector types
138; ==============================================================================
139define <2 x i1> @eq_vector(<2 x i8> %x, <2 x i8> %y) {
140; CHECK-LABEL: define <2 x i1> @eq_vector(
141; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
142; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X]], splat (i8 -1)
143; CHECK-NEXT:    [[OR:%.*]] = icmp uge <2 x i8> [[TMP1]], [[Y]]
144; CHECK-NEXT:    ret <2 x i1> [[OR]]
145;
146  %c1 = icmp eq <2 x i8> %x, <i8 0, i8 0>
147  %c2 = icmp ugt <2 x i8> %x, %y
148  %or = or <2 x i1> %c1, %c2
149  ret <2 x i1> %or
150}
151
152define <2 x i1> @ne_vector_equal_5(<2 x i8> %x, <2 x i8> %y) {
153; CHECK-LABEL: define <2 x i1> @ne_vector_equal_5(
154; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
155; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X]], splat (i8 -6)
156; CHECK-NEXT:    [[AND:%.*]] = icmp ult <2 x i8> [[TMP1]], [[Y]]
157; CHECK-NEXT:    ret <2 x i1> [[AND]]
158;
159  %sub = add <2 x i8> %x, <i8 -5, i8 -5>
160  %c1 = icmp ne <2 x i8> %x, <i8 5, i8 5>
161  %c2 = icmp ule <2 x i8> %sub, %y
162  %and = and <2 x i1> %c1, %c2
163  ret <2 x i1> %and
164}
165
166define <2 x i1> @eq_vector_equal_minus_1(<2 x i8> %x, <2 x i8> %y) {
167; CHECK-LABEL: define <2 x i1> @eq_vector_equal_minus_1(
168; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
169; CHECK-NEXT:    [[OR:%.*]] = icmp uge <2 x i8> [[X]], [[Y]]
170; CHECK-NEXT:    ret <2 x i1> [[OR]]
171;
172  %add = add <2 x i8> %x, <i8 1, i8 1>
173  %c1 = icmp eq <2 x i8> %x, <i8 -1, i8 -1>
174  %c2 = icmp ugt <2 x i8> %add, %y
175  %or = or <2 x i1> %c1, %c2
176  ret <2 x i1> %or
177}
178
179define <2 x i1> @ne_vector_equal_minus_7(<2 x i8> %x, <2 x i8> %y) {
180; CHECK-LABEL: define <2 x i1> @ne_vector_equal_minus_7(
181; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
182; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X]], splat (i8 6)
183; CHECK-NEXT:    [[AND:%.*]] = icmp ult <2 x i8> [[TMP1]], [[Y]]
184; CHECK-NEXT:    ret <2 x i1> [[AND]]
185;
186  %add = add <2 x i8> %x, <i8 7, i8 7>
187  %c1 = icmp ne <2 x i8> %x, <i8 -7, i8 -7>
188  %c2 = icmp ule <2 x i8> %add, %y
189  %and = and <2 x i1> %c1, %c2
190  ret <2 x i1> %and
191}
192
193define <2 x i1> @eq_vector_unequal1(<2 x i8> %x, <2 x i8> %y) {
194; CHECK-LABEL: define <2 x i1> @eq_vector_unequal1(
195; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
196; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i8> [[X]], splat (i8 -5)
197; CHECK-NEXT:    [[C1:%.*]] = icmp eq <2 x i8> [[X]], splat (i8 2)
198; CHECK-NEXT:    [[C2:%.*]] = icmp ugt <2 x i8> [[SUB]], [[Y]]
199; CHECK-NEXT:    [[OR:%.*]] = or <2 x i1> [[C1]], [[C2]]
200; CHECK-NEXT:    ret <2 x i1> [[OR]]
201;
202  %sub = add <2 x i8> %x, <i8 -5, i8 -5>
203  %c1 = icmp eq <2 x i8> %x, <i8 2, i8 2>
204  %c2 = icmp ugt <2 x i8> %sub, %y
205  %or = or <2 x i1> %c1, %c2
206  ret <2 x i1> %or
207}
208
209define <2 x i1> @ne_vector_unequal2(<2 x i8> %x, <2 x i8> %y) {
210; CHECK-LABEL: define <2 x i1> @ne_vector_unequal2(
211; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
212; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i8> [[X]], splat (i8 7)
213; CHECK-NEXT:    [[C1:%.*]] = icmp ne <2 x i8> [[X]], splat (i8 -3)
214; CHECK-NEXT:    [[C2:%.*]] = icmp ule <2 x i8> [[ADD]], [[Y]]
215; CHECK-NEXT:    [[AND:%.*]] = and <2 x i1> [[C1]], [[C2]]
216; CHECK-NEXT:    ret <2 x i1> [[AND]]
217;
218  %add = add <2 x i8> %x, <i8 7, i8 7>
219  %c1 = icmp ne <2 x i8> %x, <i8 -3, i8 -3>
220  %c2 = icmp ule <2 x i8> %add, %y
221  %and = and <2 x i1> %c1, %c2
222  ret <2 x i1> %and
223}
224
225; ==============================================================================
226; Tests with poison
227; ==============================================================================
228define <2 x i1> @eq_vector_poison_icmp(<2 x i8> %x, <2 x i8> %y) {
229; CHECK-LABEL: define <2 x i1> @eq_vector_poison_icmp(
230; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
231; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X]], splat (i8 -6)
232; CHECK-NEXT:    [[OR:%.*]] = icmp uge <2 x i8> [[TMP1]], [[Y]]
233; CHECK-NEXT:    ret <2 x i1> [[OR]]
234;
235  %sub = add <2 x i8> %x, <i8 -5, i8 -5>
236  %c1 = icmp eq <2 x i8> %x, <i8 5, i8 poison>
237  %c2 = icmp ugt <2 x i8> %sub, %y
238  %or = or <2 x i1> %c1, %c2
239  ret <2 x i1> %or
240}
241
242define <2 x i1> @eq_vector_poison_add(<2 x i8> %x, <2 x i8> %y) {
243; CHECK-LABEL: define <2 x i1> @eq_vector_poison_add(
244; CHECK-SAME: <2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
245; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X]], splat (i8 -6)
246; CHECK-NEXT:    [[OR:%.*]] = icmp uge <2 x i8> [[TMP1]], [[Y]]
247; CHECK-NEXT:    ret <2 x i1> [[OR]]
248;
249  %sub = add <2 x i8> %x, <i8 -5, i8 poison>
250  %c1 = icmp eq <2 x i8> %x, <i8 5, i8 5>
251  %c2 = icmp ugt <2 x i8> %sub, %y
252  %or = or <2 x i1> %c1, %c2
253  ret <2 x i1> %or
254}
255
256; ==============================================================================
257; Tests with values commuted
258; ==============================================================================
259define i1 @eq_commuted(i8 %x, i8 %py) {
260; CHECK-LABEL: define i1 @eq_commuted(
261; CHECK-SAME: i8 [[X:%.*]], i8 [[PY:%.*]]) {
262; CHECK-NEXT:    [[Y:%.*]] = sdiv i8 43, [[PY]]
263; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], -1
264; CHECK-NEXT:    [[OR:%.*]] = icmp uge i8 [[TMP1]], [[Y]]
265; CHECK-NEXT:    ret i1 [[OR]]
266;
267  %y = sdiv i8 43, %py ; thwart complexity-based canonicalization
268  %c1 = icmp eq i8 %x, 0
269  %c2 = icmp ult i8 %y, %x
270  %or = or i1 %c1, %c2
271  ret i1 %or
272}
273
274define i1 @ne_commuted_equal_minus_1(i8 %x, i8 %py) {
275; CHECK-LABEL: define i1 @ne_commuted_equal_minus_1(
276; CHECK-SAME: i8 [[X:%.*]], i8 [[PY:%.*]]) {
277; CHECK-NEXT:    [[Y:%.*]] = sdiv i8 42, [[PY]]
278; CHECK-NEXT:    [[AND:%.*]] = icmp ult i8 [[X]], [[Y]]
279; CHECK-NEXT:    ret i1 [[AND]]
280;
281  %y = sdiv i8 42, %py ; thwart complexity-based canonicalization
282  %add = add i8 %x, 1
283  %c1 = icmp ne i8 %x, -1
284  %c2 = icmp uge i8 %y, %add
285  %and = and i1 %c1, %c2
286  ret i1 %and
287}
288
289declare void @use(i1)
290