From 73fab55a236183c56bedafb88ea1063e137c034a Mon Sep 17 00:00:00 2001 From: Mikhail Gudim Date: Fri, 3 Nov 2023 16:15:36 -0400 Subject: [PATCH 1/6] [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 289976718e52f..023340b799e8f 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(BO0)) - NoOp0WrapProblem = - ICmpInst::isEquality(Pred) || - (CmpInst::isUnsigned(Pred) && BO0->hasNoUnsignedWrap()) || - (CmpInst::isSigned(Pred) && BO0->hasNoSignedWrap()); - if (BO1 && isa(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(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 0000000000000..b47edf7f878b2 --- /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 99d841c6c42a63f4a80184b0f4daa96f1b1f2425 Mon Sep 17 00:00:00 2001 From: Mikhail Gudim Date: Fri, 15 Dec 2023 04:24:53 -0500 Subject: [PATCH 2/6] Rerun CI --- .../Transforms/InstCombine/InstCombineCompares.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 023340b799e8f..05a2087cd766e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4629,16 +4629,15 @@ 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, - bool &HasNUW) -> bool { + auto hasNoWrapProblem = [](const BinaryOperator &BO, CmpInst::Predicate Pred, + bool &HasNSW, bool &HasNUW) -> bool { if (isa(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) { + } 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) From d01ea9060d8418d87ac979f3ecd52e910ef5c4b8 Mon Sep 17 00:00:00 2001 From: Mikhail Gudim Date: Mon, 18 Dec 2023 15:50:03 -0500 Subject: [PATCH 3/6] updated tests. --- llvm/test/Transforms/InstCombine/icmp.ll | 40 ++++++++++-------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll index 1c7bb36f0d34c..cc1bcffa13606 100644 --- a/llvm/test/Transforms/InstCombine/icmp.ll +++ b/llvm/test/Transforms/InstCombine/icmp.ll @@ -3862,10 +3862,9 @@ define <8 x i1> @bitreverse_vec_ne(<8 x i16> %x, <8 x i16> %y) { define i1 @knownbits1(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits1( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], 1 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A2]], [[B2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 5 @@ -3879,10 +3878,9 @@ define i1 @knownbits1(i8 %a, i8 %b) { define i1 @knownbits2(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits2( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], 1 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A2]], [[B2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 5 @@ -3896,10 +3894,9 @@ define i1 @knownbits2(i8 %a, i8 %b) { define i1 @knownbits3(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits3( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], 1 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[B2]], [[A2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], [[A1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 5 @@ -3913,10 +3910,9 @@ define i1 @knownbits3(i8 %a, i8 %b) { define <2 x i1> @knownbits4(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @knownbits4( ; CHECK-NEXT: [[A1:%.*]] = and <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[A2:%.*]] = or disjoint <2 x i8> [[A1]], ; CHECK-NEXT: [[B1:%.*]] = and <2 x i8> [[B:%.*]], -; CHECK-NEXT: [[B2:%.*]] = or disjoint <2 x i8> [[B1]], -; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> [[B2]], [[A2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint <2 x i8> [[B1]], +; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> [[TMP1]], [[A1]] ; CHECK-NEXT: ret <2 x i1> [[C]] ; %a1 = and <2 x i8> %a, @@ -3932,10 +3928,9 @@ define <2 x i1> @knownbits4(<2 x i8> %a, <2 x i8> %b) { define i1 @knownbits5(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits5( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], -127 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A2]], [[B2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 133 @@ -3949,10 +3944,9 @@ define i1 @knownbits5(i8 %a, i8 %b) { define i1 @knownbits6(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits6( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], -127 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A2]], [[B2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[A1]], [[TMP1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 133 @@ -3966,10 +3960,9 @@ define i1 @knownbits6(i8 %a, i8 %b) { define <2 x i1> @knownbits7(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @knownbits7( ; CHECK-NEXT: [[A1:%.*]] = and <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[A2:%.*]] = or disjoint <2 x i8> [[A1]], ; CHECK-NEXT: [[B1:%.*]] = and <2 x i8> [[B:%.*]], -; CHECK-NEXT: [[B2:%.*]] = or disjoint <2 x i8> [[B1]], -; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[B2]], [[A2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint <2 x i8> [[B1]], +; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i8> [[TMP1]], [[A1]] ; CHECK-NEXT: ret <2 x i1> [[C]] ; %a1 = and <2 x i8> %a, @@ -3983,10 +3976,9 @@ define <2 x i1> @knownbits7(<2 x i8> %a, <2 x i8> %b) { define i1 @knownbits8(i8 %a, i8 %b) { ; CHECK-LABEL: @knownbits8( ; CHECK-NEXT: [[A1:%.*]] = and i8 [[A:%.*]], -127 -; CHECK-NEXT: [[A2:%.*]] = or disjoint i8 [[A1]], 4 ; CHECK-NEXT: [[B1:%.*]] = and i8 [[B:%.*]], 2 -; CHECK-NEXT: [[B2:%.*]] = or disjoint i8 [[B1]], 5 -; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[B2]], [[A2]] +; CHECK-NEXT: [[TMP1:%.*]] = or disjoint i8 [[B1]], 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[TMP1]], [[A1]] ; CHECK-NEXT: ret i1 [[C]] ; %a1 = and i8 %a, 133 From e955d12b8d790203233493168d1dc42131284818 Mon Sep 17 00:00:00 2001 From: Mikhail Gudim Date: Mon, 18 Dec 2023 16:21:38 -0500 Subject: [PATCH 4/6] Fixed a typo --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 05a2087cd766e..0b99260bb635a 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4872,7 +4872,7 @@ 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 && Op0HasNUW && Op1HasNSW) + if (NonZero && BO0 && BO1 && Op0HasNSW && Op1HasNSW) return new ICmpInst(Pred, X, Y); } else NonZero = isKnownNonZero(Z, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT); From 077ccf007d2e5c7d053172a3466412e587ab679a Mon Sep 17 00:00:00 2001 From: Mikhail Gudim Date: Mon, 18 Dec 2023 16:27:28 -0500 Subject: [PATCH 5/6] Deleted unnecessary test --- .../Transforms/InstCombine/disjoint-or-icmp.ll | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 llvm/test/Transforms/InstCombine/disjoint-or-icmp.ll diff --git a/llvm/test/Transforms/InstCombine/disjoint-or-icmp.ll b/llvm/test/Transforms/InstCombine/disjoint-or-icmp.ll deleted file mode 100644 index b47edf7f878b2..0000000000000 --- a/llvm/test/Transforms/InstCombine/disjoint-or-icmp.ll +++ /dev/null @@ -1,14 +0,0 @@ -; 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 4dee840b11c5b138136684ce553c95ad7d374ccf Mon Sep 17 00:00:00 2001 From: Mikhail Gudim Date: Tue, 19 Dec 2023 13:22:09 -0500 Subject: [PATCH 6/6] Addressed review comments --- .../InstCombine/InstCombineCompares.cpp | 4 +- llvm/test/Transforms/InstCombine/icmp.ll | 77 +++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 0b99260bb635a..0ad87eeb4c91a 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4628,7 +4628,6 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, 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; auto hasNoWrapProblem = [](const BinaryOperator &BO, CmpInst::Predicate Pred, bool &HasNSW, bool &HasNUW) -> bool { if (isa(BO)) { @@ -4645,6 +4644,7 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, return false; } }; + Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr; if (BO0) { match(BO0, m_AddLike(m_Value(A), m_Value(B))); @@ -4655,6 +4655,8 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, NoOp1WrapProblem = hasNoWrapProblem(*BO1, Pred, 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())); diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll index cc1bcffa13606..fe831934f4f33 100644 --- a/llvm/test/Transforms/InstCombine/icmp.ll +++ b/llvm/test/Transforms/InstCombine/icmp.ll @@ -4904,3 +4904,80 @@ define i1 @or_positive_sgt_zero_multi_use(i8 %a) { %cmp = icmp sgt i8 %b, 0 ret i1 %cmp } + + +define i1 @disjoint_or_sgt_1(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_sgt_1( +; CHECK-NEXT: [[B1:%.*]] = add nsw i8 [[B:%.*]], 2 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp sle i8 [[B1]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 1 + %b1 = add nsw i8 %b, 2 + %icmp_ = icmp sgt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_sgt_2(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_sgt_2( +; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2 +; CHECK-NEXT: [[B1:%.*]] = add i8 [[B:%.*]], 1 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp sgt i8 [[A1]], [[B1]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 2 + %b1 = add i8 %b, 1 + %icmp_ = icmp sgt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_sgt_3(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_sgt_3( +; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2 +; CHECK-NEXT: [[B1:%.*]] = add nuw i8 [[B:%.*]], 1 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp sgt i8 [[A1]], [[B1]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 2 + %b1 = add nuw i8 %b, 1 + %icmp_ = icmp sgt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_ugt_1(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_ugt_1( +; CHECK-NEXT: [[B1:%.*]] = add nsw i8 [[B:%.*]], 2 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp ule i8 [[B1]], [[A:%.*]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 1 + %b1 = add nsw i8 %b, 2 + %icmp_ = icmp ugt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_ugt_2(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_ugt_2( +; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2 +; CHECK-NEXT: [[B1:%.*]] = add i8 [[B:%.*]], 1 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp ugt i8 [[A1]], [[B1]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 2 + %b1 = add i8 %b, 1 + %icmp_ = icmp ugt i8 %a1, %b1 + ret i1 %icmp_ +} + +define i1 @disjoint_or_ugt_3(i8 %a, i8 %b) { +; CHECK-LABEL: @disjoint_or_ugt_3( +; CHECK-NEXT: [[A1:%.*]] = or disjoint i8 [[A:%.*]], 2 +; CHECK-NEXT: [[B1:%.*]] = add nuw i8 [[B:%.*]], 1 +; CHECK-NEXT: [[ICMP_:%.*]] = icmp ugt i8 [[A1]], [[B1]] +; CHECK-NEXT: ret i1 [[ICMP_]] +; + %a1 = or disjoint i8 %a, 2 + %b1 = add nuw i8 %b, 1 + %icmp_ = icmp ugt i8 %a1, %b1 + ret i1 %icmp_ +}