Skip to content

Commit 413ab0a

Browse files
committed
support X==Y that transformed from X^Y==0
1 parent bd20058 commit 413ab0a

File tree

2 files changed

+51
-41
lines changed

2 files changed

+51
-41
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

+32-21
Original file line numberDiff line numberDiff line change
@@ -1831,11 +1831,26 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
18311831
InstCombinerImpl &IC) {
18321832
Value *X, *Y;
18331833
const APInt *C;
1834-
1835-
if (!((match(CmpLHS, m_BinOp(m_Value(X), m_Value(Y))) &&
1836-
match(CmpRHS, m_APInt(C))) &&
1837-
(match(TVal, m_c_BinOp(m_Specific(X), m_Value())) ||
1838-
match(TVal, m_c_BinOp(m_Specific(Y), m_Value())))))
1834+
unsigned CmpLHSOpc;
1835+
bool IsDisjoint = false;
1836+
// Specially handling for X^Y==0 transformed to X==Y
1837+
if (match(TVal, m_c_BitwiseLogic(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
1838+
X = CmpLHS;
1839+
Y = CmpRHS;
1840+
APInt ZeroVal = APInt::getZero(CmpLHS->getType()->getScalarSizeInBits());
1841+
C = const_cast<APInt *>(&ZeroVal);
1842+
CmpLHSOpc = Instruction::Xor;
1843+
} else if ((match(CmpLHS, m_BinOp(m_Value(X), m_Value(Y))) &&
1844+
match(CmpRHS, m_APInt(C))) &&
1845+
(match(TVal, m_c_BinOp(m_Specific(X), m_Value())) ||
1846+
match(TVal, m_c_BinOp(m_Specific(Y), m_Value())))) {
1847+
if (auto Inst = dyn_cast<PossiblyDisjointInst>(CmpLHS)) {
1848+
if (Inst->isDisjoint())
1849+
IsDisjoint = true;
1850+
CmpLHSOpc = Instruction::Or;
1851+
} else
1852+
CmpLHSOpc = cast<BinaryOperator>(CmpLHS)->getOpcode();
1853+
} else
18391854
return nullptr;
18401855

18411856
enum SpecialKnownBits {
@@ -1847,20 +1862,17 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
18471862

18481863
// We cannot know exactly what bits is known in X Y.
18491864
// Instead, we just know what relationship exist for.
1850-
auto isSpecialKnownBitsFor = [&](const Instruction *CmpLHS,
1851-
const APInt *CmpRHS) -> unsigned {
1852-
unsigned Opc = CmpLHS->getOpcode();
1853-
if (Opc == Instruction::And) {
1854-
if (CmpRHS->isZero())
1865+
auto isSpecialKnownBitsFor = [&]() -> unsigned {
1866+
if (CmpLHSOpc == Instruction::And) {
1867+
if (C->isZero())
18551868
return NoCommonBits;
1856-
} else if (Opc == Instruction::Xor) {
1857-
if (CmpRHS->isAllOnes())
1869+
} else if (CmpLHSOpc == Instruction::Xor) {
1870+
if (C->isAllOnes())
18581871
return NoCommonBits | AllBitsEnabled;
1859-
if (CmpRHS->isZero())
1872+
if (C->isZero())
18601873
return AllCommonBits;
1861-
} else if (auto Disjoint = dyn_cast<PossiblyDisjointInst>(CmpLHS);
1862-
Disjoint->isDisjoint()) {
1863-
if (CmpRHS->isAllOnes())
1874+
} else if (CmpLHSOpc == Instruction::Or && IsDisjoint) {
1875+
if (C->isAllOnes())
18641876
return NoCommonBits | AllBitsEnabled;
18651877
return NoCommonBits;
18661878
}
@@ -1879,10 +1891,9 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
18791891
Type *TValTy = TVal->getType();
18801892
unsigned BitWidth = TVal->getType()->getScalarSizeInBits();
18811893
auto TValBop = cast<BinaryOperator>(TVal);
1882-
auto CmpLHSBop = cast<BinaryOperator>(CmpLHS);
18831894
unsigned XOrder = hasOperandAt(TValBop, X);
18841895
unsigned YOrder = hasOperandAt(TValBop, Y);
1885-
unsigned SKB = isSpecialKnownBitsFor(CmpLHSBop, C);
1896+
unsigned SKB = isSpecialKnownBitsFor();
18861897

18871898
KnownBits Known;
18881899
if (TValBop->isBitwiseLogicOp()) {
@@ -1933,19 +1944,19 @@ static Instruction *foldSelectICmpBinOp(SelectInst &SI, ICmpInst *ICI,
19331944
CmpInst::Predicate Pred = ICI->getPredicate();
19341945
if (Pred == ICmpInst::ICMP_EQ) {
19351946
// Estimate additional KnownBits from the relationship between X and Y
1936-
if (CmpLHSBop->getOpcode() == Instruction::And) {
1947+
if (CmpLHSOpc == Instruction::And) {
19371948
// The bit that are set to 1 at `~C&Y` must be 0 in X
19381949
// The bit that are set to 1 at `~C&X` must be 0 in Y
19391950
XKnown.Zero |= ~*C & YKnown.One;
19401951
YKnown.Zero |= ~*C & XKnown.One;
19411952
}
1942-
if (CmpLHSBop->getOpcode() == Instruction::Or) {
1953+
if (CmpLHSOpc == Instruction::Or) {
19431954
// The bit that are set to 0 at `C&Y` must be 1 in X
19441955
// The bit that are set to 0 at `C&X` must be 1 in Y
19451956
XKnown.One |= *C & YKnown.Zero;
19461957
YKnown.One |= *C & XKnown.Zero;
19471958
}
1948-
if (CmpLHSBop->getOpcode() == Instruction::Xor) {
1959+
if (CmpLHSOpc == Instruction::Xor) {
19491960
// If X^Y==C, then X and Y must be either (1,0) or (0,1) for the
19501961
// enabled bits in C.
19511962
XKnown.One |= *C & YKnown.Zero;

llvm/test/Transforms/InstCombine/select.ll

+19-20
Original file line numberDiff line numberDiff line change
@@ -4474,9 +4474,9 @@ define i32 @src_select_or_ne0_or_and(i32 %x, i32 %y) {
44744474

44754475
define i32 @src_select_xor_eq0_and_xor(i32 %x, i32 %y) {
44764476
; CHECK-LABEL: @src_select_xor_eq0_and_xor(
4477-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
4478-
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
4479-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[X]], i32 [[XOR]]
4477+
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
4478+
; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 0, i32 [[Y]]
4479+
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
44804480
; CHECK-NEXT: ret i32 [[COND]]
44814481
;
44824482
%xor = xor i32 %x, %y
@@ -4488,9 +4488,9 @@ define i32 @src_select_xor_eq0_and_xor(i32 %x, i32 %y) {
44884488

44894489
define i32 @src_select_xor_ne0_xor_and(i32 %x, i32 %y) {
44904490
; CHECK-LABEL: @src_select_xor_ne0_xor_and(
4491-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
4492-
; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], 0
4493-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[X]], i32 [[XOR]]
4491+
; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
4492+
; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0_NOT]], i32 0, i32 [[Y]]
4493+
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
44944494
; CHECK-NEXT: ret i32 [[COND]]
44954495
;
44964496
%xor = xor i32 %x, %y
@@ -4502,9 +4502,9 @@ define i32 @src_select_xor_ne0_xor_and(i32 %x, i32 %y) {
45024502

45034503
define i32 @src_select_xor_eq0_or_xor(i32 %x, i32 %y) {
45044504
; CHECK-LABEL: @src_select_xor_eq0_or_xor(
4505-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
4506-
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[XOR]], 0
4507-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[X]], i32 [[XOR]]
4505+
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
4506+
; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 0, i32 [[Y]]
4507+
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
45084508
; CHECK-NEXT: ret i32 [[COND]]
45094509
;
45104510
%xor = xor i32 %x, %y
@@ -4516,9 +4516,9 @@ define i32 @src_select_xor_eq0_or_xor(i32 %x, i32 %y) {
45164516

45174517
define i32 @src_select_xor_ne0_xor_or(i32 %x, i32 %y) {
45184518
; CHECK-LABEL: @src_select_xor_ne0_xor_or(
4519-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
4520-
; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[XOR]], 0
4521-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0_NOT]], i32 [[X]], i32 [[XOR]]
4519+
; CHECK-NEXT: [[XOR0_NOT:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
4520+
; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0_NOT]], i32 0, i32 [[Y]]
4521+
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
45224522
; CHECK-NEXT: ret i32 [[COND]]
45234523
;
45244524
%xor = xor i32 %x, %y
@@ -4863,8 +4863,8 @@ define i32 @src_no_trans_select_xor_eq0_xor_and(i32 %x, i32 %y) {
48634863
ret i32 %cond
48644864
}
48654865

4866-
define i32 @src_no_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
4867-
; CHECK-LABEL: @src_no_trans_select_xor_eq0_xor_or(
4866+
define i32 @src_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
4867+
; CHECK-LABEL: @src_trans_select_xor_eq0_xor_or(
48684868
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
48694869
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
48704870
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 0, i32 [[OR]]
@@ -4877,12 +4877,11 @@ define i32 @src_no_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
48774877
ret i32 %cond
48784878
}
48794879

4880-
define i32 @src_no_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) {
4881-
; CHECK-LABEL: @src_no_trans_select_xor_eq0_and_xor(
4882-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
4883-
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X]], [[Y]]
4884-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
4885-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[XOR]]
4880+
define i32 @src_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) {
4881+
; CHECK-LABEL: @src_trans_select_xor_eq0_and_xor(
4882+
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
4883+
; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 0, i32 [[Y]]
4884+
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[X]]
48864885
; CHECK-NEXT: ret i32 [[COND]]
48874886
;
48884887
%xor = xor i32 %x, %y

0 commit comments

Comments
 (0)