@@ -9585,56 +9585,147 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
95859585 bool HasNSW = IIQ.hasNoSignedWrap (&BO);
95869586 bool HasNUW = IIQ.hasNoUnsignedWrap (&BO);
95879587
9588- // If the caller expects a signed compare, then try to use a signed range.
9589- // Otherwise if both no-wraps are set, use the unsigned range because it
9590- // is never larger than the signed range. Example:
9591- // "sub nuw nsw i8 -2, x" is unsigned [0, 254] vs. signed [-128, 126].
9592- // "sub nuw nsw i8 2, x" is unsigned [0, 2] vs. signed [-125, 127].
9593- if (PreferSignedRange && HasNSW && HasNUW)
9594- HasNUW = false ;
9595-
9596- if (HasNUW) {
9597- // 'sub nuw c, x' produces [0, C].
9598- Upper = *C + 1 ;
9599- } else if (HasNSW) {
9588+ // Build the two candidate ranges as [lo..hi]:
9589+ // unsignedRange: NUW ⇒ [0 .. C]
9590+ // signedRange: NSW ⇒ either [SINT_MIN .. -C - SINT_MIN] or [C -
9591+ // SINT_MAX .. SINT_MAX]
9592+ auto makeUnsignedRange = [&]() {
9593+ return std::pair<APInt, APInt>(APInt::getZero (Width), *C);
9594+ };
9595+ auto makeSignedRange = [&]() {
96009596 if (C->isNegative ()) {
9601- // 'sub nsw -C, x' produces [SINT_MIN, -C - SINT_MIN].
9602- Lower = APInt::getSignedMinValue (Width);
9603- Upper = *C - APInt::getSignedMaxValue (Width);
9597+ // sub nsw -C, x
9598+ APInt lo = APInt::getSignedMinValue (Width);
9599+ APInt hi = *C - APInt::getSignedMinValue (Width);
9600+ return std::pair<APInt, APInt>(lo, hi);
9601+ } else {
9602+ // sub nsw C, x
9603+ APInt lo = *C - APInt::getSignedMaxValue (Width);
9604+ APInt hi = APInt::getSignedMaxValue (Width);
9605+ return std::pair<APInt, APInt>(lo, hi);
9606+ }
9607+ };
9608+
9609+ // Split a (possibly wrapping) [lo..hi] into up to two non‑wrapping
9610+ // pieces:
9611+ auto splitPieces = [&](std::pair<APInt, APInt> rng,
9612+ SmallVectorImpl<std::pair<APInt, APInt>> &pieces) {
9613+ APInt lo = rng.first , hi = rng.second ;
9614+ if (lo.ugt (hi)) {
9615+ // wraps around 2^n
9616+ pieces.emplace_back (lo, APInt::getMaxValue (Width)); // [lo..2^n-1]
9617+ pieces.emplace_back (APInt::getZero (Width), hi); // [0..hi]
96049618 } else {
9605- // Note that sub 0, INT_MIN is not NSW. It techically is a signed wrap
9606- // 'sub nsw C, x' produces [C - SINT_MAX, SINT_MAX].
9607- Lower = *C - APInt::getSignedMaxValue (Width);
9608- Upper = APInt::getSignedMinValue (Width);
9619+ pieces.emplace_back (lo, hi);
9620+ }
9621+ };
9622+
9623+ SmallVector<std::pair<APInt, APInt>, 2 > piecesU, piecesS;
9624+ if (HasNUW)
9625+ splitPieces (makeUnsignedRange (), piecesU);
9626+ if (HasNSW)
9627+ splitPieces (makeSignedRange (), piecesS);
9628+
9629+ // Intersect piecewise:
9630+ SmallVector<std::pair<APInt, APInt>, 2 > inters;
9631+ for (auto &u : piecesU) {
9632+ for (auto &s : piecesS) {
9633+ APInt loI = u.first .ugt (s.first ) ? u.first : s.first ;
9634+ APInt hiI = u.second .ult (s.second ) ? u.second : s.second ;
9635+ if (loI.ule (hiI))
9636+ inters.emplace_back (loI, hiI);
96099637 }
96109638 }
9639+
9640+ if (inters.size () == 1 ) {
9641+ // Exactly one contiguous overlap → use it
9642+ Lower = inters[0 ].first ;
9643+ Upper = inters[0 ].second ;
9644+ } else if (HasNUW && !PreferSignedRange) {
9645+ // Fallback to plain NUW result [0..C]
9646+ Lower = APInt::getZero (Width);
9647+ Upper = *C;
9648+ } else if (HasNSW) {
9649+ // Fallback to plain NSW result
9650+ auto S = makeSignedRange ();
9651+ Lower = S.first ;
9652+ Upper = S.second ;
9653+ }
96119654 }
96129655 break ;
96139656 case Instruction::Add:
96149657 if (match (BO.getOperand (1 ), m_APInt (C)) && !C->isZero ()) {
96159658 bool HasNSW = IIQ.hasNoSignedWrap (&BO);
96169659 bool HasNUW = IIQ.hasNoUnsignedWrap (&BO);
96179660
9618- // If the caller expects a signed compare, then try to use a signed
9619- // range. Otherwise if both no-wraps are set, use the unsigned range
9620- // because it is never larger than the signed range. Example: "add nuw
9621- // nsw i8 X, -2" is unsigned [254,255] vs. signed [-128, 125].
9622- if (PreferSignedRange && HasNSW && HasNUW)
9623- HasNUW = false ;
9661+ // Build the two candidate ranges as [lo..hi] in the unsigned 0..2^n-1
9662+ // world:
9663+ // NUW: 'add nuw x, C' ⇒ [ C .. UINT_MAX ]
9664+ auto makeUnsignedRange = [&]() {
9665+ APInt lo = *C;
9666+ APInt hi = APInt::getMaxValue (Width);
9667+ return std::pair<APInt, APInt>(lo, hi);
9668+ };
96249669
9625- if (HasNUW) {
9626- // 'add nuw x, C' produces [C, UINT_MAX].
9627- Lower = *C;
9628- } else if (HasNSW ) {
9670+ // NSW: 'add nsw x, C'
9671+ // if C<0: [ SINT_MIN .. SINT_MAX + C ]
9672+ // else: [ SINT_MIN + C .. SINT_MAX ]
9673+ auto makeSignedRange = [&]( ) {
96299674 if (C->isNegative ()) {
9630- // 'add nsw x, -C' produces [SINT_MIN, SINT_MAX - C].
9631- Lower = APInt::getSignedMinValue (Width);
9632- Upper = APInt::getSignedMaxValue (Width) + *C + 1 ;
9675+ APInt lo = APInt::getSignedMinValue (Width);
9676+ APInt hi = APInt::getSignedMaxValue (Width) + *C ;
9677+ return std::pair<APInt, APInt>(lo, hi) ;
96339678 } else {
9634- // 'add nsw x, +C' produces [SINT_MIN + C, SINT_MAX].
9635- Lower = APInt::getSignedMinValue (Width) + *C ;
9636- Upper = APInt::getSignedMaxValue (Width) + 1 ;
9679+ APInt lo = APInt::getSignedMinValue (Width) + *C;
9680+ APInt hi = APInt::getSignedMaxValue (Width);
9681+ return std::pair<APInt, APInt>(lo, hi) ;
96379682 }
9683+ };
9684+
9685+ // Split [lo..hi] into up to two non‑wrapping intervals:
9686+ auto splitPieces = [&](std::pair<APInt, APInt> rng,
9687+ SmallVectorImpl<std::pair<APInt, APInt>> &dst) {
9688+ APInt lo = rng.first , hi = rng.second ;
9689+ if (lo.ugt (hi)) {
9690+ // wraps around 2^n
9691+ dst.emplace_back (lo, APInt::getMaxValue (Width));
9692+ dst.emplace_back (APInt::getZero (Width), hi);
9693+ } else {
9694+ dst.emplace_back (lo, hi);
9695+ }
9696+ };
9697+
9698+ SmallVector<std::pair<APInt, APInt>, 2 > piecesU, piecesS;
9699+ if (HasNUW)
9700+ splitPieces (makeUnsignedRange (), piecesU);
9701+ if (HasNSW)
9702+ splitPieces (makeSignedRange (), piecesS);
9703+
9704+ // Intersect piecewise
9705+ SmallVector<std::pair<APInt, APInt>, 2 > inters;
9706+ for (auto &u : piecesU) {
9707+ for (auto &s : piecesS) {
9708+ APInt loI = u.first .ugt (s.first ) ? u.first : s.first ;
9709+ APInt hiI = u.second .ult (s.second ) ? u.second : s.second ;
9710+ if (loI.ule (hiI))
9711+ inters.emplace_back (loI, hiI);
9712+ }
9713+ }
9714+
9715+ if (inters.size () == 1 ) {
9716+ // Exactly one contiguous overlap ⇒ use it
9717+ Lower = inters[0 ].first ;
9718+ Upper = inters[0 ].second +
9719+ 1 ; // make Upper exclusive if you’re following [Lo..Hi)
9720+ } else if (HasNUW && !PreferSignedRange) {
9721+ // Fallback to plain NUW [C..UINT_MAX]
9722+ Lower = *C;
9723+ Upper = APInt::getMaxValue (Width) + 1 ;
9724+ } else if (HasNSW) {
9725+ // Fallback to plain NSW
9726+ auto S = makeSignedRange ();
9727+ Lower = S.first ;
9728+ Upper = S.second + 1 ;
96389729 }
96399730 }
96409731 break ;
0 commit comments