@@ -5120,6 +5120,18 @@ 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.isOne ())
5127+ return true ;
5128+
5129+ if (!C.isPowerOf2 ())
5130+ return false ;
5131+
5132+ return MaskedValueIsZero (X, C - 1 , Q);
5133+ }
5134+
51235135// / Try to fold icmp (binop), X or icmp X, (binop).
51245136// / TODO: A large part of this logic is duplicated in InstSimplify's
51255137// / simplifyICmpWithBinOp(). We should be able to share that and avoid the code
@@ -5278,66 +5290,62 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
52785290 return new ICmpInst (Pred, Y, Z);
52795291 }
52805292
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);
5293+ if (ICmpInst::isRelational (Pred)) {
5294+ // Return if both X and Y is divisible by Z/-Z.
5295+ // TODO: Generalize to check if (X - Y) is divisible by Z/-Z.
5296+ auto ShareCommonDivisor = [&Q](Value *X, Value *Y, Value *Z,
5297+ bool IsNegative) -> bool {
5298+ const APInt *OffsetC;
5299+ if (!match (Z, m_APInt (OffsetC)))
5300+ return false ;
52985301
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);
5302+ // Fast path for Z == 1/-1.
5303+ if (IsNegative ? OffsetC->isAllOnes () : OffsetC->isOne ())
5304+ return true ;
53035305
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);
5306+ APInt C = *OffsetC;
5307+ if (IsNegative)
5308+ C.negate ();
5309+ // Note: -INT_MIN is also negative.
5310+ if (!C.isStrictlyPositive ())
5311+ return false ;
53085312
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);
5313+ return isMultipleOf (X, C, Q) && isMultipleOf (Y, C, Q);
5314+ };
53125315
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);
5316+ // TODO: The subtraction-related identities shown below also hold, but
5317+ // canonicalization from (X -nuw 1) to (X + -1) means that the combinations
5318+ // wouldn't happen even if they were implemented.
5319+ //
5320+ // icmp ult (A - 1), Op1 -> icmp ule A, Op1
5321+ // icmp uge (A - 1), Op1 -> icmp ugt A, Op1
5322+ // icmp ugt Op0, (C - 1) -> icmp uge Op0, C
5323+ // icmp ule Op0, (C - 1) -> icmp ult Op0, C
5324+
5325+ // icmp slt (A + -1), Op1 -> icmp sle A, Op1
5326+ // icmp sge (A + -1), Op1 -> icmp sgt A, Op1
5327+ // icmp sle (A + 1), Op1 -> icmp slt A, Op1
5328+ // icmp sgt (A + 1), Op1 -> icmp sge A, Op1
5329+ // icmp ule (A + 1), Op0 -> icmp ult A, Op1
5330+ // icmp ugt (A + 1), Op0 -> icmp uge A, Op1
5331+ if (A && NoOp0WrapProblem &&
5332+ ShareCommonDivisor (A, Op1, B,
5333+ ICmpInst::isLT (Pred) || ICmpInst::isGE (Pred)))
5334+ return new ICmpInst (ICmpInst::getFlippedStrictnessPredicate (Pred), A,
5335+ Op1);
53165336
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);
5337+ // icmp sgt Op0, (C + -1) -> icmp sge Op0, C
5338+ // icmp sle Op0, (C + -1) -> icmp slt Op0, C
5339+ // icmp sge Op0, (C + 1) -> icmp sgt Op0, C
5340+ // icmp slt Op0, (C + 1) -> icmp sle Op0, C
5341+ // icmp uge Op0, (C + 1) -> icmp ugt Op0, C
5342+ // icmp ult Op0, (C + 1) -> icmp ule Op0, C
5343+ if (C && NoOp1WrapProblem &&
5344+ ShareCommonDivisor (Op0, C, D,
5345+ ICmpInst::isGT (Pred) || ICmpInst::isLE (Pred)))
5346+ return new ICmpInst (ICmpInst::getFlippedStrictnessPredicate (Pred), Op0,
5347+ C);
5348+ }
53415349
53425350 // if C1 has greater magnitude than C2:
53435351 // icmp (A + C1), (C + C2) -> icmp (A + C3), C
0 commit comments