[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