Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[InstCombine] Simplify and/or of icmp eq with op replacement #70335

Merged
merged 1 commit into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 60 additions & 0 deletions llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2025,6 +2025,52 @@ static Value *simplifyAndOrOfCmps(const SimplifyQuery &Q, Value *Op0,
return nullptr;
}

static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *RepOp,
const SimplifyQuery &Q,
bool AllowRefinement,
SmallVectorImpl<Instruction *> *DropFlags,
unsigned MaxRecurse);

static Value *simplifyAndOrWithICmpEq(unsigned Opcode, Value *Op0, Value *Op1,
const SimplifyQuery &Q,
unsigned MaxRecurse) {
assert((Opcode == Instruction::And || Opcode == Instruction::Or) &&
"Must be and/or");
ICmpInst::Predicate Pred;
Value *A, *B;
if (!match(Op0, m_ICmp(Pred, m_Value(A), m_Value(B))) ||
!ICmpInst::isEquality(Pred) || !MaxRecurse--)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Would have recursive check first.

return nullptr;

auto Simplify = [&](Value *Res) -> Value * {
// and (icmp eq a, b), x implies (a==b) inside x.
// or (icmp ne a, b), x implies (a==b) inside x.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you get any benefit (and icmp ne (a, b), x) and use a != b inside x? (Likewise for eq + or?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we had a way to say "simplify x under the assumption that a != b", I would expect that to be beneficial. But we can only do this for equalities right now, as in that case we can just replace operands.

I think we need some generic way to say "evaluate this predicate under the assumption that v has range CR" -- some of @dtcxzyw's recent PRs go in that direction, but I feel like there must be a more generic solution to this, which integrates with existing range propagation logic, instead of reimplementing it in parts. This seems like something that LVI/CVP should be doing, but I don't see a good way to integrate it there.

// If x simplifies to true/false, we can simplify the and/or.
if (Pred ==
(Opcode == Instruction::And ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE))
return simplifyBinOp(Opcode, Op0, Res, Q, MaxRecurse);
// If we have and (icmp ne a, b), x and for a==b we can simplify x to false,
// then we can drop the icmp, as x will already be false in the case where
// the icmp is false. Similar for or and true.
if (Res == ConstantExpr::getBinOpAbsorber(Opcode, Res->getType()))
return Op1;
return nullptr;
};

// Increment MaxRecurse again, because simplifyWithOpReplaced() does its own
// decrement.
if (Value *Res =
simplifyWithOpReplaced(Op1, A, B, Q, /* AllowRefinement */ true,
/* DropFlags */ nullptr, MaxRecurse + 1))
return Simplify(Res);
if (Value *Res =
simplifyWithOpReplaced(Op1, B, A, Q, /* AllowRefinement */ true,
/* DropFlags */ nullptr, MaxRecurse + 1))
return Simplify(Res);

return nullptr;
}

/// Given a bitwise logic op, check if the operands are add/sub with a common
/// source value and inverted constant (identity: C - X -> ~(X + ~C)).
static Value *simplifyLogicOfAddSub(Value *Op0, Value *Op1,
Expand Down Expand Up @@ -2159,6 +2205,13 @@ static Value *simplifyAndInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
isKnownToBeAPowerOfTwo(Op0, Q.DL, /*OrZero*/ true, 0, Q.AC, Q.CxtI, Q.DT))
return Constant::getNullValue(Op0->getType());

if (Value *V =
simplifyAndOrWithICmpEq(Instruction::And, Op0, Op1, Q, MaxRecurse))
return V;
if (Value *V =
simplifyAndOrWithICmpEq(Instruction::And, Op1, Op0, Q, MaxRecurse))
return V;

if (Value *V = simplifyAndOrOfCmps(Q, Op0, Op1, true))
return V;

Expand Down Expand Up @@ -2435,6 +2488,13 @@ static Value *simplifyOrInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
match(Op0, m_LShr(m_Specific(X), m_Specific(Y))))
return Op1;

if (Value *V =
simplifyAndOrWithICmpEq(Instruction::Or, Op0, Op1, Q, MaxRecurse))
return V;
if (Value *V =
simplifyAndOrWithICmpEq(Instruction::Or, Op1, Op0, Q, MaxRecurse))
return V;

if (Value *V = simplifyAndOrOfCmps(Q, Op0, Op1, false))
return V;

Expand Down
10 changes: 3 additions & 7 deletions llvm/test/CodeGen/PowerPC/pr45448.ll
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,16 @@ define hidden void @julia_tryparse_internal_45896() #0 {
; CHECK-NEXT: .LBB0_6: # %fail194
; CHECK-NEXT: .LBB0_7: # %L670
; CHECK-NEXT: li r5, -3
; CHECK-NEXT: cmpdi r3, 0
; CHECK-NEXT: sradi r4, r3, 63
; CHECK-NEXT: rldic r5, r5, 4, 32
; CHECK-NEXT: crnot 4*cr5+lt, eq
; CHECK-NEXT: mulhdu r3, r3, r5
; CHECK-NEXT: maddld r6, r4, r5, r3
; CHECK-NEXT: cmpld cr1, r6, r3
; CHECK-NEXT: mulhdu. r3, r4, r5
; CHECK-NEXT: bc 4, 4*cr5+lt, .LBB0_10
; CHECK-NEXT: # %bb.8: # %L670
; CHECK-NEXT: crorc 4*cr5+lt, 4*cr1+lt, eq
; CHECK-NEXT: bc 4, 4*cr5+lt, .LBB0_10
; CHECK-NEXT: # %bb.9: # %L917
; CHECK-NEXT: .LBB0_10: # %L994
; CHECK-NEXT: bc 4, 4*cr5+lt, .LBB0_9
; CHECK-NEXT: # %bb.8: # %L917
; CHECK-NEXT: .LBB0_9: # %L994
top:
%0 = load i64, ptr undef, align 8
%1 = icmp ne i64 %0, 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ define i1 @n2_wrong_size(i4 %size0, i4 %size1, i4 %nmemb) {

define i1 @n3_wrong_pred(i4 %size, i4 %nmemb) {
; CHECK-LABEL: @n3_wrong_pred(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i4 [[SIZE:%.*]], 0
; CHECK-NEXT: [[SMUL:%.*]] = tail call { i4, i1 } @llvm.smul.with.overflow.i4(i4 [[SIZE]], i4 [[NMEMB:%.*]])
; CHECK-NEXT: [[SMUL_OV:%.*]] = extractvalue { i4, i1 } [[SMUL]], 1
; CHECK-NEXT: [[AND:%.*]] = and i1 [[SMUL_OV]], [[CMP]]
; CHECK-NEXT: ret i1 [[AND]]
; CHECK-NEXT: ret i1 false
;
%cmp = icmp eq i4 %size, 0 ; not 'ne'
%smul = tail call { i4, i1 } @llvm.smul.with.overflow.i4(i4 %size, i4 %nmemb)
Expand All @@ -63,10 +59,7 @@ define i1 @n3_wrong_pred(i4 %size, i4 %nmemb) {
define i1 @n4_not_and(i4 %size, i4 %nmemb) {
; CHECK-LABEL: @n4_not_and(
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i4 [[SIZE:%.*]], 0
; CHECK-NEXT: [[SMUL:%.*]] = tail call { i4, i1 } @llvm.smul.with.overflow.i4(i4 [[SIZE]], i4 [[NMEMB:%.*]])
; CHECK-NEXT: [[SMUL_OV:%.*]] = extractvalue { i4, i1 } [[SMUL]], 1
; CHECK-NEXT: [[AND:%.*]] = or i1 [[SMUL_OV]], [[CMP]]
; CHECK-NEXT: ret i1 [[AND]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%cmp = icmp ne i4 %size, 0
%smul = tail call { i4, i1 } @llvm.smul.with.overflow.i4(i4 %size, i4 %nmemb)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ define i1 @n2_wrong_size(i4 %size0, i4 %size1, i4 %nmemb) {

define i1 @n3_wrong_pred(i4 %size, i4 %nmemb) {
; CHECK-LABEL: @n3_wrong_pred(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i4 [[SIZE:%.*]], 0
; CHECK-NEXT: [[UMUL:%.*]] = tail call { i4, i1 } @llvm.umul.with.overflow.i4(i4 [[SIZE]], i4 [[NMEMB:%.*]])
; CHECK-NEXT: [[UMUL_OV:%.*]] = extractvalue { i4, i1 } [[UMUL]], 1
; CHECK-NEXT: [[AND:%.*]] = and i1 [[UMUL_OV]], [[CMP]]
; CHECK-NEXT: ret i1 [[AND]]
; CHECK-NEXT: ret i1 false
;
%cmp = icmp eq i4 %size, 0 ; not 'ne'
%umul = tail call { i4, i1 } @llvm.umul.with.overflow.i4(i4 %size, i4 %nmemb)
Expand All @@ -63,10 +59,7 @@ define i1 @n3_wrong_pred(i4 %size, i4 %nmemb) {
define i1 @n4_not_and(i4 %size, i4 %nmemb) {
; CHECK-LABEL: @n4_not_and(
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i4 [[SIZE:%.*]], 0
; CHECK-NEXT: [[UMUL:%.*]] = tail call { i4, i1 } @llvm.umul.with.overflow.i4(i4 [[SIZE]], i4 [[NMEMB:%.*]])
; CHECK-NEXT: [[UMUL_OV:%.*]] = extractvalue { i4, i1 } [[UMUL]], 1
; CHECK-NEXT: [[AND:%.*]] = or i1 [[UMUL_OV]], [[CMP]]
; CHECK-NEXT: ret i1 [[AND]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%cmp = icmp ne i4 %size, 0
%umul = tail call { i4, i1 } @llvm.umul.with.overflow.i4(i4 %size, i4 %nmemb)
Expand Down
24 changes: 5 additions & 19 deletions llvm/test/Transforms/InstCombine/ispow2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -392,9 +392,7 @@ define i1 @is_pow2_ctpop_wrong_pred1(i32 %x) {
; CHECK-LABEL: @is_pow2_ctpop_wrong_pred1(
; CHECK-NEXT: [[T0:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range [[RNG0]]
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[T0]], 2
; CHECK-NEXT: [[NOTZERO:%.*]] = icmp ne i32 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = and i1 [[NOTZERO]], [[CMP]]
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%t0 = tail call i32 @llvm.ctpop.i32(i32 %x)
%cmp = icmp ugt i32 %t0, 2
Expand Down Expand Up @@ -946,9 +944,7 @@ define i1 @is_pow2or0_ctpop_wrong_pred1(i32 %x) {
; CHECK-LABEL: @is_pow2or0_ctpop_wrong_pred1(
; CHECK-NEXT: [[T0:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range [[RNG0]]
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[T0]], 1
; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i32 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = or i1 [[ISZERO]], [[CMP]]
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%t0 = tail call i32 @llvm.ctpop.i32(i32 %x)
%cmp = icmp ne i32 %t0, 1
Expand All @@ -959,11 +955,7 @@ define i1 @is_pow2or0_ctpop_wrong_pred1(i32 %x) {

define i1 @is_pow2or0_ctpop_wrong_pred2(i32 %x) {
; CHECK-LABEL: @is_pow2or0_ctpop_wrong_pred2(
; CHECK-NEXT: [[T0:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range [[RNG0]]
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[T0]], 1
; CHECK-NEXT: [[ISZERO:%.*]] = icmp ne i32 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = or i1 [[ISZERO]], [[CMP]]
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 true
;
%t0 = tail call i32 @llvm.ctpop.i32(i32 %x)
%cmp = icmp ne i32 %t0, 1
Expand Down Expand Up @@ -1149,9 +1141,7 @@ define i1 @isnot_pow2nor0_ctpop_wrong_pred1(i32 %x) {
; CHECK-LABEL: @isnot_pow2nor0_ctpop_wrong_pred1(
; CHECK-NEXT: [[T0:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range [[RNG0]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[T0]], 1
; CHECK-NEXT: [[NOTZERO:%.*]] = icmp ne i32 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = and i1 [[NOTZERO]], [[CMP]]
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%t0 = tail call i32 @llvm.ctpop.i32(i32 %x)
%cmp = icmp eq i32 %t0, 1
Expand All @@ -1162,11 +1152,7 @@ define i1 @isnot_pow2nor0_ctpop_wrong_pred1(i32 %x) {

define i1 @isnot_pow2nor0_ctpop_wrong_pred2(i32 %x) {
; CHECK-LABEL: @isnot_pow2nor0_ctpop_wrong_pred2(
; CHECK-NEXT: [[T0:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range [[RNG0]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[T0]], 1
; CHECK-NEXT: [[NOTZERO:%.*]] = icmp eq i32 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = and i1 [[NOTZERO]], [[CMP]]
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 false
;
%t0 = tail call i32 @llvm.ctpop.i32(i32 %x)
%cmp = icmp eq i32 %t0, 1
Expand Down
10 changes: 2 additions & 8 deletions llvm/test/Transforms/InstSimplify/and-or-icmp-ctpop.ll
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,7 @@ define <2 x i1> @eq_or_non_0_commute(<2 x i32> %x) {

define i1 @eq_or_non_0_wrong_pred1(i32 %x) {
; CHECK-LABEL: @eq_or_non_0_wrong_pred1(
; CHECK-NEXT: [[T0:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[X:%.*]])
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[T0]], 10
; CHECK-NEXT: [[NOTZERO:%.*]] = icmp ne i32 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = or i1 [[NOTZERO]], [[CMP]]
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 true
;
%t0 = tail call i32 @llvm.ctpop.i32(i32 %x)
%cmp = icmp ne i32 %t0, 10
Expand Down Expand Up @@ -90,9 +86,7 @@ define i1 @ne_and_is_0_wrong_pred1(i32 %x) {
; CHECK-LABEL: @ne_and_is_0_wrong_pred1(
; CHECK-NEXT: [[T0:%.*]] = tail call i32 @llvm.ctpop.i32(i32 [[X:%.*]])
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[T0]], 10
; CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i32 [[X]], 0
; CHECK-NEXT: [[R:%.*]] = or i1 [[ISZERO]], [[CMP]]
; CHECK-NEXT: ret i1 [[R]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%t0 = tail call i32 @llvm.ctpop.i32(i32 %x)
%cmp = icmp ne i32 %t0, 10
Expand Down