Skip to content

Commit 7c18e17

Browse files
committed
[InstCombine] Fold xor of bittests intto bittest of xor'd values
1 parent dceb898 commit 7c18e17

File tree

2 files changed

+30
-26
lines changed

2 files changed

+30
-26
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4150,9 +4150,6 @@ Value *InstCombinerImpl::foldXorOfICmps(ICmpInst *LHS, ICmpInst *RHS,
41504150
}
41514151
}
41524152

4153-
// TODO: This can be generalized to compares of non-signbits using
4154-
// decomposeBitTestICmp(). It could be enhanced more by using (something like)
4155-
// foldLogOpOfMaskedICmps().
41564153
const APInt *LC, *RC;
41574154
if (match(LHS1, m_APInt(LC)) && match(RHS1, m_APInt(RC)) &&
41584155
LHS0->getType() == RHS0->getType() &&
@@ -4200,6 +4197,21 @@ Value *InstCombinerImpl::foldXorOfICmps(ICmpInst *LHS, ICmpInst *RHS,
42004197
}
42014198
}
42024199
}
4200+
4201+
// Fold (icmp eq/ne (X & Pow2), 0) ^ (icmp eq/ne (Y & Pow2), 0) into
4202+
// (icmp eq/ne ((X ^ Y) & Pow2), 0)
4203+
Value *X, *Y;
4204+
const APInt *Mask;
4205+
if (ICmpInst::isEquality(PredL) && ICmpInst::isEquality(PredR) &&
4206+
LC->isZero() && RC->isZero() && LHS->hasOneUse() && RHS->hasOneUse() &&
4207+
match(LHS0, m_And(m_Value(X), m_Power2(Mask))) &&
4208+
match(RHS0, m_And(m_Value(Y), m_SpecificInt(*Mask)))) {
4209+
Value *Xor = Builder.CreateXor(X, Y);
4210+
Value *And = Builder.CreateAnd(Xor, *Mask);
4211+
return Builder.CreateICmp(PredL == PredR ? ICmpInst::ICMP_NE
4212+
: ICmpInst::ICMP_EQ,
4213+
And, ConstantInt::getNullValue(Xor->getType()));
4214+
}
42034215
}
42044216

42054217
// Instead of trying to imitate the folds for and/or, decompose this 'xor'

llvm/test/Transforms/InstCombine/xor-icmps.ll

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -322,12 +322,10 @@ define i1 @xor_icmp_to_icmp_add_multiuse2(i32 %a) {
322322

323323
define i1 @test_xor_of_bittest_ne_ne(i8 %x, i8 %y) {
324324
; CHECK-LABEL: @test_xor_of_bittest_ne_ne(
325-
; CHECK-NEXT: [[MASK1:%.*]] = and i8 [[X:%.*]], 2
326-
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[MASK1]], 0
327-
; CHECK-NEXT: [[MASK2:%.*]] = and i8 [[Y:%.*]], 2
325+
; CHECK-NEXT: [[Y:%.*]] = xor i8 [[X:%.*]], [[Y1:%.*]]
326+
; CHECK-NEXT: [[MASK2:%.*]] = and i8 [[Y]], 2
328327
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[MASK2]], 0
329-
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CMP1]], [[CMP2]]
330-
; CHECK-NEXT: ret i1 [[XOR]]
328+
; CHECK-NEXT: ret i1 [[CMP2]]
331329
;
332330
%mask1 = and i8 %x, 2
333331
%cmp1 = icmp ne i8 %mask1, 0
@@ -339,11 +337,9 @@ define i1 @test_xor_of_bittest_ne_ne(i8 %x, i8 %y) {
339337

340338
define i1 @test_xor_of_bittest_eq_eq(i8 %x, i8 %y) {
341339
; CHECK-LABEL: @test_xor_of_bittest_eq_eq(
342-
; CHECK-NEXT: [[MASK1:%.*]] = and i8 [[X:%.*]], 2
343-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[MASK1]], 0
344-
; CHECK-NEXT: [[MASK2:%.*]] = and i8 [[Y:%.*]], 2
345-
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[MASK2]], 0
346-
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CMP1]], [[CMP2]]
340+
; CHECK-NEXT: [[Y:%.*]] = xor i8 [[X:%.*]], [[Y1:%.*]]
341+
; CHECK-NEXT: [[MASK2:%.*]] = and i8 [[Y]], 2
342+
; CHECK-NEXT: [[XOR:%.*]] = icmp ne i8 [[MASK2]], 0
347343
; CHECK-NEXT: ret i1 [[XOR]]
348344
;
349345
%mask1 = and i8 %x, 2
@@ -356,12 +352,10 @@ define i1 @test_xor_of_bittest_eq_eq(i8 %x, i8 %y) {
356352

357353
define i1 @test_xor_of_bittest_ne_eq(i8 %x, i8 %y) {
358354
; CHECK-LABEL: @test_xor_of_bittest_ne_eq(
359-
; CHECK-NEXT: [[MASK1:%.*]] = and i8 [[X:%.*]], 2
360-
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[MASK1]], 0
361-
; CHECK-NEXT: [[MASK2:%.*]] = and i8 [[Y:%.*]], 2
355+
; CHECK-NEXT: [[Y:%.*]] = xor i8 [[X:%.*]], [[Y1:%.*]]
356+
; CHECK-NEXT: [[MASK2:%.*]] = and i8 [[Y]], 2
362357
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i8 [[MASK2]], 0
363-
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CMP1]], [[CMP2]]
364-
; CHECK-NEXT: ret i1 [[XOR]]
358+
; CHECK-NEXT: ret i1 [[CMP2]]
365359
;
366360
%mask1 = and i8 %x, 2
367361
%cmp1 = icmp ne i8 %mask1, 0
@@ -373,12 +367,10 @@ define i1 @test_xor_of_bittest_ne_eq(i8 %x, i8 %y) {
373367

374368
define i1 @test_xor_of_bittest_eq_ne(i8 %x, i8 %y) {
375369
; CHECK-LABEL: @test_xor_of_bittest_eq_ne(
376-
; CHECK-NEXT: [[MASK1:%.*]] = and i8 [[X:%.*]], 2
370+
; CHECK-NEXT: [[X:%.*]] = xor i8 [[X1:%.*]], [[Y:%.*]]
371+
; CHECK-NEXT: [[MASK1:%.*]] = and i8 [[X]], 2
377372
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[MASK1]], 0
378-
; CHECK-NEXT: [[MASK2:%.*]] = and i8 [[Y:%.*]], 2
379-
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[MASK2]], 0
380-
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CMP1]], [[CMP2]]
381-
; CHECK-NEXT: ret i1 [[XOR]]
373+
; CHECK-NEXT: ret i1 [[CMP1]]
382374
;
383375
%mask1 = and i8 %x, 2
384376
%cmp1 = icmp eq i8 %mask1, 0
@@ -392,11 +384,11 @@ define i1 @test_xor_of_bittest_ne_ne_multiuse1(i8 %x, i8 %y) {
392384
; CHECK-LABEL: @test_xor_of_bittest_ne_ne_multiuse1(
393385
; CHECK-NEXT: [[MASK1:%.*]] = and i8 [[X:%.*]], 2
394386
; CHECK-NEXT: call void @usei8(i8 [[MASK1]])
395-
; CHECK-NEXT: [[CMP1:%.*]] = icmp ne i8 [[MASK1]], 0
396387
; CHECK-NEXT: [[MASK2:%.*]] = and i8 [[Y:%.*]], 2
397388
; CHECK-NEXT: call void @usei8(i8 [[MASK2]])
398-
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i8 [[MASK2]], 0
399-
; CHECK-NEXT: [[XOR:%.*]] = xor i1 [[CMP1]], [[CMP2]]
389+
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[X]], [[Y]]
390+
; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[TMP1]], 2
391+
; CHECK-NEXT: [[XOR:%.*]] = icmp ne i8 [[TMP2]], 0
400392
; CHECK-NEXT: ret i1 [[XOR]]
401393
;
402394
%mask1 = and i8 %x, 2

0 commit comments

Comments
 (0)