Skip to content

Commit 35d6ae8

Browse files
authored
[InstCombine] Handle multi-use in simplifyAndOrWithOpReplaced() (#81006)
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.
1 parent decbd29 commit 35d6ae8

File tree

2 files changed

+47
-48
lines changed

2 files changed

+47
-48
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,47 +2217,47 @@ foldBitwiseLogicWithIntrinsics(BinaryOperator &I,
22172217
}
22182218
}
22192219

2220-
// Try to simplify X | Y by replacing occurrences of Y in X with 0.
2221-
// Similarly, simplify X & Y by replacing occurrences of Y in X with -1.
2220+
// Try to simplify V by replacing occurrences of Op with RepOp, but only look
2221+
// through bitwise operations. In particular, for X | Y we try to replace Y with
2222+
// 0 inside X and for X & Y we try to replace Y with -1 inside X.
22222223
// Return the simplified result of X if successful, and nullptr otherwise.
2223-
static Value *simplifyAndOrWithOpReplaced(Value *X, Value *Y, bool IsAnd,
2224+
// If SimplifyOnly is true, no new instructions will be created.
2225+
static Value *simplifyAndOrWithOpReplaced(Value *V, Value *Op, Value *RepOp,
2226+
bool SimplifyOnly,
22242227
InstCombinerImpl &IC,
22252228
unsigned Depth = 0) {
2226-
if (isa<Constant>(X) || X == Y)
2229+
if (Op == RepOp)
22272230
return nullptr;
22282231

2229-
Value *RHS;
2230-
if (match(X, m_c_And(m_Specific(Y), m_Value(RHS)))) {
2231-
return IsAnd ? RHS : Constant::getNullValue(X->getType());
2232-
} else if (match(X, m_c_Or(m_Specific(Y), m_Value(RHS)))) {
2233-
return IsAnd ? Constant::getAllOnesValue(X->getType()) : RHS;
2234-
} else if (match(X, m_c_Xor(m_Specific(Y), m_Value(RHS)))) {
2235-
if (IsAnd) {
2236-
if (X->hasOneUse())
2237-
return IC.Builder.CreateNot(RHS);
2232+
if (V == Op)
2233+
return RepOp;
22382234

2239-
if (Value *NotRHS =
2240-
IC.getFreelyInverted(RHS, RHS->hasOneUse(), &IC.Builder))
2241-
return NotRHS;
2242-
} else
2243-
return RHS;
2244-
}
2235+
auto *I = dyn_cast<BinaryOperator>(V);
2236+
if (!I || !I->isBitwiseLogicOp() || Depth >= 3)
2237+
return nullptr;
22452238

2246-
// Replace uses of Y in X recursively.
2247-
Value *Op0, *Op1;
2248-
if (Depth < 2 && match(X, m_BitwiseLogic(m_Value(Op0), m_Value(Op1)))) {
2249-
// TODO: Relax the one-use constraint to clean up existing hard-coded
2250-
// simplifications.
2251-
if (!X->hasOneUse())
2252-
return nullptr;
2253-
Value *NewOp0 = simplifyAndOrWithOpReplaced(Op0, Y, IsAnd, IC, Depth + 1);
2254-
Value *NewOp1 = simplifyAndOrWithOpReplaced(Op1, Y, IsAnd, IC, Depth + 1);
2255-
if (!NewOp0 && !NewOp1)
2256-
return nullptr;
2257-
return IC.Builder.CreateBinOp(cast<BinaryOperator>(X)->getOpcode(),
2258-
NewOp0 ? NewOp0 : Op0, NewOp1 ? NewOp1 : Op1);
2259-
}
2260-
return nullptr;
2239+
if (!I->hasOneUse())
2240+
SimplifyOnly = true;
2241+
2242+
Value *NewOp0 = simplifyAndOrWithOpReplaced(I->getOperand(0), Op, RepOp,
2243+
SimplifyOnly, IC, Depth + 1);
2244+
Value *NewOp1 = simplifyAndOrWithOpReplaced(I->getOperand(1), Op, RepOp,
2245+
SimplifyOnly, IC, Depth + 1);
2246+
if (!NewOp0 && !NewOp1)
2247+
return nullptr;
2248+
2249+
if (!NewOp0)
2250+
NewOp0 = I->getOperand(0);
2251+
if (!NewOp1)
2252+
NewOp1 = I->getOperand(1);
2253+
2254+
if (Value *Res = simplifyBinOp(I->getOpcode(), NewOp0, NewOp1,
2255+
IC.getSimplifyQuery().getWithInstruction(I)))
2256+
return Res;
2257+
2258+
if (SimplifyOnly)
2259+
return nullptr;
2260+
return IC.Builder.CreateBinOp(I->getOpcode(), NewOp0, NewOp1);
22612261
}
22622262

22632263
// FIXME: We use commutative matchers (m_c_*) for some, but not all, matches
@@ -2781,9 +2781,13 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
27812781
if (Instruction *Res = foldBitwiseLogicWithIntrinsics(I, Builder))
27822782
return Res;
27832783

2784-
if (Value *V = simplifyAndOrWithOpReplaced(Op0, Op1, /*IsAnd*/ true, *this))
2784+
if (Value *V =
2785+
simplifyAndOrWithOpReplaced(Op0, Op1, Constant::getAllOnesValue(Ty),
2786+
/*SimplifyOnly*/ false, *this))
27852787
return BinaryOperator::CreateAnd(V, Op1);
2786-
if (Value *V = simplifyAndOrWithOpReplaced(Op1, Op0, /*IsAnd*/ true, *this))
2788+
if (Value *V =
2789+
simplifyAndOrWithOpReplaced(Op1, Op0, Constant::getAllOnesValue(Ty),
2790+
/*SimplifyOnly*/ false, *this))
27872791
return BinaryOperator::CreateAnd(Op0, V);
27882792

27892793
return nullptr;
@@ -3602,14 +3606,6 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
36023606
if (match(Op1, m_Xor(m_Specific(B), m_Specific(A))))
36033607
return BinaryOperator::CreateOr(Op1, C);
36043608

3605-
// ((A & B) ^ C) | B -> C | B
3606-
if (match(Op0, m_c_Xor(m_c_And(m_Value(A), m_Specific(Op1)), m_Value(C))))
3607-
return BinaryOperator::CreateOr(C, Op1);
3608-
3609-
// B | ((A & B) ^ C) -> B | C
3610-
if (match(Op1, m_c_Xor(m_c_And(m_Value(A), m_Specific(Op0)), m_Value(C))))
3611-
return BinaryOperator::CreateOr(Op0, C);
3612-
36133609
if (Instruction *DeMorgan = matchDeMorgansLaws(I, *this))
36143610
return DeMorgan;
36153611

@@ -3965,9 +3961,13 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
39653961
if (Instruction *Res = foldBitwiseLogicWithIntrinsics(I, Builder))
39663962
return Res;
39673963

3968-
if (Value *V = simplifyAndOrWithOpReplaced(Op0, Op1, /*IsAnd*/ false, *this))
3964+
if (Value *V =
3965+
simplifyAndOrWithOpReplaced(Op0, Op1, Constant::getNullValue(Ty),
3966+
/*SimplifyOnly*/ false, *this))
39693967
return BinaryOperator::CreateOr(V, Op1);
3970-
if (Value *V = simplifyAndOrWithOpReplaced(Op1, Op0, /*IsAnd*/ false, *this))
3968+
if (Value *V =
3969+
simplifyAndOrWithOpReplaced(Op1, Op0, Constant::getNullValue(Ty),
3970+
/*SimplifyOnly*/ false, *this))
39713971
return BinaryOperator::CreateOr(Op0, V);
39723972

39733973
return nullptr;

llvm/test/Transforms/InstCombine/or.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1938,8 +1938,7 @@ define i32 @test_or_and_and_multiuse(i32 %a, i32 %b, i32 %c) {
19381938
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[AND1]], [[C:%.*]]
19391939
; CHECK-NEXT: call void @use(i32 [[AND1]])
19401940
; CHECK-NEXT: call void @use(i32 [[AND2]])
1941-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND2]], [[A]]
1942-
; CHECK-NEXT: ret i32 [[OR]]
1941+
; CHECK-NEXT: ret i32 [[A]]
19431942
;
19441943
%and1 = and i32 %a, %b
19451944
%and2 = and i32 %and1, %c

0 commit comments

Comments
 (0)