Skip to content

Commit b348c46

Browse files
committed
[InstCombine] Fold xored one-complemented operand comparisons.
1 parent f42483f commit b348c46

File tree

2 files changed

+49
-49
lines changed

2 files changed

+49
-49
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7022,7 +7022,7 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
70227022
return Res;
70237023

70247024
{
7025-
Value *X, *Y;
7025+
Value *X, *Y, *Z;
70267026
// Transform (X & ~Y) == 0 --> (X & Y) != 0
70277027
// and (X & ~Y) != 0 --> (X & Y) == 0
70287028
// if A is a power of 2.
@@ -7032,6 +7032,22 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
70327032
return new ICmpInst(I.getInversePredicate(), Builder.CreateAnd(X, Y),
70337033
Op1);
70347034

7035+
// Transform (~X ^ Y) s< ~Z --> (X ^ Y) s> Z,
7036+
// (~X ^ Y) s> ~Z --> (X ^ Y) s< Z,
7037+
// (~X ^ Y) s<= ~Z --> (X ^ Y) s>= Z,
7038+
// (~X ^ Y) s>= ~Z --> (X ^ Y) s<= Z,
7039+
// (~X ^ Y) u< ~Z --> (X ^ Y) u< Z,
7040+
// (~X ^ Y) u> ~Z --> (X ^ Y) u< Z,
7041+
// (~X ^ Y) u<= ~Z --> (X ^ Y) u>= Z,
7042+
// (~X ^ Y) u>= ~Z --> (X ^ Y) u<= Z,
7043+
// (~X ^ Y) == ~Z --> (X ^ Y) == Z,
7044+
// and (~X ^ Y) != ~Z --> (X ^ Y) != Z,
7045+
if (match(&I, m_c_ICmp(Pred, m_c_Xor(m_Not(m_Value(X)), m_Value(Y)),
7046+
m_Not(m_Value(Z)))) &&
7047+
(I.getOperand(0)->hasOneUse() || I.getOperand(1)->hasOneUse()))
7048+
return new ICmpInst(I.getSwappedPredicate(Pred), Builder.CreateXor(X, Y),
7049+
Z);
7050+
70357051
// ~X < ~Y --> Y < X
70367052
// ~X < C --> X > ~C
70377053
if (match(Op0, m_Not(m_Value(X)))) {

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

Lines changed: 32 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
1010
; CHECK-LABEL: @test_xor1(
1111
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X:%.*]], -1
1212
; CHECK-NEXT: call void @use.i8(i8 [[XOR]])
13-
; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
14-
; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
15-
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[XOR2]], [[NZ]]
13+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
14+
; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
1615
; CHECK-NEXT: ret i1 [[R]]
1716
;
1817
%xor = xor i8 %x, -1
@@ -26,11 +25,10 @@ define i1 @test_xor1(i8 %x, i8 %y, i8 %z) {
2625
; test for ~z <= (x ^ ~y)
2726
define i1 @test_xor2(i8 %x, i8 %y, i8 %z) {
2827
; CHECK-LABEL: @test_xor2(
29-
; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
3028
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[Y:%.*]], -1
3129
; CHECK-NEXT: call void @use.i8(i8 [[XOR]])
32-
; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[XOR]], [[X:%.*]]
33-
; CHECK-NEXT: [[R:%.*]] = icmp sge i8 [[XOR2]], [[NZ]]
30+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[Y]], [[X:%.*]]
31+
; CHECK-NEXT: [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
3432
; CHECK-NEXT: ret i1 [[R]]
3533
;
3634
%nz = xor i8 %z, -1
@@ -44,11 +42,10 @@ define i1 @test_xor2(i8 %x, i8 %y, i8 %z) {
4442
; test for ~z > (~x ^ y)
4543
define i1 @test_xor3(i8 %x, i8 %y, i8 %z) {
4644
; CHECK-LABEL: @test_xor3(
47-
; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
4845
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X:%.*]], -1
4946
; CHECK-NEXT: call void @use.i8(i8 [[XOR]])
50-
; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
51-
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[XOR2]], [[NZ]]
47+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
48+
; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[TMP1]], [[Z:%.*]]
5249
; CHECK-NEXT: ret i1 [[R]]
5350
;
5451
%nz = xor i8 %z, -1
@@ -89,11 +86,10 @@ define i1 @test_xor_eq(i8 %x, i8 %y, i8 %z) {
8986
; other tests
9087
define i1 @test_xor4(i8 %x, i8 %y, i8 %z) {
9188
; CHECK-LABEL: @test_xor4(
92-
; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
9389
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X:%.*]], -1
9490
; CHECK-NEXT: call void @use.i8(i8 [[XOR]])
95-
; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
96-
; CHECK-NEXT: [[R:%.*]] = icmp sge i8 [[XOR2]], [[NZ]]
91+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
92+
; CHECK-NEXT: [[R:%.*]] = icmp sle i8 [[TMP1]], [[Z:%.*]]
9793
; CHECK-NEXT: ret i1 [[R]]
9894
;
9995
%nz = xor i8 %z, -1
@@ -106,11 +102,10 @@ define i1 @test_xor4(i8 %x, i8 %y, i8 %z) {
106102

107103
define i1 @test_xor5(i8 %x, i8 %y, i8 %z) {
108104
; CHECK-LABEL: @test_xor5(
109-
; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
110105
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X:%.*]], -1
111106
; CHECK-NEXT: call void @use.i8(i8 [[XOR]])
112-
; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
113-
; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[XOR2]], [[NZ]]
107+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
108+
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[TMP1]], [[Z:%.*]]
114109
; CHECK-NEXT: ret i1 [[R]]
115110
;
116111
%nz = xor i8 %z, -1
@@ -123,11 +118,10 @@ define i1 @test_xor5(i8 %x, i8 %y, i8 %z) {
123118

124119
define i1 @test_xor6(i8 %x, i8 %y, i8 %z) {
125120
; CHECK-LABEL: @test_xor6(
126-
; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
127121
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X:%.*]], -1
128122
; CHECK-NEXT: call void @use.i8(i8 [[XOR]])
129-
; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
130-
; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[XOR2]], [[NZ]]
123+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
124+
; CHECK-NEXT: [[R:%.*]] = icmp uge i8 [[TMP1]], [[Z:%.*]]
131125
; CHECK-NEXT: ret i1 [[R]]
132126
;
133127
%nz = xor i8 %z, -1
@@ -140,11 +134,10 @@ define i1 @test_xor6(i8 %x, i8 %y, i8 %z) {
140134

141135
define i1 @test_xor7(i8 %x, i8 %y, i8 %z) {
142136
; CHECK-LABEL: @test_xor7(
143-
; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
144137
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X:%.*]], -1
145138
; CHECK-NEXT: call void @use.i8(i8 [[XOR]])
146-
; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
147-
; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[XOR2]], [[NZ]]
139+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
140+
; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[TMP1]], [[Z:%.*]]
148141
; CHECK-NEXT: ret i1 [[R]]
149142
;
150143
%nz = xor i8 %z, -1
@@ -157,11 +150,10 @@ define i1 @test_xor7(i8 %x, i8 %y, i8 %z) {
157150

158151
define i1 @test_xor8(i8 %x, i8 %y, i8 %z) {
159152
; CHECK-LABEL: @test_xor8(
160-
; CHECK-NEXT: [[NZ:%.*]] = xor i8 [[Z:%.*]], -1
161153
; CHECK-NEXT: [[XOR:%.*]] = xor i8 [[X:%.*]], -1
162154
; CHECK-NEXT: call void @use.i8(i8 [[XOR]])
163-
; CHECK-NEXT: [[XOR2:%.*]] = xor i8 [[XOR]], [[Y:%.*]]
164-
; CHECK-NEXT: [[R:%.*]] = icmp uge i8 [[XOR2]], [[NZ]]
155+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y:%.*]]
156+
; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[TMP1]], [[Z:%.*]]
165157
; CHECK-NEXT: ret i1 [[R]]
166158
;
167159
%nz = xor i8 %z, -1
@@ -175,9 +167,8 @@ define i1 @test_xor8(i8 %x, i8 %y, i8 %z) {
175167
; test (~a ^ b) < ~a
176168
define i1 @test_slt_xor(i32 %x, i32 %y) {
177169
; CHECK-LABEL: @test_slt_xor(
178-
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[X:%.*]], -1
179-
; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[XOR1]], [[Y:%.*]]
180-
; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[XOR2]], [[XOR1]]
170+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
171+
; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[TMP1]], [[X]]
181172
; CHECK-NEXT: ret i1 [[R]]
182173
;
183174
%xor1 = xor i32 %x, -1
@@ -189,9 +180,8 @@ define i1 @test_slt_xor(i32 %x, i32 %y) {
189180
; test (a ^ ~b) <= ~b
190181
define i1 @test_sle_xor(i32 %x, i32 %y) {
191182
; CHECK-LABEL: @test_sle_xor(
192-
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[Y:%.*]], -1
193-
; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[XOR1]], [[X:%.*]]
194-
; CHECK-NEXT: [[R:%.*]] = icmp sle i32 [[XOR2]], [[XOR1]]
183+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
184+
; CHECK-NEXT: [[R:%.*]] = icmp sge i32 [[TMP1]], [[Y]]
195185
; CHECK-NEXT: ret i1 [[R]]
196186
;
197187
%xor1 = xor i32 %y, -1
@@ -203,9 +193,8 @@ define i1 @test_sle_xor(i32 %x, i32 %y) {
203193
; test ~a > (~a ^ b)
204194
define i1 @test_sgt_xor(i32 %x, i32 %y) {
205195
; CHECK-LABEL: @test_sgt_xor(
206-
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[X:%.*]], -1
207-
; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[XOR1]], [[Y:%.*]]
208-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[XOR2]], [[XOR1]]
196+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
197+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP1]], [[X]]
209198
; CHECK-NEXT: ret i1 [[CMP]]
210199
;
211200
%xor1 = xor i32 %x, -1
@@ -216,9 +205,8 @@ define i1 @test_sgt_xor(i32 %x, i32 %y) {
216205

217206
define i1 @test_sge_xor(i32 %x, i32 %y) {
218207
; CHECK-LABEL: @test_sge_xor(
219-
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[X:%.*]], -1
220-
; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[XOR1]], [[Y:%.*]]
221-
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[XOR2]], [[XOR1]]
208+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
209+
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[TMP1]], [[X]]
222210
; CHECK-NEXT: ret i1 [[CMP]]
223211
;
224212
%xor1 = xor i32 %x, -1
@@ -229,9 +217,8 @@ define i1 @test_sge_xor(i32 %x, i32 %y) {
229217

230218
define i1 @test_ult_xor(i32 %x, i32 %y) {
231219
; CHECK-LABEL: @test_ult_xor(
232-
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[X:%.*]], -1
233-
; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[XOR1]], [[Y:%.*]]
234-
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[XOR2]], [[XOR1]]
220+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
221+
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[TMP1]], [[X]]
235222
; CHECK-NEXT: ret i1 [[CMP]]
236223
;
237224
%xor1 = xor i32 %x, -1
@@ -242,9 +229,8 @@ define i1 @test_ult_xor(i32 %x, i32 %y) {
242229

243230
define i1 @test_ule_xor(i32 %x, i32 %y) {
244231
; CHECK-LABEL: @test_ule_xor(
245-
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[X:%.*]], -1
246-
; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[XOR1]], [[Y:%.*]]
247-
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[XOR2]], [[XOR1]]
232+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
233+
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[TMP1]], [[X]]
248234
; CHECK-NEXT: ret i1 [[CMP]]
249235
;
250236
%xor1 = xor i32 %x, -1
@@ -255,9 +241,8 @@ define i1 @test_ule_xor(i32 %x, i32 %y) {
255241

256242
define i1 @test_ugt_xor(i32 %x, i32 %y) {
257243
; CHECK-LABEL: @test_ugt_xor(
258-
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[X:%.*]], -1
259-
; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[XOR1]], [[Y:%.*]]
260-
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[XOR2]], [[XOR1]]
244+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
245+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP1]], [[X]]
261246
; CHECK-NEXT: ret i1 [[CMP]]
262247
;
263248
%xor1 = xor i32 %x, -1
@@ -268,9 +253,8 @@ define i1 @test_ugt_xor(i32 %x, i32 %y) {
268253

269254
define i1 @test_uge_xor(i32 %x, i32 %y) {
270255
; CHECK-LABEL: @test_uge_xor(
271-
; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[X:%.*]], -1
272-
; CHECK-NEXT: [[XOR2:%.*]] = xor i32 [[XOR1]], [[Y:%.*]]
273-
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i32 [[XOR2]], [[XOR1]]
256+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
257+
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[TMP1]], [[X]]
274258
; CHECK-NEXT: ret i1 [[CMP]]
275259
;
276260
%xor1 = xor i32 %x, -1

0 commit comments

Comments
 (0)