[llvm] [InstCombine] Simplify and/or by replacing operands with constants (PR #77231)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Jan 17 11:39:35 PST 2024
================
@@ -2179,6 +2179,62 @@ foldBitwiseLogicWithIntrinsics(BinaryOperator &I,
}
}
+// Try to simplify X | Y by replacing occurrences of Y in X with 0.
+// Similarly, simplify X & Y by replacing occurrences of Y in X with -1.
+// Return the simplified result of X if successful, and nullptr otherwise.
+static Value *simplifyAndOrWithOpReplaced(Value *X, Value *Y, bool IsAnd,
+ InstCombinerImpl &IC,
+ unsigned Depth = 0) {
+ if (isa<Constant>(X) || X == Y)
+ return nullptr;
+
+ auto RecursivelyReplaceUses = [&](Instruction::BinaryOps Opcode, Value *Op0,
+ Value *Op1) -> Value * {
+ if (Depth == 2)
+ return nullptr;
+
+ // TODO: Relax the one-use constraint to clean up existing hard-coded
+ // simplifications.
+ if (!X->hasOneUse())
+ return nullptr;
+ Value *NewOp0 = simplifyAndOrWithOpReplaced(Op0, Y, IsAnd, IC, Depth + 1);
+ Value *NewOp1 = simplifyAndOrWithOpReplaced(Op1, Y, IsAnd, IC, Depth + 1);
+ if (!NewOp0 && !NewOp1)
+ return nullptr;
+ return IC.Builder.CreateBinOp(Opcode, NewOp0 ? NewOp0 : Op0,
+ NewOp1 ? NewOp1 : Op1);
+ };
+
+ Value *Op0, *Op1;
+ if (match(X, m_And(m_Value(Op0), m_Value(Op1)))) {
+ if (Op0 == Y || Op1 == Y)
+ return IsAnd ? (Op0 == Y ? Op1 : Op0)
+ : Constant::getNullValue(X->getType());
+ return RecursivelyReplaceUses(Instruction::And, Op0, Op1);
+ } else if (match(X, m_Or(m_Value(Op0), m_Value(Op1)))) {
+ if (Op0 == Y || Op1 == Y)
+ return IsAnd ? Constant::getAllOnesValue(X->getType())
+ : (Op0 == Y ? Op1 : Op0);
+ return RecursivelyReplaceUses(Instruction::Or, Op0, Op1);
+ } else if (match(X, m_Xor(m_Value(Op0), m_Value(Op1)))) {
+ if (Op0 == Y || Op1 == Y) {
+ Value *V = Op0 == Y ? Op1 : Op0;
+ if (IsAnd) {
+ if (Value *NotV =
+ simplifyXorInst(V, Constant::getAllOnesValue(V->getType()),
+ IC.getSimplifyQuery()))
+ return NotV;
+ if (X->hasOneUse())
+ return IC.Builder.CreateNot(V);
+ } else
+ return V;
+ }
+ // FIXME: Is it correct to decompose xor if Y may be undef?
+ return RecursivelyReplaceUses(Instruction::Xor, Op0, Op1);
+ }
----------------
goldsteinn wrote:
I think as a general rewrite, it might be cleaner to do the following:
```
if(match(X, m_c_And(m_Specific(Y), m_Value(Op)) {
// And logic
}
if(match(X, m_c_Or(m_Specific(Y), m_Value(Op)) {
// Or Logic
}
if(match(X, m_c_Xor(m_Specific(Y), m_Value(Op)) {
// Xor Logic
}
if(match(X, m_BitWiseOperator(m_Value(Op0), m_Value(Op1)) {
return recursivelyMatch(cast<instruction>(X)->getOpcode(), Op0, Op1);
}
```
Then you could drop the `if (Op0 == Y || Op1 == Y) {` and ternary logic on `Y == Op0...` in all the scopes and not duplcate the recursive call 3x places.
https://github.com/llvm/llvm-project/pull/77231
More information about the llvm-commits
mailing list