[llvm] [InstCombine] Extend `foldICmpBinOp` to `add`-like `or`. (PR #71396)
Mikhail Gudim via llvm-commits
llvm-commits at lists.llvm.org
Fri Dec 15 20:31:10 PST 2023
https://github.com/mgudim updated https://github.com/llvm/llvm-project/pull/71396
>From 635d791655d26097e509ff492d9cd4b7c6d4db97 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Fri, 3 Nov 2023 16:15:36 -0400
Subject: [PATCH 1/2] [InstCombine] Extend `foldICmpBinOp` to `add`-like `or`.
InstCombine canonicalizes `add` to `or` when possible, but this makes
some optimizations applicable to `add` to be missed because they don't
realize that the `or` is equivalent to `add`.
In this patch we generalize `foldICmpBinOp` to handle such cases.
---
.../InstCombine/InstCombineCompares.cpp | 65 ++++++++++---------
.../InstCombine/disjoint-or-icmp.ll | 14 ++++
2 files changed, 48 insertions(+), 31 deletions(-)
create mode 100644 llvm/test/Transforms/InstCombine/disjoint-or-icmp.ll
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 289976718e52f3..023340b799e8fa 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4624,31 +4624,38 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
}
bool NoOp0WrapProblem = false, NoOp1WrapProblem = false;
- if (BO0 && isa<OverflowingBinaryOperator>(BO0))
- NoOp0WrapProblem =
- ICmpInst::isEquality(Pred) ||
- (CmpInst::isUnsigned(Pred) && BO0->hasNoUnsignedWrap()) ||
- (CmpInst::isSigned(Pred) && BO0->hasNoSignedWrap());
- if (BO1 && isa<OverflowingBinaryOperator>(BO1))
- NoOp1WrapProblem =
- ICmpInst::isEquality(Pred) ||
- (CmpInst::isUnsigned(Pred) && BO1->hasNoUnsignedWrap()) ||
- (CmpInst::isSigned(Pred) && BO1->hasNoSignedWrap());
-
+ bool Op0HasNUW = false, Op1HasNUW = false;
+ bool Op0HasNSW = false, Op1HasNSW = false;
// Analyze the case when either Op0 or Op1 is an add instruction.
// Op0 = A + B (or A and B are null); Op1 = C + D (or C and D are null).
Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr;
- if (BO0 && BO0->getOpcode() == Instruction::Add) {
- A = BO0->getOperand(0);
- B = BO0->getOperand(1);
+ auto hasNoWrapProblem = [&](const BinaryOperator &BO, const Value *X,
+ const Value *Y, bool &HasNSW,
+ bool &HasNUW) -> bool {
+ if (isa<OverflowingBinaryOperator>(BO)) {
+ HasNUW = BO.hasNoUnsignedWrap();
+ HasNSW = BO.hasNoSignedWrap();
+ return ICmpInst::isEquality(Pred) ||
+ (CmpInst::isUnsigned(Pred) && HasNUW) ||
+ (CmpInst::isSigned(Pred) && HasNSW);
+ } else if (BO0->getOpcode() == Instruction::Or) {
+ HasNUW = true;
+ HasNSW = true;
+ return true;
+ } else {
+ return false;
+ }
+ };
+
+ if (BO0) {
+ match(BO0, m_AddLike(m_Value(A), m_Value(B)));
+ NoOp0WrapProblem = hasNoWrapProblem(*BO0, A, B, Op0HasNSW, Op0HasNUW);
}
- if (BO1 && BO1->getOpcode() == Instruction::Add) {
- C = BO1->getOperand(0);
- D = BO1->getOperand(1);
+ if (BO1) {
+ match(BO1, m_AddLike(m_Value(C), m_Value(D)));
+ NoOp1WrapProblem = hasNoWrapProblem(*BO1, C, D, Op1HasNSW, Op1HasNUW);
}
- // icmp (A+B), A -> icmp B, 0 for equalities or if there is no overflow.
- // icmp (A+B), B -> icmp A, 0 for equalities or if there is no overflow.
if ((A == Op1 || B == Op1) && NoOp0WrapProblem)
return new ICmpInst(Pred, A == Op1 ? B : A,
Constant::getNullValue(Op1->getType()));
@@ -4764,17 +4771,15 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
APInt AP2Abs = AP2->abs();
if (AP1Abs.uge(AP2Abs)) {
APInt Diff = *AP1 - *AP2;
- bool HasNUW = BO0->hasNoUnsignedWrap() && Diff.ule(*AP1);
- bool HasNSW = BO0->hasNoSignedWrap();
Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff);
- Value *NewAdd = Builder.CreateAdd(A, C3, "", HasNUW, HasNSW);
+ Value *NewAdd = Builder.CreateAdd(
+ A, C3, "", Op0HasNUW && Diff.ule(*AP1), Op0HasNSW);
return new ICmpInst(Pred, NewAdd, C);
} else {
APInt Diff = *AP2 - *AP1;
- bool HasNUW = BO1->hasNoUnsignedWrap() && Diff.ule(*AP2);
- bool HasNSW = BO1->hasNoSignedWrap();
Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff);
- Value *NewAdd = Builder.CreateAdd(C, C3, "", HasNUW, HasNSW);
+ Value *NewAdd = Builder.CreateAdd(
+ C, C3, "", Op1HasNUW && Diff.ule(*AP1), Op1HasNSW);
return new ICmpInst(Pred, A, NewAdd);
}
}
@@ -4868,16 +4873,14 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
isKnownNonZero(Z, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT);
// if Z != 0 and nsw(X * Z) and nsw(Y * Z)
// X * Z eq/ne Y * Z -> X eq/ne Y
- if (NonZero && BO0 && BO1 && BO0->hasNoSignedWrap() &&
- BO1->hasNoSignedWrap())
+ if (NonZero && BO0 && BO1 && Op0HasNUW && Op1HasNSW)
return new ICmpInst(Pred, X, Y);
} else
NonZero = isKnownNonZero(Z, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT);
// If Z != 0 and nuw(X * Z) and nuw(Y * Z)
// X * Z u{lt/le/gt/ge}/eq/ne Y * Z -> X u{lt/le/gt/ge}/eq/ne Y
- if (NonZero && BO0 && BO1 && BO0->hasNoUnsignedWrap() &&
- BO1->hasNoUnsignedWrap())
+ if (NonZero && BO0 && BO1 && Op0HasNUW && Op1HasNUW)
return new ICmpInst(Pred, X, Y);
}
}
@@ -4976,8 +4979,8 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
case Instruction::Shl: {
- bool NUW = BO0->hasNoUnsignedWrap() && BO1->hasNoUnsignedWrap();
- bool NSW = BO0->hasNoSignedWrap() && BO1->hasNoSignedWrap();
+ bool NUW = Op0HasNUW && Op1HasNUW;
+ bool NSW = Op0HasNSW && Op1HasNSW;
if (!NUW && !NSW)
break;
if (!NSW && I.isSigned())
diff --git a/llvm/test/Transforms/InstCombine/disjoint-or-icmp.ll b/llvm/test/Transforms/InstCombine/disjoint-or-icmp.ll
new file mode 100644
index 00000000000000..b47edf7f878b2e
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/disjoint-or-icmp.ll
@@ -0,0 +1,14 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @simplify_icmp(i32 %x, i32 %y) {
+; CHECK-LABEL: define i1 @simplify_icmp(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[ICMP_:%.*]] = icmp sle i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i1 [[ICMP_]]
+;
+ %add0_ = or disjoint i32 %x, 1
+ %add1_ = add nsw i32 %y, 1
+ %icmp_ = icmp sle i32 %add0_, %add1_
+ ret i1 %icmp_
+}
>From 6667732f6ebf7fe1c6bfe1f14c53e850fac75fcd Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at gmail.com>
Date: Fri, 15 Dec 2023 04:24:53 -0500
Subject: [PATCH 2/2] Rerun CI
---
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 023340b799e8fa..b99fd23add4e08 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4629,8 +4629,7 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
// Analyze the case when either Op0 or Op1 is an add instruction.
// Op0 = A + B (or A and B are null); Op1 = C + D (or C and D are null).
Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr;
- auto hasNoWrapProblem = [&](const BinaryOperator &BO, const Value *X,
- const Value *Y, bool &HasNSW,
+ auto hasNoWrapProblem = [](const BinaryOperator &BO, CmpInst::Predicate Pred, bool &HasNSW,
bool &HasNUW) -> bool {
if (isa<OverflowingBinaryOperator>(BO)) {
HasNUW = BO.hasNoUnsignedWrap();
@@ -4638,7 +4637,7 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
return ICmpInst::isEquality(Pred) ||
(CmpInst::isUnsigned(Pred) && HasNUW) ||
(CmpInst::isSigned(Pred) && HasNSW);
- } else if (BO0->getOpcode() == Instruction::Or) {
+ } else if (BO.getOpcode() == Instruction::Or) {
HasNUW = true;
HasNSW = true;
return true;
@@ -4649,11 +4648,11 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
if (BO0) {
match(BO0, m_AddLike(m_Value(A), m_Value(B)));
- NoOp0WrapProblem = hasNoWrapProblem(*BO0, A, B, Op0HasNSW, Op0HasNUW);
+ NoOp0WrapProblem = hasNoWrapProblem(*BO0, Pred, Op0HasNSW, Op0HasNUW);
}
if (BO1) {
match(BO1, m_AddLike(m_Value(C), m_Value(D)));
- NoOp1WrapProblem = hasNoWrapProblem(*BO1, C, D, Op1HasNSW, Op1HasNUW);
+ NoOp1WrapProblem = hasNoWrapProblem(*BO1, Pred, Op1HasNSW, Op1HasNUW);
}
if ((A == Op1 || B == Op1) && NoOp0WrapProblem)
More information about the llvm-commits
mailing list