[llvm] [InstCombine] Fold signed icmp X, (X | C) when C is negative (PR #217805)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 10 01:33:51 PDT 2026
github-actions[bot] wrote:
<!--LLVM CODE FORMAT COMMENT: {clang-format}-->
:warning: C/C++ code formatter, clang-format found issues in your code. :warning:
<details>
<summary>
You can test this locally with the following command:
</summary>
``````````bash
git-clang-format --diff origin/main HEAD --extensions cpp -- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --diff_from_common_commit
``````````
:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:
</details>
<details>
<summary>
View the diff from clang-format here.
</summary>
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index a48fc15dc..c0d716e3b 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -5333,519 +5333,530 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
if (P == ICmpInst::ICMP_SGE)
return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType()));
}
- // (X urem Y) == X --> X u< Y
- // (X urem Y) != X --> X u>= Y
- Value *Dividend, *Divisor;
- if (I.isEquality() &&
- match(&I, m_c_ICmp(m_URem(m_Value(Dividend), m_Value(Divisor)),
- m_Deferred(Dividend)))) {
- CmpInst::Predicate NewPred =
- Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE;
- return new ICmpInst(NewPred, Dividend, Divisor);
- }
-
- Value *X;
-
- // Convert add-with-unsigned-overflow comparisons into a 'not' with compare.
- // (Op1 + X) u</u>= Op1 --> ~Op1 u</u>= X
- if (match(Op0, m_OneUse(m_c_Add(m_Specific(Op1), m_Value(X)))) &&
- (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE))
- return new ICmpInst(Pred, Builder.CreateNot(Op1), X);
- // Op0 u>/u<= (Op0 + X) --> X u>/u<= ~Op0
- if (match(Op1, m_OneUse(m_c_Add(m_Specific(Op0), m_Value(X)))) &&
- (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE))
- return new ICmpInst(Pred, X, Builder.CreateNot(Op0));
-
- {
- // (Op1 + X) + C u</u>= Op1 --> ~C - X u</u>= Op1
- Constant *C;
- if (match(Op0, m_OneUse(m_Add(m_c_Add(m_Specific(Op1), m_Value(X)),
- m_ImmConstant(C)))) &&
- (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE)) {
- Constant *C2 = ConstantExpr::getNot(C);
- return new ICmpInst(Pred, Builder.CreateSub(C2, X), Op1);
- }
- // Op0 u>/u<= (Op0 + X) + C --> Op0 u>/u<= ~C - X
- if (match(Op1, m_OneUse(m_Add(m_c_Add(m_Specific(Op0), m_Value(X)),
- m_ImmConstant(C)))) &&
- (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE)) {
- Constant *C2 = ConstantExpr::getNot(C);
- return new ICmpInst(Pred, Op0, Builder.CreateSub(C2, X));
+ // (X urem Y) == X --> X u< Y
+ // (X urem Y) != X --> X u>= Y
+ Value *Dividend, *Divisor;
+ if (I.isEquality() &&
+ match(&I, m_c_ICmp(m_URem(m_Value(Dividend), m_Value(Divisor)),
+ m_Deferred(Dividend)))) {
+ CmpInst::Predicate NewPred =
+ Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE;
+ return new ICmpInst(NewPred, Dividend, Divisor);
}
- }
- // (icmp eq/ne (X, -P2), INT_MIN)
- // -> (icmp slt/sge X, INT_MIN + P2)
- if (ICmpInst::isEquality(Pred) && BO0 &&
- match(I.getOperand(1), m_SignMask()) &&
- match(BO0, m_And(m_Value(), m_NegatedPower2OrZero()))) {
- // Will Constant fold.
- Value *NewC = Builder.CreateSub(I.getOperand(1), BO0->getOperand(1));
- return new ICmpInst(Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_SLT
- : ICmpInst::ICMP_SGE,
- BO0->getOperand(0), NewC);
- }
+ Value *X;
- {
- // Similar to above: an unsigned overflow comparison may use offset + mask:
- // ((Op1 + C) & C) u< Op1 --> Op1 != 0
- // ((Op1 + C) & C) u>= Op1 --> Op1 == 0
- // Op0 u> ((Op0 + C) & C) --> Op0 != 0
- // Op0 u<= ((Op0 + C) & C) --> Op0 == 0
- BinaryOperator *BO;
- const APInt *C;
- if ((Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE) &&
- match(Op0, m_And(m_BinOp(BO), m_LowBitMask(C))) &&
- match(BO, m_Add(m_Specific(Op1), m_SpecificIntAllowPoison(*C)))) {
- CmpInst::Predicate NewPred =
- Pred == ICmpInst::ICMP_ULT ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ;
- Constant *Zero = ConstantInt::getNullValue(Op1->getType());
- return new ICmpInst(NewPred, Op1, Zero);
- }
+ // Convert add-with-unsigned-overflow comparisons into a 'not' with compare.
+ // (Op1 + X) u</u>= Op1 --> ~Op1 u</u>= X
+ if (match(Op0, m_OneUse(m_c_Add(m_Specific(Op1), m_Value(X)))) &&
+ (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE))
+ return new ICmpInst(Pred, Builder.CreateNot(Op1), X);
+ // Op0 u>/u<= (Op0 + X) --> X u>/u<= ~Op0
+ if (match(Op1, m_OneUse(m_c_Add(m_Specific(Op0), m_Value(X)))) &&
+ (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE))
+ return new ICmpInst(Pred, X, Builder.CreateNot(Op0));
- if ((Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE) &&
- match(Op1, m_And(m_BinOp(BO), m_LowBitMask(C))) &&
- match(BO, m_Add(m_Specific(Op0), m_SpecificIntAllowPoison(*C)))) {
- CmpInst::Predicate NewPred =
- Pred == ICmpInst::ICMP_UGT ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ;
- Constant *Zero = ConstantInt::getNullValue(Op1->getType());
- return new ICmpInst(NewPred, Op0, Zero);
- }
- }
-
- bool NoOp0WrapProblem = false, NoOp1WrapProblem = false;
- 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).
- auto hasNoWrapProblem = [](const BinaryOperator &BO, CmpInst::Predicate Pred,
- 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 (BO.getOpcode() == Instruction::Or) {
- // The invariant here is that we are handling m_AddLike instructions,
- // which can only be a or disjoint, which is equivalent to an add nuw nsw.
- HasNUW = true;
- HasNSW = true;
- return true;
- } else {
- return false;
+ {
+ // (Op1 + X) + C u</u>= Op1 --> ~C - X u</u>= Op1
+ Constant *C;
+ if (match(Op0, m_OneUse(m_Add(m_c_Add(m_Specific(Op1), m_Value(X)),
+ m_ImmConstant(C)))) &&
+ (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE)) {
+ Constant *C2 = ConstantExpr::getNot(C);
+ return new ICmpInst(Pred, Builder.CreateSub(C2, X), Op1);
+ }
+ // Op0 u>/u<= (Op0 + X) + C --> Op0 u>/u<= ~C - X
+ if (match(Op1, m_OneUse(m_Add(m_c_Add(m_Specific(Op0), m_Value(X)),
+ m_ImmConstant(C)))) &&
+ (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE)) {
+ Constant *C2 = ConstantExpr::getNot(C);
+ return new ICmpInst(Pred, Op0, Builder.CreateSub(C2, X));
+ }
}
- };
- Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr;
- if (BO0) {
- match(BO0, m_AddLike(m_Value(A), m_Value(B)));
- NoOp0WrapProblem = hasNoWrapProblem(*BO0, Pred, Op0HasNSW, Op0HasNUW);
- }
- if (BO1) {
- match(BO1, m_AddLike(m_Value(C), m_Value(D)));
- NoOp1WrapProblem = hasNoWrapProblem(*BO1, Pred, Op1HasNSW, Op1HasNUW);
- }
+ // (icmp eq/ne (X, -P2), INT_MIN)
+ // -> (icmp slt/sge X, INT_MIN + P2)
+ if (ICmpInst::isEquality(Pred) && BO0 &&
+ match(I.getOperand(1), m_SignMask()) &&
+ match(BO0, m_And(m_Value(), m_NegatedPower2OrZero()))) {
+ // Will Constant fold.
+ Value *NewC = Builder.CreateSub(I.getOperand(1), BO0->getOperand(1));
+ return new ICmpInst(Pred == ICmpInst::ICMP_EQ ? ICmpInst::ICMP_SLT
+ : ICmpInst::ICMP_SGE,
+ BO0->getOperand(0), NewC);
+ }
- // 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()));
+ {
+ // Similar to above: an unsigned overflow comparison may use offset +
+ // mask:
+ // ((Op1 + C) & C) u< Op1 --> Op1 != 0
+ // ((Op1 + C) & C) u>= Op1 --> Op1 == 0
+ // Op0 u> ((Op0 + C) & C) --> Op0 != 0
+ // Op0 u<= ((Op0 + C) & C) --> Op0 == 0
+ BinaryOperator *BO;
+ const APInt *C;
+ if ((Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE) &&
+ match(Op0, m_And(m_BinOp(BO), m_LowBitMask(C))) &&
+ match(BO, m_Add(m_Specific(Op1), m_SpecificIntAllowPoison(*C)))) {
+ CmpInst::Predicate NewPred =
+ Pred == ICmpInst::ICMP_ULT ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ;
+ Constant *Zero = ConstantInt::getNullValue(Op1->getType());
+ return new ICmpInst(NewPred, Op1, Zero);
+ }
- // icmp C, (C+D) -> icmp 0, D for equalities or if there is no overflow.
- // icmp D, (C+D) -> icmp 0, C for equalities or if there is no overflow.
- if ((C == Op0 || D == Op0) && NoOp1WrapProblem)
- return new ICmpInst(Pred, Constant::getNullValue(Op0->getType()),
- C == Op0 ? D : C);
-
- // icmp (A+B), (A+D) -> icmp B, D for equalities or if there is no overflow.
- if (A && C && (A == C || A == D || B == C || B == D) && NoOp0WrapProblem &&
- NoOp1WrapProblem) {
- // Determine Y and Z in the form icmp (X+Y), (X+Z).
- Value *Y, *Z;
- if (A == C) {
- // C + B == C + D -> B == D
- Y = B;
- Z = D;
- } else if (A == D) {
- // D + B == C + D -> B == C
- Y = B;
- Z = C;
- } else if (B == C) {
- // A + C == C + D -> A == D
- Y = A;
- Z = D;
- } else {
- assert(B == D);
- // A + D == C + D -> A == C
- Y = A;
- Z = C;
+ if ((Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE) &&
+ match(Op1, m_And(m_BinOp(BO), m_LowBitMask(C))) &&
+ match(BO, m_Add(m_Specific(Op0), m_SpecificIntAllowPoison(*C)))) {
+ CmpInst::Predicate NewPred =
+ Pred == ICmpInst::ICMP_UGT ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ;
+ Constant *Zero = ConstantInt::getNullValue(Op1->getType());
+ return new ICmpInst(NewPred, Op0, Zero);
+ }
}
- return new ICmpInst(Pred, Y, Z);
- }
- if (ICmpInst::isRelational(Pred)) {
- // Return if both X and Y is divisible by Z/-Z.
- // TODO: Generalize to check if (X - Y) is divisible by Z/-Z.
- auto ShareCommonDivisor = [&Q](Value *X, Value *Y, Value *Z,
- bool IsNegative) -> bool {
- const APInt *OffsetC;
- if (!match(Z, m_APInt(OffsetC)))
- return false;
-
- // Fast path for Z == 1/-1.
- if (IsNegative ? OffsetC->isAllOnes() : OffsetC->isOne())
+ bool NoOp0WrapProblem = false, NoOp1WrapProblem = false;
+ 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).
+ auto hasNoWrapProblem = [](const BinaryOperator &BO,
+ CmpInst::Predicate Pred, 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 (BO.getOpcode() == Instruction::Or) {
+ // The invariant here is that we are handling m_AddLike instructions,
+ // which can only be a or disjoint, which is equivalent to an add nuw
+ // nsw.
+ HasNUW = true;
+ HasNSW = true;
return true;
-
- APInt C = *OffsetC;
- if (IsNegative)
- C.negate();
- // Note: -INT_MIN is also negative.
- if (!C.isStrictlyPositive())
+ } else {
return false;
-
- return isMultipleOf(X, C, Q) && isMultipleOf(Y, C, Q);
+ }
};
+ Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr;
- // The subtraction-related identities (A -nuw B) shown below require that
- // the subtraction does not wrap unsigned (i.e., A >=u B). Canonicalization
- // from (A -nuw 1) to (A + -1) means that such combinations ought to never
- // occur, as sub nuw ops should have been canonicalized to add ones. It may
- // however appear in the form of a or disjoint. Though, or disjoint A, -B
- // requires proving A <u B, for which the nowrap precondition can never be
- // satisfied. These are therefore skipped.
- //
- // icmp ult (A - 1), Op1 -> icmp ule A, Op1
- // icmp uge (A - 1), Op1 -> icmp ugt A, Op1
- // icmp ugt Op0, (C - 1) -> icmp uge Op0, C
- // icmp ule Op0, (C - 1) -> icmp ult Op0, C
-
- // icmp slt (A + -1), Op1 -> icmp sle A, Op1
- // icmp sge (A + -1), Op1 -> icmp sgt A, Op1
- // icmp sle (A + 1), Op1 -> icmp slt A, Op1
- // icmp sgt (A + 1), Op1 -> icmp sge A, Op1
- // icmp ule (A + 1), Op0 -> icmp ult A, Op1
- // icmp ugt (A + 1), Op0 -> icmp uge A, Op1
- bool IsNegative = ICmpInst::isLT(Pred) || ICmpInst::isGE(Pred);
- bool IsAddOrSignedPred = !IsNegative || ICmpInst::isSigned(Pred);
- if (A && NoOp0WrapProblem && IsAddOrSignedPred &&
- ShareCommonDivisor(A, Op1, B, IsNegative))
- return new ICmpInst(ICmpInst::getFlippedStrictnessPredicate(Pred), A,
- Op1);
+ if (BO0) {
+ match(BO0, m_AddLike(m_Value(A), m_Value(B)));
+ NoOp0WrapProblem = hasNoWrapProblem(*BO0, Pred, Op0HasNSW, Op0HasNUW);
+ }
+ if (BO1) {
+ match(BO1, m_AddLike(m_Value(C), m_Value(D)));
+ NoOp1WrapProblem = hasNoWrapProblem(*BO1, Pred, Op1HasNSW, Op1HasNUW);
+ }
- // icmp sgt Op0, (C + -1) -> icmp sge Op0, C
- // icmp sle Op0, (C + -1) -> icmp slt Op0, C
- // icmp sge Op0, (C + 1) -> icmp sgt Op0, C
- // icmp slt Op0, (C + 1) -> icmp sle Op0, C
- // icmp uge Op0, (C + 1) -> icmp ugt Op0, C
- // icmp ult Op0, (C + 1) -> icmp ule Op0, C
- if (C && NoOp1WrapProblem &&
- ShareCommonDivisor(Op0, C, D,
- ICmpInst::isGT(Pred) || ICmpInst::isLE(Pred)))
- return new ICmpInst(ICmpInst::getFlippedStrictnessPredicate(Pred), Op0,
- C);
- }
-
- // if C1 has greater magnitude than C2:
- // icmp (A + C1), (C + C2) -> icmp (A + C3), C
- // s.t. C3 = C1 - C2
- //
- // if C2 has greater magnitude than C1:
- // icmp (A + C1), (C + C2) -> icmp A, (C + C3)
- // s.t. C3 = C2 - C1
- if (A && C && NoOp0WrapProblem && NoOp1WrapProblem &&
- (BO0->hasOneUse() || BO1->hasOneUse()) && !I.isUnsigned()) {
- const APInt *AP1, *AP2;
- // TODO: Support non-uniform vectors.
- // TODO: Allow poison passthrough if B or D's element is poison.
- if (match(B, m_APIntAllowPoison(AP1)) &&
- match(D, m_APIntAllowPoison(AP2)) &&
- AP1->isNegative() == AP2->isNegative()) {
- APInt AP1Abs = AP1->abs();
- APInt AP2Abs = AP2->abs();
- if (AP1Abs.uge(AP2Abs)) {
- APInt Diff = *AP1 - *AP2;
- Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff);
- Value *NewAdd = Builder.CreateAdd(
- A, C3, "", Op0HasNUW && Diff.ule(*AP1), Op0HasNSW);
- return new ICmpInst(Pred, NewAdd, C);
+ // 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()));
+
+ // icmp C, (C+D) -> icmp 0, D for equalities or if there is no overflow.
+ // icmp D, (C+D) -> icmp 0, C for equalities or if there is no overflow.
+ if ((C == Op0 || D == Op0) && NoOp1WrapProblem)
+ return new ICmpInst(Pred, Constant::getNullValue(Op0->getType()),
+ C == Op0 ? D : C);
+
+ // icmp (A+B), (A+D) -> icmp B, D for equalities or if there is no overflow.
+ if (A && C && (A == C || A == D || B == C || B == D) && NoOp0WrapProblem &&
+ NoOp1WrapProblem) {
+ // Determine Y and Z in the form icmp (X+Y), (X+Z).
+ Value *Y, *Z;
+ if (A == C) {
+ // C + B == C + D -> B == D
+ Y = B;
+ Z = D;
+ } else if (A == D) {
+ // D + B == C + D -> B == C
+ Y = B;
+ Z = C;
+ } else if (B == C) {
+ // A + C == C + D -> A == D
+ Y = A;
+ Z = D;
} else {
- APInt Diff = *AP2 - *AP1;
- Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff);
- Value *NewAdd = Builder.CreateAdd(
- C, C3, "", Op1HasNUW && Diff.ule(*AP2), Op1HasNSW);
- return new ICmpInst(Pred, A, NewAdd);
+ assert(B == D);
+ // A + D == C + D -> A == C
+ Y = A;
+ Z = C;
}
+ return new ICmpInst(Pred, Y, Z);
}
- Constant *Cst1, *Cst2;
- if (match(B, m_ImmConstant(Cst1)) && match(D, m_ImmConstant(Cst2)) &&
- ICmpInst::isEquality(Pred)) {
- Constant *Diff = ConstantExpr::getSub(Cst2, Cst1);
- Value *NewAdd = Builder.CreateAdd(C, Diff);
- return new ICmpInst(Pred, A, NewAdd);
- }
- }
-
- // Analyze the case when either Op0 or Op1 is a sub instruction.
- // Op0 = A - B (or A and B are null); Op1 = C - D (or C and D are null).
- A = nullptr;
- B = nullptr;
- C = nullptr;
- D = nullptr;
- if (BO0 && BO0->getOpcode() == Instruction::Sub) {
- A = BO0->getOperand(0);
- B = BO0->getOperand(1);
- }
- if (BO1 && BO1->getOpcode() == Instruction::Sub) {
- C = BO1->getOperand(0);
- D = BO1->getOperand(1);
- }
-
- // icmp (A-B), A -> icmp 0, B for equalities or if there is no overflow.
- if (A == Op1 && NoOp0WrapProblem)
- return new ICmpInst(Pred, Constant::getNullValue(Op1->getType()), B);
- // icmp C, (C-D) -> icmp D, 0 for equalities or if there is no overflow.
- if (C == Op0 && NoOp1WrapProblem)
- return new ICmpInst(Pred, D, Constant::getNullValue(Op0->getType()));
-
- // Convert sub-with-unsigned-overflow comparisons into a comparison of args.
- // (A - B) u>/u<= A --> B u>/u<= A
- if (A == Op1 && (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE))
- return new ICmpInst(Pred, B, A);
- // C u</u>= (C - D) --> C u</u>= D
- if (C == Op0 && (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE))
- return new ICmpInst(Pred, C, D);
- // (A - B) u>=/u< A --> B u>/u<= A iff B != 0
- if (A == Op1 && (Pred == ICmpInst::ICMP_UGE || Pred == ICmpInst::ICMP_ULT) &&
- isKnownNonZero(B, Q))
- return new ICmpInst(CmpInst::getFlippedStrictnessPredicate(Pred), B, A);
- // C u<=/u> (C - D) --> C u</u>= D iff B != 0
- if (C == Op0 && (Pred == ICmpInst::ICMP_ULE || Pred == ICmpInst::ICMP_UGT) &&
- isKnownNonZero(D, Q))
- return new ICmpInst(CmpInst::getFlippedStrictnessPredicate(Pred), C, D);
-
- // icmp (A-B), (C-B) -> icmp A, C for equalities or if there is no overflow.
- if (B && D && B == D && NoOp0WrapProblem && NoOp1WrapProblem)
- return new ICmpInst(Pred, A, C);
-
- // icmp (A-B), (A-D) -> icmp D, B for equalities or if there is no overflow.
- if (A && C && A == C && NoOp0WrapProblem && NoOp1WrapProblem)
- return new ICmpInst(Pred, D, B);
-
- // icmp (0-X) < cst --> x > -cst
- if (NoOp0WrapProblem && ICmpInst::isSigned(Pred)) {
- Value *X;
- if (match(BO0, m_Neg(m_Value(X))))
- if (Constant *RHSC = dyn_cast<Constant>(Op1))
- if (RHSC->isNotMinSignedValue())
- return new ICmpInst(I.getSwappedPredicate(), X,
- ConstantExpr::getNeg(RHSC));
- }
- if (Instruction *R = foldICmpXorXX(I, Q, *this))
- return R;
- if (Instruction *R = foldICmpOrXX(I, Q, *this))
- return R;
+ if (ICmpInst::isRelational(Pred)) {
+ // Return if both X and Y is divisible by Z/-Z.
+ // TODO: Generalize to check if (X - Y) is divisible by Z/-Z.
+ auto ShareCommonDivisor = [&Q](Value *X, Value *Y, Value *Z,
+ bool IsNegative) -> bool {
+ const APInt *OffsetC;
+ if (!match(Z, m_APInt(OffsetC)))
+ return false;
- {
- // Try to remove shared multiplier from comparison:
- // X * Z pred Y * Z
- Value *X, *Y, *Z;
- if ((match(Op0, m_Mul(m_Value(X), m_Value(Z))) &&
- match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y)))) ||
- (match(Op0, m_Mul(m_Value(Z), m_Value(X))) &&
- match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y))))) {
- if (ICmpInst::isSigned(Pred)) {
- if (Op0HasNSW && Op1HasNSW) {
- KnownBits ZKnown = computeKnownBits(Z, &I);
- if (ZKnown.isStrictlyPositive())
- return new ICmpInst(Pred, X, Y);
- if (ZKnown.isNegative())
- return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), X, Y);
- Value *LessThan = simplifyICmpInst(ICmpInst::ICMP_SLT, X, Y,
- SQ.getWithInstruction(&I));
- if (LessThan && match(LessThan, m_One()))
- return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), Z,
- Constant::getNullValue(Z->getType()));
- Value *GreaterThan = simplifyICmpInst(ICmpInst::ICMP_SGT, X, Y,
- SQ.getWithInstruction(&I));
- if (GreaterThan && match(GreaterThan, m_One()))
- return new ICmpInst(Pred, Z, Constant::getNullValue(Z->getType()));
- }
- } else {
- bool NonZero;
- if (ICmpInst::isEquality(Pred)) {
- // If X != Y, fold (X *nw Z) eq/ne (Y *nw Z) -> Z eq/ne 0
- if (((Op0HasNSW && Op1HasNSW) || (Op0HasNUW && Op1HasNUW)) &&
- isKnownNonEqual(X, Y, SQ))
- return new ICmpInst(Pred, Z, Constant::getNullValue(Z->getType()));
-
- KnownBits ZKnown = computeKnownBits(Z, &I);
- // if Z % 2 != 0
- // X * Z eq/ne Y * Z -> X eq/ne Y
- if (ZKnown.countMaxTrailingZeros() == 0)
- return new ICmpInst(Pred, X, Y);
- NonZero = !ZKnown.One.isZero() || isKnownNonZero(Z, Q);
- // 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 && Op0HasNSW && Op1HasNSW)
- return new ICmpInst(Pred, X, Y);
- } else
- NonZero = isKnownNonZero(Z, Q);
+ // Fast path for Z == 1/-1.
+ if (IsNegative ? OffsetC->isAllOnes() : OffsetC->isOne())
+ return true;
- // 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 && Op0HasNUW && Op1HasNUW)
- return new ICmpInst(Pred, X, Y);
+ APInt C = *OffsetC;
+ if (IsNegative)
+ C.negate();
+ // Note: -INT_MIN is also negative.
+ if (!C.isStrictlyPositive())
+ return false;
+
+ return isMultipleOf(X, C, Q) && isMultipleOf(Y, C, Q);
+ };
+
+ // The subtraction-related identities (A -nuw B) shown below require that
+ // the subtraction does not wrap unsigned (i.e., A >=u B).
+ // Canonicalization from (A -nuw 1) to (A + -1) means that such
+ // combinations ought to never occur, as sub nuw ops should have been
+ // canonicalized to add ones. It may however appear in the form of a or
+ // disjoint. Though, or disjoint A, -B requires proving A <u B, for which
+ // the nowrap precondition can never be satisfied. These are therefore
+ // skipped.
+ //
+ // icmp ult (A - 1), Op1 -> icmp ule A, Op1
+ // icmp uge (A - 1), Op1 -> icmp ugt A, Op1
+ // icmp ugt Op0, (C - 1) -> icmp uge Op0, C
+ // icmp ule Op0, (C - 1) -> icmp ult Op0, C
+
+ // icmp slt (A + -1), Op1 -> icmp sle A, Op1
+ // icmp sge (A + -1), Op1 -> icmp sgt A, Op1
+ // icmp sle (A + 1), Op1 -> icmp slt A, Op1
+ // icmp sgt (A + 1), Op1 -> icmp sge A, Op1
+ // icmp ule (A + 1), Op0 -> icmp ult A, Op1
+ // icmp ugt (A + 1), Op0 -> icmp uge A, Op1
+ bool IsNegative = ICmpInst::isLT(Pred) || ICmpInst::isGE(Pred);
+ bool IsAddOrSignedPred = !IsNegative || ICmpInst::isSigned(Pred);
+ if (A && NoOp0WrapProblem && IsAddOrSignedPred &&
+ ShareCommonDivisor(A, Op1, B, IsNegative))
+ return new ICmpInst(ICmpInst::getFlippedStrictnessPredicate(Pred), A,
+ Op1);
+
+ // icmp sgt Op0, (C + -1) -> icmp sge Op0, C
+ // icmp sle Op0, (C + -1) -> icmp slt Op0, C
+ // icmp sge Op0, (C + 1) -> icmp sgt Op0, C
+ // icmp slt Op0, (C + 1) -> icmp sle Op0, C
+ // icmp uge Op0, (C + 1) -> icmp ugt Op0, C
+ // icmp ult Op0, (C + 1) -> icmp ule Op0, C
+ if (C && NoOp1WrapProblem &&
+ ShareCommonDivisor(Op0, C, D,
+ ICmpInst::isGT(Pred) || ICmpInst::isLE(Pred)))
+ return new ICmpInst(ICmpInst::getFlippedStrictnessPredicate(Pred), Op0,
+ C);
+ }
+
+ // if C1 has greater magnitude than C2:
+ // icmp (A + C1), (C + C2) -> icmp (A + C3), C
+ // s.t. C3 = C1 - C2
+ //
+ // if C2 has greater magnitude than C1:
+ // icmp (A + C1), (C + C2) -> icmp A, (C + C3)
+ // s.t. C3 = C2 - C1
+ if (A && C && NoOp0WrapProblem && NoOp1WrapProblem &&
+ (BO0->hasOneUse() || BO1->hasOneUse()) && !I.isUnsigned()) {
+ const APInt *AP1, *AP2;
+ // TODO: Support non-uniform vectors.
+ // TODO: Allow poison passthrough if B or D's element is poison.
+ if (match(B, m_APIntAllowPoison(AP1)) &&
+ match(D, m_APIntAllowPoison(AP2)) &&
+ AP1->isNegative() == AP2->isNegative()) {
+ APInt AP1Abs = AP1->abs();
+ APInt AP2Abs = AP2->abs();
+ if (AP1Abs.uge(AP2Abs)) {
+ APInt Diff = *AP1 - *AP2;
+ Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff);
+ Value *NewAdd = Builder.CreateAdd(
+ A, C3, "", Op0HasNUW && Diff.ule(*AP1), Op0HasNSW);
+ return new ICmpInst(Pred, NewAdd, C);
+ } else {
+ APInt Diff = *AP2 - *AP1;
+ Constant *C3 = Constant::getIntegerValue(BO0->getType(), Diff);
+ Value *NewAdd = Builder.CreateAdd(
+ C, C3, "", Op1HasNUW && Diff.ule(*AP2), Op1HasNSW);
+ return new ICmpInst(Pred, A, NewAdd);
+ }
+ }
+ Constant *Cst1, *Cst2;
+ if (match(B, m_ImmConstant(Cst1)) && match(D, m_ImmConstant(Cst2)) &&
+ ICmpInst::isEquality(Pred)) {
+ Constant *Diff = ConstantExpr::getSub(Cst2, Cst1);
+ Value *NewAdd = Builder.CreateAdd(C, Diff);
+ return new ICmpInst(Pred, A, NewAdd);
}
}
- }
- BinaryOperator *SRem = nullptr;
- // icmp (srem X, Y), Y
- if (BO0 && BO0->getOpcode() == Instruction::SRem && Op1 == BO0->getOperand(1))
- SRem = BO0;
- // icmp Y, (srem X, Y)
- else if (BO1 && BO1->getOpcode() == Instruction::SRem &&
- Op0 == BO1->getOperand(1))
- SRem = BO1;
- if (SRem) {
- // We don't check hasOneUse to avoid increasing register pressure because
- // the value we use is the same value this instruction was already using.
- switch (SRem == BO0 ? ICmpInst::getSwappedPredicate(Pred) : Pred) {
- default:
- break;
- case ICmpInst::ICMP_EQ:
- return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
- case ICmpInst::ICMP_NE:
- return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType()));
- case ICmpInst::ICMP_SGT:
- case ICmpInst::ICMP_SGE:
- return new ICmpInst(ICmpInst::ICMP_SGT, SRem->getOperand(1),
- Constant::getAllOnesValue(SRem->getType()));
- case ICmpInst::ICMP_SLT:
- case ICmpInst::ICMP_SLE:
- return new ICmpInst(ICmpInst::ICMP_SLT, SRem->getOperand(1),
- Constant::getNullValue(SRem->getType()));
+ // Analyze the case when either Op0 or Op1 is a sub instruction.
+ // Op0 = A - B (or A and B are null); Op1 = C - D (or C and D are null).
+ A = nullptr;
+ B = nullptr;
+ C = nullptr;
+ D = nullptr;
+ if (BO0 && BO0->getOpcode() == Instruction::Sub) {
+ A = BO0->getOperand(0);
+ B = BO0->getOperand(1);
+ }
+ if (BO1 && BO1->getOpcode() == Instruction::Sub) {
+ C = BO1->getOperand(0);
+ D = BO1->getOperand(1);
+ }
+
+ // icmp (A-B), A -> icmp 0, B for equalities or if there is no overflow.
+ if (A == Op1 && NoOp0WrapProblem)
+ return new ICmpInst(Pred, Constant::getNullValue(Op1->getType()), B);
+ // icmp C, (C-D) -> icmp D, 0 for equalities or if there is no overflow.
+ if (C == Op0 && NoOp1WrapProblem)
+ return new ICmpInst(Pred, D, Constant::getNullValue(Op0->getType()));
+
+ // Convert sub-with-unsigned-overflow comparisons into a comparison of args.
+ // (A - B) u>/u<= A --> B u>/u<= A
+ if (A == Op1 && (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULE))
+ return new ICmpInst(Pred, B, A);
+ // C u</u>= (C - D) --> C u</u>= D
+ if (C == Op0 && (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_UGE))
+ return new ICmpInst(Pred, C, D);
+ // (A - B) u>=/u< A --> B u>/u<= A iff B != 0
+ if (A == Op1 &&
+ (Pred == ICmpInst::ICMP_UGE || Pred == ICmpInst::ICMP_ULT) &&
+ isKnownNonZero(B, Q))
+ return new ICmpInst(CmpInst::getFlippedStrictnessPredicate(Pred), B, A);
+ // C u<=/u> (C - D) --> C u</u>= D iff B != 0
+ if (C == Op0 &&
+ (Pred == ICmpInst::ICMP_ULE || Pred == ICmpInst::ICMP_UGT) &&
+ isKnownNonZero(D, Q))
+ return new ICmpInst(CmpInst::getFlippedStrictnessPredicate(Pred), C, D);
+
+ // icmp (A-B), (C-B) -> icmp A, C for equalities or if there is no overflow.
+ if (B && D && B == D && NoOp0WrapProblem && NoOp1WrapProblem)
+ return new ICmpInst(Pred, A, C);
+
+ // icmp (A-B), (A-D) -> icmp D, B for equalities or if there is no overflow.
+ if (A && C && A == C && NoOp0WrapProblem && NoOp1WrapProblem)
+ return new ICmpInst(Pred, D, B);
+
+ // icmp (0-X) < cst --> x > -cst
+ if (NoOp0WrapProblem && ICmpInst::isSigned(Pred)) {
+ Value *X;
+ if (match(BO0, m_Neg(m_Value(X))))
+ if (Constant *RHSC = dyn_cast<Constant>(Op1))
+ if (RHSC->isNotMinSignedValue())
+ return new ICmpInst(I.getSwappedPredicate(), X,
+ ConstantExpr::getNeg(RHSC));
}
- }
- if (BO0 && BO1 && BO0->getOpcode() == BO1->getOpcode() &&
- (BO0->hasOneUse() || BO1->hasOneUse()) &&
- BO0->getOperand(1) == BO1->getOperand(1)) {
- switch (BO0->getOpcode()) {
- default:
- break;
- case Instruction::Add:
- case Instruction::Sub:
- case Instruction::Xor: {
- if (I.isEquality()) // a+x icmp eq/ne b+x --> a icmp b
- return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
+ if (Instruction *R = foldICmpXorXX(I, Q, *this))
+ return R;
+ if (Instruction *R = foldICmpOrXX(I, Q, *this))
+ return R;
- const APInt *C;
- if (match(BO0->getOperand(1), m_APInt(C))) {
- // icmp u/s (a ^ signmask), (b ^ signmask) --> icmp s/u a, b
- if (C->isSignMask()) {
- ICmpInst::Predicate NewPred = I.getFlippedSignednessPredicate();
- return new ICmpInst(NewPred, BO0->getOperand(0), BO1->getOperand(0));
- }
+ {
+ // Try to remove shared multiplier from comparison:
+ // X * Z pred Y * Z
+ Value *X, *Y, *Z;
+ if ((match(Op0, m_Mul(m_Value(X), m_Value(Z))) &&
+ match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y)))) ||
+ (match(Op0, m_Mul(m_Value(Z), m_Value(X))) &&
+ match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y))))) {
+ if (ICmpInst::isSigned(Pred)) {
+ if (Op0HasNSW && Op1HasNSW) {
+ KnownBits ZKnown = computeKnownBits(Z, &I);
+ if (ZKnown.isStrictlyPositive())
+ return new ICmpInst(Pred, X, Y);
+ if (ZKnown.isNegative())
+ return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), X, Y);
+ Value *LessThan = simplifyICmpInst(ICmpInst::ICMP_SLT, X, Y,
+ SQ.getWithInstruction(&I));
+ if (LessThan && match(LessThan, m_One()))
+ return new ICmpInst(ICmpInst::getSwappedPredicate(Pred), Z,
+ Constant::getNullValue(Z->getType()));
+ Value *GreaterThan = simplifyICmpInst(ICmpInst::ICMP_SGT, X, Y,
+ SQ.getWithInstruction(&I));
+ if (GreaterThan && match(GreaterThan, m_One()))
+ return new ICmpInst(Pred, Z,
+ Constant::getNullValue(Z->getType()));
+ }
+ } else {
+ bool NonZero;
+ if (ICmpInst::isEquality(Pred)) {
+ // If X != Y, fold (X *nw Z) eq/ne (Y *nw Z) -> Z eq/ne 0
+ if (((Op0HasNSW && Op1HasNSW) || (Op0HasNUW && Op1HasNUW)) &&
+ isKnownNonEqual(X, Y, SQ))
+ return new ICmpInst(Pred, Z,
+ Constant::getNullValue(Z->getType()));
+
+ KnownBits ZKnown = computeKnownBits(Z, &I);
+ // if Z % 2 != 0
+ // X * Z eq/ne Y * Z -> X eq/ne Y
+ if (ZKnown.countMaxTrailingZeros() == 0)
+ return new ICmpInst(Pred, X, Y);
+ NonZero = !ZKnown.One.isZero() || isKnownNonZero(Z, Q);
+ // 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 && Op0HasNSW && Op1HasNSW)
+ return new ICmpInst(Pred, X, Y);
+ } else
+ NonZero = isKnownNonZero(Z, Q);
- // icmp u/s (a ^ maxsignval), (b ^ maxsignval) --> icmp s/u' a, b
- if (BO0->getOpcode() == Instruction::Xor && C->isMaxSignedValue()) {
- ICmpInst::Predicate NewPred = I.getFlippedSignednessPredicate();
- NewPred = I.getSwappedPredicate(NewPred);
- return new ICmpInst(NewPred, BO0->getOperand(0), BO1->getOperand(0));
+ // 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 && Op0HasNUW && Op1HasNUW)
+ return new ICmpInst(Pred, X, Y);
}
}
- break;
}
- case Instruction::Mul: {
- if (!I.isEquality())
- break;
- const APInt *C;
- if (match(BO0->getOperand(1), m_APInt(C)) && !C->isZero() &&
- !C->isOne()) {
- // icmp eq/ne (X * C), (Y * C) --> icmp (X & Mask), (Y & Mask)
- // Mask = -1 >> count-trailing-zeros(C).
- if (unsigned TZs = C->countr_zero()) {
- Constant *Mask = ConstantInt::get(
- BO0->getType(),
- APInt::getLowBitsSet(C->getBitWidth(), C->getBitWidth() - TZs));
- Value *And1 = Builder.CreateAnd(BO0->getOperand(0), Mask);
- Value *And2 = Builder.CreateAnd(BO1->getOperand(0), Mask);
- return new ICmpInst(Pred, And1, And2);
- }
+ BinaryOperator *SRem = nullptr;
+ // icmp (srem X, Y), Y
+ if (BO0 && BO0->getOpcode() == Instruction::SRem &&
+ Op1 == BO0->getOperand(1))
+ SRem = BO0;
+ // icmp Y, (srem X, Y)
+ else if (BO1 && BO1->getOpcode() == Instruction::SRem &&
+ Op0 == BO1->getOperand(1))
+ SRem = BO1;
+ if (SRem) {
+ // We don't check hasOneUse to avoid increasing register pressure because
+ // the value we use is the same value this instruction was already using.
+ switch (SRem == BO0 ? ICmpInst::getSwappedPredicate(Pred) : Pred) {
+ default:
+ break;
+ case ICmpInst::ICMP_EQ:
+ return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
+ case ICmpInst::ICMP_NE:
+ return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType()));
+ case ICmpInst::ICMP_SGT:
+ case ICmpInst::ICMP_SGE:
+ return new ICmpInst(ICmpInst::ICMP_SGT, SRem->getOperand(1),
+ Constant::getAllOnesValue(SRem->getType()));
+ case ICmpInst::ICMP_SLT:
+ case ICmpInst::ICMP_SLE:
+ return new ICmpInst(ICmpInst::ICMP_SLT, SRem->getOperand(1),
+ Constant::getNullValue(SRem->getType()));
}
- break;
}
- case Instruction::UDiv:
- case Instruction::LShr:
- if (I.isSigned() || !BO0->isExact() || !BO1->isExact())
- break;
- return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
- case Instruction::SDiv:
- if (!(I.isEquality() || match(BO0->getOperand(1), m_NonNegative())) ||
- !BO0->isExact() || !BO1->isExact())
+ if (BO0 && BO1 && BO0->getOpcode() == BO1->getOpcode() &&
+ (BO0->hasOneUse() || BO1->hasOneUse()) &&
+ BO0->getOperand(1) == BO1->getOperand(1)) {
+ switch (BO0->getOpcode()) {
+ default:
break;
- return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Xor: {
+ if (I.isEquality()) // a+x icmp eq/ne b+x --> a icmp b
+ return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
+
+ const APInt *C;
+ if (match(BO0->getOperand(1), m_APInt(C))) {
+ // icmp u/s (a ^ signmask), (b ^ signmask) --> icmp s/u a, b
+ if (C->isSignMask()) {
+ ICmpInst::Predicate NewPred = I.getFlippedSignednessPredicate();
+ return new ICmpInst(NewPred, BO0->getOperand(0),
+ BO1->getOperand(0));
+ }
- case Instruction::AShr:
- if (!BO0->isExact() || !BO1->isExact())
+ // icmp u/s (a ^ maxsignval), (b ^ maxsignval) --> icmp s/u' a, b
+ if (BO0->getOpcode() == Instruction::Xor && C->isMaxSignedValue()) {
+ ICmpInst::Predicate NewPred = I.getFlippedSignednessPredicate();
+ NewPred = I.getSwappedPredicate(NewPred);
+ return new ICmpInst(NewPred, BO0->getOperand(0),
+ BO1->getOperand(0));
+ }
+ }
break;
- return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
+ }
+ case Instruction::Mul: {
+ if (!I.isEquality())
+ break;
- case Instruction::Shl: {
- bool NUW = Op0HasNUW && Op1HasNUW;
- bool NSW = Op0HasNSW && Op1HasNSW;
- if (!NUW && !NSW)
- break;
- if (!NSW && I.isSigned())
+ const APInt *C;
+ if (match(BO0->getOperand(1), m_APInt(C)) && !C->isZero() &&
+ !C->isOne()) {
+ // icmp eq/ne (X * C), (Y * C) --> icmp (X & Mask), (Y & Mask)
+ // Mask = -1 >> count-trailing-zeros(C).
+ if (unsigned TZs = C->countr_zero()) {
+ Constant *Mask = ConstantInt::get(
+ BO0->getType(),
+ APInt::getLowBitsSet(C->getBitWidth(), C->getBitWidth() - TZs));
+ Value *And1 = Builder.CreateAnd(BO0->getOperand(0), Mask);
+ Value *And2 = Builder.CreateAnd(BO1->getOperand(0), Mask);
+ return new ICmpInst(Pred, And1, And2);
+ }
+ }
break;
- return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
- }
+ }
+ case Instruction::UDiv:
+ case Instruction::LShr:
+ if (I.isSigned() || !BO0->isExact() || !BO1->isExact())
+ break;
+ return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
+
+ case Instruction::SDiv:
+ if (!(I.isEquality() || match(BO0->getOperand(1), m_NonNegative())) ||
+ !BO0->isExact() || !BO1->isExact())
+ break;
+ return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
+
+ case Instruction::AShr:
+ if (!BO0->isExact() || !BO1->isExact())
+ break;
+ return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
+
+ case Instruction::Shl: {
+ bool NUW = Op0HasNUW && Op1HasNUW;
+ bool NSW = Op0HasNSW && Op1HasNSW;
+ if (!NUW && !NSW)
+ break;
+ if (!NSW && I.isSigned())
+ break;
+ return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0));
+ }
+ }
}
- }
- if (BO0) {
- // Transform A & (L - 1) `ult` L --> L != 0
- auto LSubOne = m_Add(m_Specific(Op1), m_AllOnes());
- auto BitwiseAnd = m_c_And(m_Value(), LSubOne);
+ if (BO0) {
+ // Transform A & (L - 1) `ult` L --> L != 0
+ auto LSubOne = m_Add(m_Specific(Op1), m_AllOnes());
+ auto BitwiseAnd = m_c_And(m_Value(), LSubOne);
- if (match(BO0, BitwiseAnd) && Pred == ICmpInst::ICMP_ULT) {
- auto *Zero = Constant::getNullValue(BO0->getType());
- return new ICmpInst(ICmpInst::ICMP_NE, Op1, Zero);
+ if (match(BO0, BitwiseAnd) && Pred == ICmpInst::ICMP_ULT) {
+ auto *Zero = Constant::getNullValue(BO0->getType());
+ return new ICmpInst(ICmpInst::ICMP_NE, Op1, Zero);
+ }
}
- }
- // For unsigned predicates / eq / ne:
- // icmp pred (x << 1), x --> icmp getSignedPredicate(pred) x, 0
- // icmp pred x, (x << 1) --> icmp getSignedPredicate(pred) 0, x
- if (!ICmpInst::isSigned(Pred)) {
- if (match(Op0, m_Shl(m_Specific(Op1), m_One())))
- return new ICmpInst(ICmpInst::getSignedPredicate(Pred), Op1,
- Constant::getNullValue(Op1->getType()));
- else if (match(Op1, m_Shl(m_Specific(Op0), m_One())))
- return new ICmpInst(ICmpInst::getSignedPredicate(Pred),
- Constant::getNullValue(Op0->getType()), Op0);
- }
+ // For unsigned predicates / eq / ne:
+ // icmp pred (x << 1), x --> icmp getSignedPredicate(pred) x, 0
+ // icmp pred x, (x << 1) --> icmp getSignedPredicate(pred) 0, x
+ if (!ICmpInst::isSigned(Pred)) {
+ if (match(Op0, m_Shl(m_Specific(Op1), m_One())))
+ return new ICmpInst(ICmpInst::getSignedPredicate(Pred), Op1,
+ Constant::getNullValue(Op1->getType()));
+ else if (match(Op1, m_Shl(m_Specific(Op0), m_One())))
+ return new ICmpInst(ICmpInst::getSignedPredicate(Pred),
+ Constant::getNullValue(Op0->getType()), Op0);
+ }
- if (Value *V = foldMultiplicationOverflowCheck(I))
- return replaceInstUsesWith(I, V);
+ if (Value *V = foldMultiplicationOverflowCheck(I))
+ return replaceInstUsesWith(I, V);
- if (Instruction *R = foldICmpAndXX(I, Q, *this))
- return R;
+ if (Instruction *R = foldICmpAndXX(I, Q, *this))
+ return R;
- if (Value *V = foldICmpWithTruncSignExtendedVal(I, Builder))
- return replaceInstUsesWith(I, V);
+ if (Value *V = foldICmpWithTruncSignExtendedVal(I, Builder))
+ return replaceInstUsesWith(I, V);
- if (Value *V = foldShiftIntoShiftInAnotherHandOfAndInICmp(I, SQ, Builder))
- return replaceInstUsesWith(I, V);
+ if (Value *V = foldShiftIntoShiftInAnotherHandOfAndInICmp(I, SQ, Builder))
+ return replaceInstUsesWith(I, V);
- return nullptr;
-}
+ return nullptr;
+ }
/// Fold icmp Pred min|max(X, Y), Z.
Instruction *InstCombinerImpl::foldICmpWithMinMax(Instruction &I,
``````````
</details>
https://github.com/llvm/llvm-project/pull/217805
More information about the llvm-commits
mailing list