Skip to content

Commit 553f8e7

Browse files
authored
[InstCombine] simplify icmp pred x, ~x (#73990)
simplify compare between specific variable `X` and `NOT(X)` Proof: https://alive2.llvm.org/ce/z/KTCpjP Fixed #57532.
1 parent 88b1d16 commit 553f8e7

File tree

2 files changed

+364
-0
lines changed

2 files changed

+364
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -5065,6 +5065,27 @@ static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
50655065
if (PredOut != Pred && isKnownNonZero(A, Q))
50665066
return new ICmpInst(PredOut, Op0, Op1);
50675067

5068+
// These transform work when A is negative.
5069+
// X s< X^A, X s<= X^A, X u> X^A, X u>= X^A --> X s< 0
5070+
// X s> X^A, X s>= X^A, X u< X^A, X u<= X^A --> X s>= 0
5071+
if (match(A, m_Negative())) {
5072+
CmpInst::Predicate NewPred;
5073+
switch (ICmpInst::getStrictPredicate(Pred)) {
5074+
default:
5075+
return nullptr;
5076+
case ICmpInst::ICMP_SLT:
5077+
case ICmpInst::ICMP_UGT:
5078+
NewPred = ICmpInst::ICMP_SLT;
5079+
break;
5080+
case ICmpInst::ICMP_SGT:
5081+
case ICmpInst::ICMP_ULT:
5082+
NewPred = ICmpInst::ICMP_SGE;
5083+
break;
5084+
}
5085+
Constant *Const = Constant::getNullValue(Op0->getType());
5086+
return new ICmpInst(NewPred, Op0, Const);
5087+
}
5088+
50685089
return nullptr;
50695090
}
50705091

llvm/test/Transforms/InstCombine/icmp-of-xor-x.ll

+343
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,349 @@ declare void @llvm.assume(i1)
55
declare void @barrier()
66
declare void @use.i8(i8)
77

8+
; Test case of X comp X^Neg_C, which have Transform to SLT.
9+
; X s< X^Neg_C --> X s< 0
10+
define i1 @src_slt(i8 %x) {
11+
; CHECK-LABEL: @src_slt(
12+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
13+
; CHECK-NEXT: ret i1 [[CMP]]
14+
;
15+
%not = xor i8 %x, -1
16+
%cmp = icmp slt i8 %x, %not
17+
ret i1 %cmp
18+
}
19+
20+
define <2 x i1> @src_slt_vec(<2 x i8> %x) {
21+
; CHECK-LABEL: @src_slt_vec(
22+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
23+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
24+
;
25+
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
26+
%cmp = icmp slt <2 x i8> %x, %not
27+
ret <2 x i1> %cmp
28+
}
29+
30+
; X s<= X^Neg_C --> X s< 0
31+
define i1 @src_sle(i8 %x) {
32+
; CHECK-LABEL: @src_sle(
33+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
34+
; CHECK-NEXT: ret i1 [[CMP]]
35+
;
36+
%not = xor i8 %x, -1
37+
%cmp = icmp sle i8 %x, %not
38+
ret i1 %cmp
39+
}
40+
41+
define <2 x i1> @src_sle_vec(<2 x i8> %x) {
42+
; CHECK-LABEL: @src_sle_vec(
43+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
44+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
45+
;
46+
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
47+
%cmp = icmp sle <2 x i8> %x, %not
48+
ret <2 x i1> %cmp
49+
}
50+
51+
; X u> X^Neg_C --> X s< 0
52+
define i1 @src_ugt(i8 %x) {
53+
; CHECK-LABEL: @src_ugt(
54+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
55+
; CHECK-NEXT: ret i1 [[CMP]]
56+
;
57+
%not = xor i8 %x, -1
58+
%cmp = icmp ugt i8 %x, %not
59+
ret i1 %cmp
60+
}
61+
62+
define <2 x i1> @src_ugt_vec(<2 x i8> %x) {
63+
; CHECK-LABEL: @src_ugt_vec(
64+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
65+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
66+
;
67+
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
68+
%cmp = icmp ugt <2 x i8> %x, %not
69+
ret <2 x i1> %cmp
70+
}
71+
72+
; X u>= X^Neg_C --> X s< 0
73+
define i1 @src_uge(i8 %x) {
74+
; CHECK-LABEL: @src_uge(
75+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0
76+
; CHECK-NEXT: ret i1 [[CMP]]
77+
;
78+
%not = xor i8 %x, -1
79+
%cmp = icmp uge i8 %x, %not
80+
ret i1 %cmp
81+
}
82+
83+
define <2 x i1> @src_uge_vec(<2 x i8> %x) {
84+
; CHECK-LABEL: @src_uge_vec(
85+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
86+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
87+
;
88+
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
89+
%cmp = icmp uge <2 x i8> %x, %not
90+
ret <2 x i1> %cmp
91+
}
92+
93+
define <2 x i1> @src_uge_vec_min(<2 x i8> %x) {
94+
; CHECK-LABEL: @src_uge_vec_min(
95+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
96+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
97+
;
98+
%not = xor <2 x i8> %x, <i8 -128, i8 -128>
99+
%cmp = icmp uge <2 x i8> %x, %not
100+
ret <2 x i1> %cmp
101+
}
102+
103+
define <2 x i1> @src_uge_vec_128(<2 x i128> %x) {
104+
; CHECK-LABEL: @src_uge_vec_128(
105+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i128> [[X:%.*]], zeroinitializer
106+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
107+
;
108+
%not = xor <2 x i128> %x, <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
109+
%cmp = icmp uge <2 x i128> %x, %not
110+
ret <2 x i1> %cmp
111+
}
112+
113+
; Test case of X comp X^Neg_C, which have Transform to SGT.
114+
; X s> X^Neg_C --> X s> -1
115+
define i1 @src_sgt(i8 %x) {
116+
; CHECK-LABEL: @src_sgt(
117+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
118+
; CHECK-NEXT: ret i1 [[CMP]]
119+
;
120+
%not = xor i8 %x, -1
121+
%cmp = icmp sgt i8 %x, %not
122+
ret i1 %cmp
123+
}
124+
125+
define <2 x i1> @src_sgt_vec(<2 x i8> %x) {
126+
; CHECK-LABEL: @src_sgt_vec(
127+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
128+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
129+
;
130+
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
131+
%cmp = icmp sgt <2 x i8> %x, %not
132+
ret <2 x i1> %cmp
133+
}
134+
135+
; X s>= X^Neg_C --> X s> -1
136+
define i1 @src_sge(i8 %x) {
137+
; CHECK-LABEL: @src_sge(
138+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
139+
; CHECK-NEXT: ret i1 [[CMP]]
140+
;
141+
%not = xor i8 %x, -1
142+
%cmp = icmp sge i8 %x, %not
143+
ret i1 %cmp
144+
}
145+
146+
define <2 x i1> @src_sge_vec(<2 x i8> %x) {
147+
; CHECK-LABEL: @src_sge_vec(
148+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
149+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
150+
;
151+
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
152+
%cmp = icmp sge <2 x i8> %x, %not
153+
ret <2 x i1> %cmp
154+
}
155+
156+
; X u< X^Neg_C --> X s> -1
157+
define i1 @src_ult(i8 %x) {
158+
; CHECK-LABEL: @src_ult(
159+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
160+
; CHECK-NEXT: ret i1 [[CMP]]
161+
;
162+
%not = xor i8 %x, -1
163+
%cmp = icmp ult i8 %x, %not
164+
ret i1 %cmp
165+
}
166+
167+
define <2 x i1> @src_ult_vec(<2 x i8> %x) {
168+
; CHECK-LABEL: @src_ult_vec(
169+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
170+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
171+
;
172+
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
173+
%cmp = icmp ult <2 x i8> %x, %not
174+
ret <2 x i1> %cmp
175+
}
176+
177+
; X u<= X^Neg_C --> X s> -1
178+
define i1 @src_ule(i8 %x) {
179+
; CHECK-LABEL: @src_ule(
180+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], -1
181+
; CHECK-NEXT: ret i1 [[CMP]]
182+
;
183+
%not = xor i8 %x, -1
184+
%cmp = icmp ule i8 %x, %not
185+
ret i1 %cmp
186+
}
187+
188+
define <2 x i1> @src_ule_vec(<2 x i8> %x) {
189+
; CHECK-LABEL: @src_ule_vec(
190+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
191+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
192+
;
193+
%not = xor <2 x i8> %x, <i8 -1, i8 -1>
194+
%cmp = icmp ule <2 x i8> %x, %not
195+
ret <2 x i1> %cmp
196+
}
197+
198+
define <2 x i1> @src_ule_vec_min(<2 x i8> %x) {
199+
; CHECK-LABEL: @src_ule_vec_min(
200+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[X:%.*]], <i8 -1, i8 -1>
201+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
202+
;
203+
%not = xor <2 x i8> %x, <i8 -128, i8 -128>
204+
%cmp = icmp ule <2 x i8> %x, %not
205+
ret <2 x i1> %cmp
206+
}
207+
208+
define <2 x i1> @src_ule_vec_128(<2 x i128> %x) {
209+
; CHECK-LABEL: @src_ule_vec_128(
210+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i128> [[X:%.*]], <i128 -1, i128 -1>
211+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
212+
;
213+
%not = xor <2 x i128> %x, <i128 -170141183460469231731687303715884105728, i128 -170141183460469231731687303715884105728>
214+
%cmp = icmp ule <2 x i128> %x, %not
215+
ret <2 x i1> %cmp
216+
}
217+
218+
; X comp X^Neg_C tests. negative
219+
; X comp Y
220+
define i1 @src_sle_xny(i8 %x, i8 %y) {
221+
; CHECK-LABEL: @src_sle_xny(
222+
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
223+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X:%.*]], [[Y_NOT]]
224+
; CHECK-NEXT: ret i1 [[CMP]]
225+
;
226+
%y.not = xor i8 %y, -1
227+
%cmp = icmp sle i8 %x, %y.not
228+
ret i1 %cmp
229+
}
230+
define i1 @src_sle_nyx(i8 %x, i8 %y) {
231+
; CHECK-LABEL: @src_sle_nyx(
232+
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
233+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[X:%.*]], [[Y_NOT]]
234+
; CHECK-NEXT: ret i1 [[CMP]]
235+
;
236+
%y.not = xor i8 %y, -1
237+
%cmp = icmp sle i8 %y.not, %x
238+
ret i1 %cmp
239+
}
240+
define i1 @src_sge_xny(i8 %x, i8 %y) {
241+
; CHECK-LABEL: @src_sge_xny(
242+
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
243+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[X:%.*]], [[Y_NOT]]
244+
; CHECK-NEXT: ret i1 [[CMP]]
245+
;
246+
%y.not = xor i8 %y, -1
247+
%cmp = icmp sge i8 %x, %y.not
248+
ret i1 %cmp
249+
}
250+
define i1 @src_sge_nyx(i8 %x, i8 %y) {
251+
; CHECK-LABEL: @src_sge_nyx(
252+
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
253+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X:%.*]], [[Y_NOT]]
254+
; CHECK-NEXT: ret i1 [[CMP]]
255+
;
256+
%y.not = xor i8 %y, -1
257+
%cmp = icmp sge i8 %y.not, %x
258+
ret i1 %cmp
259+
}
260+
define i1 @src_ule_xny(i8 %x, i8 %y) {
261+
; CHECK-LABEL: @src_ule_xny(
262+
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
263+
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X:%.*]], [[Y_NOT]]
264+
; CHECK-NEXT: ret i1 [[CMP]]
265+
;
266+
%y.not = xor i8 %y, -1
267+
%cmp = icmp ule i8 %x, %y.not
268+
ret i1 %cmp
269+
}
270+
define i1 @src_ule_nyx(i8 %x, i8 %y) {
271+
; CHECK-LABEL: @src_ule_nyx(
272+
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
273+
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X:%.*]], [[Y_NOT]]
274+
; CHECK-NEXT: ret i1 [[CMP]]
275+
;
276+
%y.not = xor i8 %y, -1
277+
%cmp = icmp ule i8 %y.not, %x
278+
ret i1 %cmp
279+
}
280+
define i1 @src_uge_xny(i8 %x, i8 %y) {
281+
; CHECK-LABEL: @src_uge_xny(
282+
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
283+
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X:%.*]], [[Y_NOT]]
284+
; CHECK-NEXT: ret i1 [[CMP]]
285+
;
286+
%y.not = xor i8 %y, -1
287+
%cmp = icmp uge i8 %x, %y.not
288+
ret i1 %cmp
289+
}
290+
define i1 @src_uge_nyx(i8 %x, i8 %y) {
291+
; CHECK-LABEL: @src_uge_nyx(
292+
; CHECK-NEXT: [[Y_NOT:%.*]] = xor i8 [[Y:%.*]], -1
293+
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i8 [[X:%.*]], [[Y_NOT]]
294+
; CHECK-NEXT: ret i1 [[CMP]]
295+
;
296+
%y.not = xor i8 %y, -1
297+
%cmp = icmp uge i8 %y.not, %x
298+
ret i1 %cmp
299+
}
300+
301+
; X comp X^Neg_C tests. negative
302+
; (X+1) comp X^Neg_C
303+
define i1 @src_sle_incx_nx(i8 %x) {
304+
; CHECK-LABEL: @src_sle_incx_nx(
305+
; CHECK-NEXT: [[TMP1:%.*]] = sub i8 -2, [[X:%.*]]
306+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[TMP1]], [[X]]
307+
; CHECK-NEXT: ret i1 [[CMP]]
308+
;
309+
%nx = xor i8 %x, -1
310+
%inc.x = add i8 %x, 1
311+
%cmp = icmp sle i8 %inc.x, %nx
312+
ret i1 %cmp
313+
}
314+
; (X-1) comp X^Neg_C
315+
define i1 @src_sle_decx_nx(i8 %x) {
316+
; CHECK-LABEL: @src_sle_decx_nx(
317+
; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[X:%.*]]
318+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X]], [[TMP1]]
319+
; CHECK-NEXT: ret i1 [[CMP]]
320+
;
321+
%nx = xor i8 %x, -1
322+
%dec.x = add i8 %x, -1
323+
%cmp = icmp sle i8 %dec.x, %nx
324+
ret i1 %cmp
325+
}
326+
; X comp (X+1)^Neg_C
327+
define i1 @src_sle_x_nincx(i8 %x) {
328+
; CHECK-LABEL: @src_sle_x_nincx(
329+
; CHECK-NEXT: [[NOT_INC_X:%.*]] = sub i8 -2, [[X:%.*]]
330+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X]], [[NOT_INC_X]]
331+
; CHECK-NEXT: ret i1 [[CMP]]
332+
;
333+
%inc.x = add i8 %x, 1
334+
%not.inc.x = xor i8 %inc.x, -1
335+
%cmp = icmp sle i8 %x, %not.inc.x
336+
ret i1 %cmp
337+
}
338+
; X comp (X-1)^Neg_C
339+
define i1 @src_sle_x_ndecx(i8 %x) {
340+
; CHECK-LABEL: @src_sle_x_ndecx(
341+
; CHECK-NEXT: [[NOT_DEC_X:%.*]] = sub i8 0, [[X:%.*]]
342+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[X]], [[NOT_DEC_X]]
343+
; CHECK-NEXT: ret i1 [[CMP]]
344+
;
345+
%dec.x = add i8 %x, -1
346+
%not.dec.x = xor i8 %dec.x, -1
347+
%cmp = icmp sle i8 %x, %not.dec.x
348+
ret i1 %cmp
349+
}
350+
8351
; test for (~x ^ y) < ~z
9352
define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
10353
; CHECK-LABEL: @test_xor1(

0 commit comments

Comments
 (0)