[llvm] [InstCombine] Handle multi-use in simplifyAndOrWithOpReplaced() (PR #81006)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 7 10:01:30 PST 2024
https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/81006
>From 8e24b3e056b9827b61a945aeafdd44145e7dd9a7 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Wed, 7 Feb 2024 16:22:27 +0100
Subject: [PATCH] [InstCombine] Handle multi-use in
simplifyAndOrWithOpReplaced()
Slightly generalize simplifyAndOrWithOpReplaced() by allowing it
to perform simplifications (without creating new instructions) in
multi-use cases. This way we can remove existing patterns without
worrying about multi-use edge cases.
I've opted to change the general way the implementation works to
be more similar to the standard simplifyWithOpReplaced(). We
perform the operand replacement generically, and then try to
simplify the result or create a new instruction if we're allowed
to do so.
---
.../InstCombine/InstCombineAndOrXor.cpp | 86 +++++++++----------
llvm/test/Transforms/InstCombine/or.ll | 3 +-
2 files changed, 43 insertions(+), 46 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index aa3b9da924aa0b..1b35c4a5ccf7d2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2220,44 +2220,42 @@ 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,
+static Value *simplifyAndOrWithOpReplaced(Value *V, Value *Op, Value *RepOp,
+ bool SimplifyOnly,
InstCombinerImpl &IC,
unsigned Depth = 0) {
- if (isa<Constant>(X) || X == Y)
+ if (Op == RepOp)
return nullptr;
- Value *RHS;
- if (match(X, m_c_And(m_Specific(Y), m_Value(RHS)))) {
- return IsAnd ? RHS : Constant::getNullValue(X->getType());
- } else if (match(X, m_c_Or(m_Specific(Y), m_Value(RHS)))) {
- return IsAnd ? Constant::getAllOnesValue(X->getType()) : RHS;
- } else if (match(X, m_c_Xor(m_Specific(Y), m_Value(RHS)))) {
- if (IsAnd) {
- if (X->hasOneUse())
- return IC.Builder.CreateNot(RHS);
+ if (V == Op)
+ return RepOp;
- if (Value *NotRHS =
- IC.getFreelyInverted(RHS, RHS->hasOneUse(), &IC.Builder))
- return NotRHS;
- } else
- return RHS;
- }
+ auto *I = dyn_cast<BinaryOperator>(V);
+ if (!I || !I->isBitwiseLogicOp() || Depth >= 3)
+ return nullptr;
- // Replace uses of Y in X recursively.
- Value *Op0, *Op1;
- if (Depth < 2 && match(X, m_BitwiseLogic(m_Value(Op0), m_Value(Op1)))) {
- // 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(cast<BinaryOperator>(X)->getOpcode(),
- NewOp0 ? NewOp0 : Op0, NewOp1 ? NewOp1 : Op1);
- }
- return nullptr;
+ if (!I->hasOneUse())
+ SimplifyOnly = true;
+
+ Value *NewOp0 = simplifyAndOrWithOpReplaced(I->getOperand(0), Op, RepOp,
+ SimplifyOnly, IC, Depth + 1);
+ Value *NewOp1 = simplifyAndOrWithOpReplaced(I->getOperand(1), Op, RepOp,
+ SimplifyOnly, IC, Depth + 1);
+ if (!NewOp0 && !NewOp1)
+ return nullptr;
+
+ if (!NewOp0)
+ NewOp0 = I->getOperand(0);
+ if (!NewOp1)
+ NewOp1 = I->getOperand(1);
+
+ if (Value *Res = simplifyBinOp(I->getOpcode(), NewOp0, NewOp1,
+ IC.getSimplifyQuery().getWithInstruction(I)))
+ return Res;
+
+ if (SimplifyOnly)
+ return nullptr;
+ return IC.Builder.CreateBinOp(I->getOpcode(), NewOp0, NewOp1);
}
// FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
@@ -2781,9 +2779,13 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
if (Instruction *Res = foldBitwiseLogicWithIntrinsics(I, Builder))
return Res;
- if (Value *V = simplifyAndOrWithOpReplaced(Op0, Op1, /*IsAnd*/ true, *this))
+ if (Value *V =
+ simplifyAndOrWithOpReplaced(Op0, Op1, Constant::getAllOnesValue(Ty),
+ /*SimplifyOnly*/ false, *this))
return BinaryOperator::CreateAnd(V, Op1);
- if (Value *V = simplifyAndOrWithOpReplaced(Op1, Op0, /*IsAnd*/ true, *this))
+ if (Value *V =
+ simplifyAndOrWithOpReplaced(Op1, Op0, Constant::getAllOnesValue(Ty),
+ /*SimplifyOnly*/ false, *this))
return BinaryOperator::CreateAnd(Op0, V);
return nullptr;
@@ -3602,14 +3604,6 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
if (match(Op1, m_Xor(m_Specific(B), m_Specific(A))))
return BinaryOperator::CreateOr(Op1, C);
- // ((A & B) ^ C) | B -> C | B
- if (match(Op0, m_c_Xor(m_c_And(m_Value(A), m_Specific(Op1)), m_Value(C))))
- return BinaryOperator::CreateOr(C, Op1);
-
- // B | ((A & B) ^ C) -> B | C
- if (match(Op1, m_c_Xor(m_c_And(m_Value(A), m_Specific(Op0)), m_Value(C))))
- return BinaryOperator::CreateOr(Op0, C);
-
if (Instruction *DeMorgan = matchDeMorgansLaws(I, *this))
return DeMorgan;
@@ -3965,9 +3959,13 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
if (Instruction *Res = foldBitwiseLogicWithIntrinsics(I, Builder))
return Res;
- if (Value *V = simplifyAndOrWithOpReplaced(Op0, Op1, /*IsAnd*/ false, *this))
+ if (Value *V =
+ simplifyAndOrWithOpReplaced(Op0, Op1, Constant::getNullValue(Ty),
+ /*SimplifyOnly*/ false, *this))
return BinaryOperator::CreateOr(V, Op1);
- if (Value *V = simplifyAndOrWithOpReplaced(Op1, Op0, /*IsAnd*/ false, *this))
+ if (Value *V =
+ simplifyAndOrWithOpReplaced(Op1, Op0, Constant::getNullValue(Ty),
+ /*SimplifyOnly*/ false, *this))
return BinaryOperator::CreateOr(Op0, V);
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 51863af37c131c..1b1a6ffbf0f2d3 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -1938,8 +1938,7 @@ define i32 @test_or_and_and_multiuse(i32 %a, i32 %b, i32 %c) {
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
; CHECK-NEXT: call void @use(i32 [[AND1]])
; CHECK-NEXT: call void @use(i32 [[AND2]])
-; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND2]], [[A]]
-; CHECK-NEXT: ret i32 [[OR]]
+; CHECK-NEXT: ret i32 [[A]]
;
%and1 = and i32 %a, %b
%and2 = and i32 %and1, %c
More information about the llvm-commits
mailing list