[llvm] [InstCombine] Modify `foldSelectICmpEq` to only handle more useful and simple cases. (PR #121672)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jan 4 17:20:45 PST 2025
https://github.com/goldsteinn created https://github.com/llvm/llvm-project/pull/121672
The original intent of the folds (from #71792) where to handle selects
where the condition was a bitwise operator compared with zero.
During review of the original PR (#73362), however, we ended up over
generalizing at the expense of code complexity, and ironically in a
way that didn't actually fix the issue as reported.
The goal of this PR is to simplify the code and only handle the
compares with zero cases that actually show up in the real world.
New code handles three cases:
1) `X & Y == 0` implies `X | Y == X ^ Y` thus:
- `X & Y == 0 ? X |/^/+ Y : X |/^/+ Y` -> `X |/^/+ Y` (the false arm)
- https://alive2.llvm.org/ce/z/jjcduh
2) `X | Y == 0` implies `X == Y == 0` thus for `Op0` and `Op1` s.t
`0 Op0 0 == 0 Op1 0 == 0`:
- `X & Y == 0 ? X Op0 Y : X Op1 Y` -> `X Op1 Y`
- `X & Y == 0 ? 0 : X Op1 Y` -> `X Op1 Y`
- https://alive2.llvm.org/ce/z/RBuFQE
3) `X ^ Y == 0` (`X == Y`) implies `X | Y == X & Y`:
- `X ^ Y == 0 ? X | Y : X & Y` -> `X & Y`
- `X ^ Y == 0 ? X & Y : X | Y` -> `X | Y`
- https://alive2.llvm.org/ce/z/SJskbz
>From ee59139acb3995a7688e77ec35b87f408dc31a68 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Sat, 4 Jan 2025 19:05:10 -0600
Subject: [PATCH] [InstCombine] Modify `foldSelectICmpEq` to only handle more
useful and simple cases.
The original intent of the folds (from #71792) where to handle selects
where the condition was a bitwise operator compared with zero.
During review of the original PR (#73362), however, we ended up over
generalizing at the expense of code complexity, and ironically in a
way that didn't actually fix the issue as reported.
The goal of this PR is to simplify the code and only handle the
compares with zero cases that actually show up in the real world.
New code handles three cases:
1) `X & Y == 0` implies `X | Y == X ^ Y` thus:
- `X & Y == 0 ? X |/^/+ Y : X |/^/+ Y` -> `X |/^/+ Y` (the false arm)
- https://alive2.llvm.org/ce/z/jjcduh
2) `X | Y == 0` implies `X == Y == 0` thus for `Op0` and `Op1` s.t
`0 Op0 0 == 0 Op1 0 == 0`:
- `X & Y == 0 ? X Op0 Y : X Op1 Y` -> `X Op1 Y`
- `X & Y == 0 ? 0 : X Op1 Y` -> `X Op1 Y`
- https://alive2.llvm.org/ce/z/RBuFQE
3) `X ^ Y == 0` (`X == Y`) implies `X | Y == X & Y`:
- `X ^ Y == 0 ? X | Y : X & Y` -> `X & Y`
- `X ^ Y == 0 ? X & Y : X | Y` -> `X | Y`
- https://alive2.llvm.org/ce/z/SJskbz
---
.../InstCombine/InstCombineSelect.cpp | 147 ++++++-------
llvm/test/Transforms/InstCombine/select.ll | 195 +++++++++++-------
2 files changed, 183 insertions(+), 159 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index e7a8e947705f8d..2838d45fcc7cd9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1821,8 +1821,12 @@ static Instruction *foldSelectWithExtremeEqCond(Value *CmpLHS, Value *CmpRHS,
return new ICmpInst(Pred, CmpLHS, B);
}
+// Fold (X Op0 Y) == 0 ? (X Op1 Y) : (X Op2 Y)
+// -> (X Op2 Y)
+// By proving that `(X Op1 Y) == (X Op2 Y)` in the context of `(X Op0 Y) == 0`.
static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
InstCombinerImpl &IC) {
+
ICmpInst::Predicate Pred = ICI->getPredicate();
if (!ICmpInst::isEquality(Pred))
return nullptr;
@@ -1835,96 +1839,79 @@ static Instruction *foldSelectICmpEq(SelectInst &SI, ICmpInst *ICI,
if (Pred == ICmpInst::ICMP_NE)
std::swap(TrueVal, FalseVal);
- if (Instruction *Res =
- foldSelectWithExtremeEqCond(CmpLHS, CmpRHS, TrueVal, FalseVal))
- return Res;
+ if (auto *R = foldSelectWithExtremeEqCond(CmpLHS, CmpRHS, TrueVal, FalseVal))
+ return R;
- // Transform (X == C) ? X : Y -> (X == C) ? C : Y
- // specific handling for Bitwise operation.
- // x&y -> (x|y) ^ (x^y) or (x|y) & ~(x^y)
- // x|y -> (x&y) | (x^y) or (x&y) ^ (x^y)
- // x^y -> (x|y) ^ (x&y) or (x|y) & ~(x&y)
Value *X, *Y;
- if (!match(CmpLHS, m_BitwiseLogic(m_Value(X), m_Value(Y))) ||
- !match(TrueVal, m_c_BitwiseLogic(m_Specific(X), m_Specific(Y))))
- return nullptr;
-
- const unsigned AndOps = Instruction::And, OrOps = Instruction::Or,
- XorOps = Instruction::Xor, NoOps = 0;
- enum NotMask { None = 0, NotInner, NotRHS };
-
- auto matchFalseVal = [&](unsigned OuterOpc, unsigned InnerOpc,
- unsigned NotMask) {
- auto matchInner = m_c_BinOp(InnerOpc, m_Specific(X), m_Specific(Y));
- if (OuterOpc == NoOps)
- return match(CmpRHS, m_Zero()) && match(FalseVal, matchInner);
-
- if (NotMask == NotInner) {
- return match(FalseVal, m_c_BinOp(OuterOpc, m_NotForbidPoison(matchInner),
- m_Specific(CmpRHS)));
- } else if (NotMask == NotRHS) {
- return match(FalseVal, m_c_BinOp(OuterOpc, matchInner,
- m_NotForbidPoison(m_Specific(CmpRHS))));
- } else {
- return match(FalseVal,
- m_c_BinOp(OuterOpc, matchInner, m_Specific(CmpRHS)));
- }
- };
-
- // (X&Y)==C ? X|Y : X^Y -> (X^Y)|C : X^Y or (X^Y)^ C : X^Y
- // (X&Y)==C ? X^Y : X|Y -> (X|Y)^C : X|Y or (X|Y)&~C : X|Y
- if (match(CmpLHS, m_And(m_Value(X), m_Value(Y)))) {
- if (match(TrueVal, m_c_Or(m_Specific(X), m_Specific(Y)))) {
- // (X&Y)==C ? X|Y : (X^Y)|C -> (X^Y)|C : (X^Y)|C -> (X^Y)|C
- // (X&Y)==C ? X|Y : (X^Y)^C -> (X^Y)^C : (X^Y)^C -> (X^Y)^C
- if (matchFalseVal(OrOps, XorOps, None) ||
- matchFalseVal(XorOps, XorOps, None))
- return IC.replaceInstUsesWith(SI, FalseVal);
- } else if (match(TrueVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
- // (X&Y)==C ? X^Y : (X|Y)^ C -> (X|Y)^ C : (X|Y)^ C -> (X|Y)^ C
- // (X&Y)==C ? X^Y : (X|Y)&~C -> (X|Y)&~C : (X|Y)&~C -> (X|Y)&~C
- if (matchFalseVal(XorOps, OrOps, None) ||
- matchFalseVal(AndOps, OrOps, NotRHS))
+ if (match(CmpRHS, m_Zero())) {
+ // (X & Y) == 0 ? X |/^/+ Y : X |/^/+ Y -> X |/^/+ Y (false arm)
+ // `(X & Y) == 0` implies no common bits which means:
+ // `X ^ Y == X | Y == X + Y`
+ // https://alive2.llvm.org/ce/z/jjcduh
+ if (match(CmpLHS, m_And(m_Value(X), m_Value(Y)))) {
+ auto MatchAddOrXor =
+ m_CombineOr(m_c_Add(m_Specific(X), m_Specific(Y)),
+ m_CombineOr(m_c_Or(m_Specific(X), m_Specific(Y)),
+ m_c_Xor(m_Specific(X), m_Specific(Y))));
+ if (match(TrueVal, MatchAddOrXor) && match(FalseVal, MatchAddOrXor))
return IC.replaceInstUsesWith(SI, FalseVal);
}
- }
- // (X|Y)==C ? X&Y : X^Y -> (X^Y)^C : X^Y or ~(X^Y)&C : X^Y
- // (X|Y)==C ? X^Y : X&Y -> (X&Y)^C : X&Y or ~(X&Y)&C : X&Y
- if (match(CmpLHS, m_Or(m_Value(X), m_Value(Y)))) {
- if (match(TrueVal, m_c_And(m_Specific(X), m_Specific(Y)))) {
- // (X|Y)==C ? X&Y: (X^Y)^C -> (X^Y)^C: (X^Y)^C -> (X^Y)^C
- // (X|Y)==C ? X&Y:~(X^Y)&C ->~(X^Y)&C:~(X^Y)&C -> ~(X^Y)&C
- if (matchFalseVal(XorOps, XorOps, None) ||
- matchFalseVal(AndOps, XorOps, NotInner))
- return IC.replaceInstUsesWith(SI, FalseVal);
- } else if (match(TrueVal, m_c_Xor(m_Specific(X), m_Specific(Y)))) {
- // (X|Y)==C ? X^Y : (X&Y)^C -> (X&Y)^C : (X&Y)^C -> (X&Y)^C
- // (X|Y)==C ? X^Y :~(X&Y)&C -> ~(X&Y)&C :~(X&Y)&C -> ~(X&Y)&C
- if (matchFalseVal(XorOps, AndOps, None) ||
- matchFalseVal(AndOps, AndOps, NotInner))
- return IC.replaceInstUsesWith(SI, FalseVal);
- }
- }
+ // (X | Y) == 0 ? X Op0 Y : X Op1 Y -> X Op1 Y
+ // For any `Op0` and `Op1` that are zero when `X` and `Y` are zero.
+ // https://alive2.llvm.org/ce/z/azHzBW
+ if (match(CmpLHS, m_Or(m_Value(X), m_Value(Y))) &&
+ (match(TrueVal, m_c_BinOp(m_Specific(X), m_Specific(Y))) ||
+ // In true arm we can also accept just `0`.
+ match(TrueVal, m_Zero())) &&
+ match(FalseVal, m_c_BinOp(m_Specific(X), m_Specific(Y)))) {
+ auto IsOpcZeroWithZeros = [](Value *V) {
+ auto *I = dyn_cast<Instruction>(V);
+ if (!I)
+ return false;
+ switch (I->getOpcode()) {
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ case Instruction::Mul:
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Shl:
+ case Instruction::AShr:
+ case Instruction::LShr:
+ return true;
+ default:
+ return false;
+ }
+ };
- // (X^Y)==C ? X&Y : X|Y -> (X|Y)^C : X|Y or (X|Y)&~C : X|Y
- // (X^Y)==C ? X|Y : X&Y -> (X&Y)|C : X&Y or (X&Y)^ C : X&Y
- if (match(CmpLHS, m_Xor(m_Value(X), m_Value(Y)))) {
- if ((match(TrueVal, m_c_And(m_Specific(X), m_Specific(Y))))) {
- // (X^Y)==C ? X&Y : (X|Y)^C -> (X|Y)^C
- // (X^Y)==C ? X&Y : (X|Y)&~C -> (X|Y)&~C
- if (matchFalseVal(XorOps, OrOps, None) ||
- matchFalseVal(AndOps, OrOps, NotRHS))
- return IC.replaceInstUsesWith(SI, FalseVal);
- } else if (match(TrueVal, m_c_Or(m_Specific(X), m_Specific(Y)))) {
- // (X^Y)==C ? (X|Y) : (X&Y)|C -> (X&Y)|C
- // (X^Y)==C ? (X|Y) : (X&Y)^C -> (X&Y)^C
- if (matchFalseVal(OrOps, AndOps, None) ||
- matchFalseVal(XorOps, AndOps, None))
+ if ((match(TrueVal, m_Zero()) || IsOpcZeroWithZeros(TrueVal)) &&
+ IsOpcZeroWithZeros(FalseVal))
return IC.replaceInstUsesWith(SI, FalseVal);
}
}
+ // (X == Y) ? X | Y : X & Y
+ // (X == Y) ? X & Y : X | Y
+ // If `X == Y` then `X == Y == X | Y == X & Y`.
+ // NB: `X == Y` is canonicalization of `(X ^ Y) == 0`.
+ // https://alive2.llvm.org/ce/z/SJskbz
+ X = CmpLHS;
+ Y = CmpRHS;
+ auto MatchOrAnd = m_CombineOr(m_c_Or(m_Specific(X), m_Specific(Y)),
+ m_c_And(m_Specific(X), m_Specific(Y)));
+ if (match(FalseVal, MatchOrAnd) &&
+ // In the true arm we can also just match `X` or `Y`.
+ (match(TrueVal, MatchOrAnd) || match(TrueVal, m_Specific(X)) ||
+ match(TrueVal, m_Specific(Y)))) {
+ // Can't preserve `or disjoint` here so rebuild.
+ auto *BO = dyn_cast<BinaryOperator>(FalseVal);
+ if (!BO)
+ return nullptr;
+ return IC.replaceInstUsesWith(
+ SI, IC.Builder.CreateBinOp(BO->getOpcode(), BO->getOperand(0),
+ BO->getOperand(1)));
+ }
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 0168a804239a89..f8067d6eade640 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -3764,12 +3764,8 @@ exit:
define i32 @src_and_eq_0_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_eq_0_or_xor(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[XOR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret i32 [[XOR]]
;
entry:
%and = and i32 %y, %x
@@ -3784,12 +3780,8 @@ entry:
define i32 @src_and_eq_0_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_and_eq_0_xor_or(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[OR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret i32 [[OR]]
;
entry:
%and = and i32 %y, %x
@@ -3841,9 +3833,13 @@ entry:
define i32 @src_and_eq_C_or_xororC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_and_eq_C_or_xororC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[XOR]], [[C:%.*]]
-; CHECK-NEXT: ret i32 [[OR1]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], [[C:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[OR1:%.*]] = or i32 [[XOR]], [[C]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[OR1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%and = and i32 %y, %x
@@ -3858,9 +3854,13 @@ entry:
define i32 @src_and_eq_C_or_xorxorC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_and_eq_C_or_xorxorC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[XOR]], [[C:%.*]]
-; CHECK-NEXT: ret i32 [[XOR1]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], [[C:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[XOR]], [[C]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[XOR1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%and = and i32 %y, %x
@@ -3875,10 +3875,14 @@ entry:
define i32 @src_and_eq_C_xor_OrAndNotC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_and_eq_C_xor_OrAndNotC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], [[C:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[C]], -1
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[OR]], [[NOT]]
-; CHECK-NEXT: ret i32 [[AND1]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[AND1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%and = and i32 %y, %x
@@ -3917,9 +3921,13 @@ entry:
define i32 @src_and_eq_C_xor_orxorC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_and_eq_C_xor_orxorC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[OR]], [[C:%.*]]
-; CHECK-NEXT: ret i32 [[XOR1]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], [[C:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[OR]], [[C]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[XOR1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%and = and i32 %y, %x
@@ -3937,11 +3945,8 @@ entry:
define i32 @src_or_eq_0_and_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_eq_0_and_xor(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 0, i32 [[XOR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret i32 [[XOR]]
;
entry:
%or = or i32 %y, %x
@@ -3956,11 +3961,8 @@ entry:
define i32 @src_or_eq_0_xor_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_eq_0_xor_and(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 0, i32 [[AND]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: ret i32 [[AND]]
;
entry:
%or = or i32 %y, %x
@@ -3974,9 +3976,13 @@ entry:
define i32 @src_or_eq_neg1_and_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_eq_neg1_and_xor(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[TMP0:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[TMP0:%.*]] = xor i32 [[X]], [[Y]]
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[TMP0]], -1
-; CHECK-NEXT: ret i32 [[NOT]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[NOT]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%or = or i32 %y, %x
@@ -3991,9 +3997,13 @@ entry:
define i32 @src_or_eq_neg1_xor_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_or_eq_neg1_xor_and(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[AND]], -1
-; CHECK-NEXT: ret i32 [[NOT]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[NOT]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%or = or i32 %y, %x
@@ -4008,9 +4018,13 @@ entry:
define i32 @src_or_eq_C_and_xorC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_or_eq_C_and_xorC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[XOR]], [[C:%.*]]
-; CHECK-NEXT: ret i32 [[XOR1]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], [[C:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[XOR]], [[C]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[XOR1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%or = or i32 %y, %x
@@ -4025,10 +4039,14 @@ entry:
define i32 @src_or_eq_C_and_andnotxorC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_or_eq_C_and_andnotxorC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[TMP0:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], [[C:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[TMP0:%.*]] = xor i32 [[X]], [[Y]]
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[TMP0]], -1
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[C:%.*]], [[NOT]]
-; CHECK-NEXT: ret i32 [[AND1]]
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[C]], [[NOT]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[AND1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%or = or i32 %y, %x
@@ -4044,9 +4062,13 @@ entry:
define i32 @src_or_eq_C_xor_xorandC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_or_eq_C_xor_xorandC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[AND]], [[C:%.*]]
-; CHECK-NEXT: ret i32 [[XOR1]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], [[C:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[AND]], [[C]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[XOR1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%or = or i32 %y, %x
@@ -4061,10 +4083,14 @@ entry:
define i32 @src_or_eq_C_xor_andnotandC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_or_eq_C_xor_andnotandC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[OR]], [[C:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y]], [[X]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[AND]], -1
-; CHECK-NEXT: [[AND1:%.*]] = and i32 [[C:%.*]], [[NOT]]
-; CHECK-NEXT: ret i32 [[AND1]]
+; CHECK-NEXT: [[AND1:%.*]] = and i32 [[C]], [[NOT]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[XOR]], i32 [[AND1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%or = or i32 %y, %x
@@ -4082,9 +4108,13 @@ entry:
define i32 @src_xor_eq_neg1_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_xor_eq_neg1_and(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[XOR]], -1
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[OR]], -1
-; CHECK-NEXT: ret i32 [[NOT]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[NOT]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%xor = xor i32 %y, %x
@@ -4117,9 +4147,13 @@ entry:
define i32 @src_xor_eq_C_and_xororC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_xor_eq_C_and_xororC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[OR]], [[C:%.*]]
-; CHECK-NEXT: ret i32 [[XOR1]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[OR]], [[C]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[XOR1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%xor = xor i32 %y, %x
@@ -4134,10 +4168,14 @@ entry:
define i32 @src_xor_eq_C_and_andornotC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_xor_eq_C_and_andornotC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[C:%.*]], -1
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[NOT:%.*]] = xor i32 [[C]], -1
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[OR]], [[NOT]]
-; CHECK-NEXT: ret i32 [[AND1]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[AND]], i32 [[AND1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%xor = xor i32 %y, %x
@@ -4153,9 +4191,13 @@ entry:
define i32 @src_xor_eq_C_or_xorandC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_xor_eq_C_or_xorandC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[AND]], [[C:%.*]]
-; CHECK-NEXT: ret i32 [[XOR1]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[XOR1:%.*]] = xor i32 [[AND]], [[C]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[XOR1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%xor = xor i32 %y, %x
@@ -4170,9 +4212,13 @@ entry:
define i32 @src_xor_eq_C_or_orandC(i32 %x, i32 %y, i32 %c) {
; CHECK-LABEL: @src_xor_eq_C_or_orandC(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y:%.*]], [[X:%.*]]
-; CHECK-NEXT: [[OR1:%.*]] = or i32 [[AND]], [[C:%.*]]
-; CHECK-NEXT: ret i32 [[OR1]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[XOR]], [[C:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[Y]], [[X]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[Y]], [[X]]
+; CHECK-NEXT: [[OR1:%.*]] = or i32 [[AND]], [[C]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[OR]], i32 [[OR1]]
+; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%xor = xor i32 %y, %x
@@ -4438,11 +4484,8 @@ define i32 @src_no_trans_select_and_eq0_xor_and(i32 %x, i32 %y) {
define i32 @src_no_trans_select_or_eq0_or_and(i32 %x, i32 %y) {
; CHECK-LABEL: @src_no_trans_select_or_eq0_or_and(
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 0, i32 [[AND]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: ret i32 [[AND]]
;
%or = or i32 %x, %y
%or0 = icmp eq i32 %or, 0
@@ -4453,11 +4496,8 @@ define i32 @src_no_trans_select_or_eq0_or_and(i32 %x, i32 %y) {
define i32 @src_no_trans_select_or_eq0_or_xor(i32 %x, i32 %y) {
; CHECK-LABEL: @src_no_trans_select_or_eq0_or_xor(
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0]], i32 0, i32 [[XOR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: ret i32 [[XOR]]
;
%or = or i32 %x, %y
%or0 = icmp eq i32 %or, 0
@@ -4492,11 +4532,8 @@ define i32 @src_no_trans_select_or_eq0_xor_or(i32 %x, i32 %y) {
define i32 @src_no_trans_select_and_ne0_xor_or(i32 %x, i32 %y) {
; CHECK-LABEL: @src_no_trans_select_and_ne0_xor_or(
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[OR0_NOT:%.*]] = icmp eq i32 [[OR]], 0
-; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X]], [[Y]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[OR0_NOT]], i32 0, i32 [[XOR]]
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: ret i32 [[XOR]]
;
%or = or i32 %x, %y
%or0 = icmp ne i32 %or, 0
More information about the llvm-commits
mailing list