Skip to content

Commit 8e24b3e

Browse files
committed
[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.
1 parent e71a5f5 commit 8e24b3e

File tree

2 files changed

+43
-46
lines changed

2 files changed

+43
-46
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2220,44 +2220,42 @@ foldBitwiseLogicWithIntrinsics(BinaryOperator &I,
22202220
// Try to simplify X | Y by replacing occurrences of Y in X with 0.
22212221
// Similarly, simplify X & Y by replacing occurrences of Y in X with -1.
22222222
// Return the simplified result of X if successful, and nullptr otherwise.
2223-
static Value *simplifyAndOrWithOpReplaced(Value *X, Value *Y, bool IsAnd,
2223+
static Value *simplifyAndOrWithOpReplaced(Value *V, Value *Op, Value *RepOp,
2224+
bool SimplifyOnly,
22242225
InstCombinerImpl &IC,
22252226
unsigned Depth = 0) {
2226-
if (isa<Constant>(X) || X == Y)
2227+
if (Op == RepOp)
22272228
return nullptr;
22282229

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);
2230+
if (V == Op)
2231+
return RepOp;
22382232

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

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;
2237+
if (!I->hasOneUse())
2238+
SimplifyOnly = true;
2239+
2240+
Value *NewOp0 = simplifyAndOrWithOpReplaced(I->getOperand(0), Op, RepOp,
2241+
SimplifyOnly, IC, Depth + 1);
2242+
Value *NewOp1 = simplifyAndOrWithOpReplaced(I->getOperand(1), Op, RepOp,
2243+
SimplifyOnly, IC, Depth + 1);
2244+
if (!NewOp0 && !NewOp1)
2245+
return nullptr;
2246+
2247+
if (!NewOp0)
2248+
NewOp0 = I->getOperand(0);
2249+
if (!NewOp1)
2250+
NewOp1 = I->getOperand(1);
2251+
2252+
if (Value *Res = simplifyBinOp(I->getOpcode(), NewOp0, NewOp1,
2253+
IC.getSimplifyQuery().getWithInstruction(I)))
2254+
return Res;
2255+
2256+
if (SimplifyOnly)
2257+
return nullptr;
2258+
return IC.Builder.CreateBinOp(I->getOpcode(), NewOp0, NewOp1);
22612259
}
22622260

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

2784-
if (Value *V = simplifyAndOrWithOpReplaced(Op0, Op1, /*IsAnd*/ true, *this))
2782+
if (Value *V =
2783+
simplifyAndOrWithOpReplaced(Op0, Op1, Constant::getAllOnesValue(Ty),
2784+
/*SimplifyOnly*/ false, *this))
27852785
return BinaryOperator::CreateAnd(V, Op1);
2786-
if (Value *V = simplifyAndOrWithOpReplaced(Op1, Op0, /*IsAnd*/ true, *this))
2786+
if (Value *V =
2787+
simplifyAndOrWithOpReplaced(Op1, Op0, Constant::getAllOnesValue(Ty),
2788+
/*SimplifyOnly*/ false, *this))
27872789
return BinaryOperator::CreateAnd(Op0, V);
27882790

27892791
return nullptr;
@@ -3602,14 +3604,6 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
36023604
if (match(Op1, m_Xor(m_Specific(B), m_Specific(A))))
36033605
return BinaryOperator::CreateOr(Op1, C);
36043606

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-
36133607
if (Instruction *DeMorgan = matchDeMorgansLaws(I, *this))
36143608
return DeMorgan;
36153609

@@ -3965,9 +3959,13 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
39653959
if (Instruction *Res = foldBitwiseLogicWithIntrinsics(I, Builder))
39663960
return Res;
39673961

3968-
if (Value *V = simplifyAndOrWithOpReplaced(Op0, Op1, /*IsAnd*/ false, *this))
3962+
if (Value *V =
3963+
simplifyAndOrWithOpReplaced(Op0, Op1, Constant::getNullValue(Ty),
3964+
/*SimplifyOnly*/ false, *this))
39693965
return BinaryOperator::CreateOr(V, Op1);
3970-
if (Value *V = simplifyAndOrWithOpReplaced(Op1, Op0, /*IsAnd*/ false, *this))
3966+
if (Value *V =
3967+
simplifyAndOrWithOpReplaced(Op1, Op0, Constant::getNullValue(Ty),
3968+
/*SimplifyOnly*/ false, *this))
39713969
return BinaryOperator::CreateOr(Op0, V);
39723970

39733971
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)