diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index e7a8e947705f8..2838d45fcc7cd 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(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(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 0168a804239a8..f8067d6eade64 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