@@ -5120,6 +5120,15 @@ static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
51205120 return nullptr ;
51215121}
51225122
5123+ // / Return true if X is a multiple of C.
5124+ // / TODO: Handle non-power-of-2 factors.
5125+ static bool isMultipleOf (Value *X, const APInt &C, const SimplifyQuery &Q) {
5126+ if (!C.isPowerOf2 ())
5127+ return false ;
5128+
5129+ return MaskedValueIsZero (X, C - 1 , Q);
5130+ }
5131+
51235132// / Try to fold icmp (binop), X or icmp X, (binop).
51245133// / TODO: A large part of this logic is duplicated in InstSimplify's
51255134// / simplifyICmpWithBinOp(). We should be able to share that and avoid the code
@@ -5278,66 +5287,62 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
52785287 return new ICmpInst (Pred, Y, Z);
52795288 }
52805289
5281- // icmp slt (A + -1), Op1 -> icmp sle A, Op1
5282- if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SLT &&
5283- match (B, m_AllOnes ()))
5284- return new ICmpInst (CmpInst::ICMP_SLE, A, Op1);
5285-
5286- // icmp sge (A + -1), Op1 -> icmp sgt A, Op1
5287- if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SGE &&
5288- match (B, m_AllOnes ()))
5289- return new ICmpInst (CmpInst::ICMP_SGT, A, Op1);
5290-
5291- // icmp sle (A + 1), Op1 -> icmp slt A, Op1
5292- if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SLE && match (B, m_One ()))
5293- return new ICmpInst (CmpInst::ICMP_SLT, A, Op1);
5294-
5295- // icmp sgt (A + 1), Op1 -> icmp sge A, Op1
5296- if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_SGT && match (B, m_One ()))
5297- return new ICmpInst (CmpInst::ICMP_SGE, A, Op1);
5290+ if (ICmpInst::isRelational (Pred)) {
5291+ // Return if both X and Y is divisible by Z/-Z.
5292+ // TODO: Generalize to check if (X - Y) is divisible by Z/-Z.
5293+ auto ShareCommonDivisor = [&Q](Value *X, Value *Y, Value *Z,
5294+ bool IsNegative) -> bool {
5295+ const APInt *OffsetC;
5296+ if (!match (Z, m_APInt (OffsetC)))
5297+ return false ;
52985298
5299- // icmp sgt Op0, (C + -1) -> icmp sge Op0, C
5300- if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SGT &&
5301- match (D, m_AllOnes ()))
5302- return new ICmpInst (CmpInst::ICMP_SGE, Op0, C);
5299+ // Fast path for Z == 1/-1.
5300+ if (IsNegative ? OffsetC->isAllOnes () : OffsetC->isOne ())
5301+ return true ;
53035302
5304- // icmp sle Op0, (C + -1) -> icmp slt Op0, C
5305- if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SLE &&
5306- match (D, m_AllOnes ()))
5307- return new ICmpInst (CmpInst::ICMP_SLT, Op0, C);
5303+ APInt C = *OffsetC;
5304+ if (IsNegative)
5305+ C.negate ();
5306+ // Note: -INT_MIN is also negative.
5307+ if (!C.isStrictlyPositive ())
5308+ return false ;
53085309
5309- // icmp sge Op0, (C + 1) -> icmp sgt Op0, C
5310- if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SGE && match (D, m_One ()))
5311- return new ICmpInst (CmpInst::ICMP_SGT, Op0, C);
5310+ return isMultipleOf (X, C, Q) && isMultipleOf (Y, C, Q);
5311+ };
53125312
5313- // icmp slt Op0, (C + 1) -> icmp sle Op0, C
5314- if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_SLT && match (D, m_One ()))
5315- return new ICmpInst (CmpInst::ICMP_SLE, Op0, C);
5313+ // TODO: The subtraction-related identities shown below also hold, but
5314+ // canonicalization from (X -nuw 1) to (X + -1) means that the combinations
5315+ // wouldn't happen even if they were implemented.
5316+ //
5317+ // icmp ult (A - 1), Op1 -> icmp ule A, Op1
5318+ // icmp uge (A - 1), Op1 -> icmp ugt A, Op1
5319+ // icmp ugt Op0, (C - 1) -> icmp uge Op0, C
5320+ // icmp ule Op0, (C - 1) -> icmp ult Op0, C
5321+
5322+ // icmp slt (A + -1), Op1 -> icmp sle A, Op1
5323+ // icmp sge (A + -1), Op1 -> icmp sgt A, Op1
5324+ // icmp sle (A + 1), Op1 -> icmp slt A, Op1
5325+ // icmp sgt (A + 1), Op1 -> icmp sge A, Op1
5326+ // icmp ule (A + 1), Op0 -> icmp ult A, Op1
5327+ // icmp ugt (A + 1), Op0 -> icmp uge A, Op1
5328+ if (A && NoOp0WrapProblem &&
5329+ ShareCommonDivisor (A, Op1, B,
5330+ ICmpInst::isLT (Pred) || ICmpInst::isGE (Pred)))
5331+ return new ICmpInst (ICmpInst::getFlippedStrictnessPredicate (Pred), A,
5332+ Op1);
53165333
5317- // TODO: The subtraction-related identities shown below also hold, but
5318- // canonicalization from (X -nuw 1) to (X + -1) means that the combinations
5319- // wouldn't happen even if they were implemented.
5320- //
5321- // icmp ult (A - 1), Op1 -> icmp ule A, Op1
5322- // icmp uge (A - 1), Op1 -> icmp ugt A, Op1
5323- // icmp ugt Op0, (C - 1) -> icmp uge Op0, C
5324- // icmp ule Op0, (C - 1) -> icmp ult Op0, C
5325-
5326- // icmp ule (A + 1), Op0 -> icmp ult A, Op1
5327- if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_ULE && match (B, m_One ()))
5328- return new ICmpInst (CmpInst::ICMP_ULT, A, Op1);
5329-
5330- // icmp ugt (A + 1), Op0 -> icmp uge A, Op1
5331- if (A && NoOp0WrapProblem && Pred == CmpInst::ICMP_UGT && match (B, m_One ()))
5332- return new ICmpInst (CmpInst::ICMP_UGE, A, Op1);
5333-
5334- // icmp uge Op0, (C + 1) -> icmp ugt Op0, C
5335- if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_UGE && match (D, m_One ()))
5336- return new ICmpInst (CmpInst::ICMP_UGT, Op0, C);
5337-
5338- // icmp ult Op0, (C + 1) -> icmp ule Op0, C
5339- if (C && NoOp1WrapProblem && Pred == CmpInst::ICMP_ULT && match (D, m_One ()))
5340- return new ICmpInst (CmpInst::ICMP_ULE, Op0, C);
5334+ // icmp sgt Op0, (C + -1) -> icmp sge Op0, C
5335+ // icmp sle Op0, (C + -1) -> icmp slt Op0, C
5336+ // icmp sge Op0, (C + 1) -> icmp sgt Op0, C
5337+ // icmp slt Op0, (C + 1) -> icmp sle Op0, C
5338+ // icmp uge Op0, (C + 1) -> icmp ugt Op0, C
5339+ // icmp ult Op0, (C + 1) -> icmp ule Op0, C
5340+ if (C && NoOp1WrapProblem &&
5341+ ShareCommonDivisor (Op0, C, D,
5342+ ICmpInst::isGT (Pred) || ICmpInst::isLE (Pred)))
5343+ return new ICmpInst (ICmpInst::getFlippedStrictnessPredicate (Pred), Op0,
5344+ C);
5345+ }
53415346
53425347 // if C1 has greater magnitude than C2:
53435348 // icmp (A + C1), (C + C2) -> icmp (A + C3), C
0 commit comments