Skip to content

Commit a0cf8df

Browse files
committed
[InstCombine] fold y -> x in select arms with condition x == y
This cleans up regressions from folding multiuse: `(icmp eq/ne (sub/xor x, y), 0)` -> `(icmp eq/ne x, y)`.
1 parent 37b2ffc commit a0cf8df

File tree

3 files changed

+48
-23
lines changed

3 files changed

+48
-23
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,6 +1835,40 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
18351835
if (Instruction *NewSel = foldSelectICmpEq(SI, ICI, *this))
18361836
return NewSel;
18371837

1838+
// Very simple "GVN" on select arms if we have X == Y ? (binop X, Y) : ...
1839+
if (CmpRHS != CmpLHS && ICmpInst::isEquality(Pred)) {
1840+
auto IsFreeWithSelf = [](Instruction *I) {
1841+
// If we have I with all the same operand, does it completely simplify?
1842+
switch (I->getOpcode()) {
1843+
default:
1844+
return false;
1845+
case Instruction::And:
1846+
case Instruction::Xor:
1847+
case Instruction::Or:
1848+
case Instruction::Sub:
1849+
case Instruction::URem:
1850+
case Instruction::SRem:
1851+
case Instruction::UDiv:
1852+
case Instruction::SDiv:
1853+
return true;
1854+
}
1855+
};
1856+
1857+
Value *ReplaceIn = Pred == ICmpInst::ICMP_EQ ? TrueVal : FalseVal;
1858+
auto *BO = dyn_cast<BinaryOperator>(ReplaceIn);
1859+
if (BO != nullptr && (BO->hasOneUse() || IsFreeWithSelf(BO)) &&
1860+
match(BO, m_c_BinOp(m_Specific(CmpLHS), m_Specific(CmpRHS)))) {
1861+
// Replace with constant if we can (RHS). If RHS is not constant, use LHS
1862+
// if this will make it one use.
1863+
if (!match(CmpRHS, m_ImmConstant()) && CmpLHS->hasNUses(2))
1864+
CmpRHS = CmpLHS;
1865+
1866+
Value *NewArm = Builder.CreateBinOp(BO->getOpcode(), CmpRHS, CmpRHS);
1867+
replaceOperand(SI, Pred == ICmpInst::ICMP_EQ ? 1 : 2, NewArm);
1868+
return &SI;
1869+
}
1870+
}
1871+
18381872
// Canonicalize a signbit condition to use zero constant by swapping:
18391873
// (CmpLHS > -1) ? TV : FV --> (CmpLHS < 0) ? FV : TV
18401874
// To avoid conflicts (infinite loops) with other canonicalizations, this is

llvm/test/Transforms/InstCombine/abs-1.ll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -852,11 +852,8 @@ define i8 @abs_diff_signed_sgt_nuw_extra_use3(i8 %a, i8 %b) {
852852

853853
define i32 @abs_diff_signed_slt_swap_wrong_pred1(i32 %a, i32 %b) {
854854
; CHECK-LABEL: @abs_diff_signed_slt_swap_wrong_pred1(
855-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[B:%.*]], [[A:%.*]]
856-
; CHECK-NEXT: [[SUB_AB:%.*]] = sub nsw i32 [[A]], [[B]]
857-
; CHECK-NEXT: [[SUB_AB1:%.*]] = sub nsw i32 [[B]], [[A]]
858-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB_AB]], i32 [[SUB_AB1]]
859-
; CHECK-NEXT: ret i32 [[COND]]
855+
; CHECK-NEXT: [[SUB_AB1:%.*]] = sub nsw i32 [[B:%.*]], [[A:%.*]]
856+
; CHECK-NEXT: ret i32 [[SUB_AB1]]
860857
;
861858
%cmp = icmp eq i32 %a, %b
862859
%sub_ba = sub nsw i32 %b, %a

llvm/test/Transforms/InstCombine/select.ll

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2839,8 +2839,7 @@ define i8 @select_replacement_sub_noundef(i8 %x, i8 noundef %y, i8 %z) {
28392839
define i8 @select_replacement_sub(i8 %x, i8 %y, i8 %z) {
28402840
; CHECK-LABEL: @select_replacement_sub(
28412841
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
2842-
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
2843-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[SUB]], i8 [[Z:%.*]]
2842+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 0, i8 [[Z:%.*]]
28442843
; CHECK-NEXT: ret i8 [[SEL]]
28452844
;
28462845
%cmp = icmp eq i8 %x, %y
@@ -4430,10 +4429,9 @@ define i32 @src_no_trans_select_and_ne0_xor_or(i32 %x, i32 %y) {
44304429

44314430
define i32 @src_no_trans_select_xor_eq0_xor_and(i32 %x, i32 %y) {
44324431
; CHECK-LABEL: @src_no_trans_select_xor_eq0_xor_and(
4433-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
4434-
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X]], [[Y]]
4432+
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
44354433
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
4436-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[XOR]], i32 [[AND]]
4434+
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 0, i32 [[AND]]
44374435
; CHECK-NEXT: ret i32 [[COND]]
44384436
;
44394437
%xor = xor i32 %x, %y
@@ -4445,10 +4443,9 @@ define i32 @src_no_trans_select_xor_eq0_xor_and(i32 %x, i32 %y) {
44454443

44464444
define i32 @src_no_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
44474445
; CHECK-LABEL: @src_no_trans_select_xor_eq0_xor_or(
4448-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
4449-
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X]], [[Y]]
4446+
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
44504447
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
4451-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[XOR]], i32 [[OR]]
4448+
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 0, i32 [[OR]]
44524449
; CHECK-NEXT: ret i32 [[COND]]
44534450
;
44544451
%xor = xor i32 %x, %y
@@ -4460,10 +4457,9 @@ define i32 @src_no_trans_select_xor_eq0_xor_or(i32 %x, i32 %y) {
44604457

44614458
define i32 @src_no_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) {
44624459
; CHECK-LABEL: @src_no_trans_select_xor_eq0_and_xor(
4463-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
4464-
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X]], [[Y]]
4465-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
4466-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[AND]], i32 [[XOR]]
4460+
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
4461+
; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 0, i32 [[X]]
4462+
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[Y]]
44674463
; CHECK-NEXT: ret i32 [[COND]]
44684464
;
44694465
%xor = xor i32 %x, %y
@@ -4476,10 +4472,9 @@ define i32 @src_no_trans_select_xor_eq0_and_xor(i32 %x, i32 %y) {
44764472
; https://alive2.llvm.org/ce/z/SBe8ei
44774473
define i32 @src_no_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) {
44784474
; CHECK-LABEL: @src_no_trans_select_xor_eq0_or_xor(
4479-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
4480-
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X]], [[Y]]
4481-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[X]], [[Y]]
4482-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 [[OR]], i32 [[XOR]]
4475+
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
4476+
; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 0, i32 [[X]]
4477+
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[Y]]
44834478
; CHECK-NEXT: ret i32 [[COND]]
44844479
;
44854480
%xor = xor i32 %x, %y
@@ -4494,8 +4489,7 @@ define i32 @src_no_trans_select_xor_eq0_or_xor(i32 %x, i32 %y) {
44944489
define i32 @src_select_xxory_eq0_xorxy_y(i32 %x, i32 %y) {
44954490
; CHECK-LABEL: @src_select_xxory_eq0_xorxy_y(
44964491
; CHECK-NEXT: [[XOR0:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
4497-
; CHECK-NEXT: [[XOR:%.*]] = select i1 [[XOR0]], i32 [[X]], i32 0
4498-
; CHECK-NEXT: [[COND:%.*]] = xor i32 [[XOR]], [[Y]]
4492+
; CHECK-NEXT: [[COND:%.*]] = select i1 [[XOR0]], i32 0, i32 [[Y]]
44994493
; CHECK-NEXT: ret i32 [[COND]]
45004494
;
45014495
%xor = xor i32 %x, %y

0 commit comments

Comments
 (0)