[llvm] [InstCombine] Modify `foldSelectICmpEq` to only handle more useful and simple cases. (PR #121672)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 5 01:46:33 PST 2025
================
@@ -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
----------------
nikic wrote:
In conjunction with my suggestion for the eq case, a principled way to handle this would be to extend https://github.com/llvm/llvm-project/blob/3321c2d72ab7757dbdd38bdd99a76d89293dac8a/llvm/lib/Analysis/InstructionSimplify.cpp#L4711-L4721 and simplifyWithOpReplaced to support multiple replacements at the same time, instead of trying to replace X and Y with 0 individually. (Whether this is feasible depends on the compile-time impact of course.)
https://github.com/llvm/llvm-project/pull/121672
More information about the llvm-commits
mailing list