@@ -9585,56 +9585,151 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
9585
9585
bool HasNSW = IIQ.hasNoSignedWrap (&BO);
9586
9586
bool HasNUW = IIQ.hasNoUnsignedWrap (&BO);
9587
9587
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 = [&]() {
9600
9596
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]
9604
9618
} 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);
9609
9637
}
9610
9638
}
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
+ }
9611
9654
}
9612
9655
break ;
9613
9656
case Instruction::Add:
9614
9657
if (match (BO.getOperand (1 ), m_APInt (C)) && !C->isZero ()) {
9615
9658
bool HasNSW = IIQ.hasNoSignedWrap (&BO);
9616
9659
bool HasNUW = IIQ.hasNoUnsignedWrap (&BO);
9617
9660
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].
9661
+ // If the caller prefers signed ranges when both wraps are forbidden:
9622
9662
if (PreferSignedRange && HasNSW && HasNUW)
9623
9663
HasNUW = false ;
9624
9664
9625
- if (HasNUW) {
9626
- // 'add nuw x, C' produces [C, UINT_MAX].
9627
- Lower = *C;
9628
- } else if (HasNSW) {
9665
+ // Build the two candidate ranges as [lo..hi] in the unsigned 0..2^n-1
9666
+ // world:
9667
+ // NUW: 'add nuw x, C' ⇒ [ C .. UINT_MAX ]
9668
+ auto makeUnsignedRange = [&]() {
9669
+ APInt lo = *C;
9670
+ APInt hi = APInt::getMaxValue (Width);
9671
+ return std::pair<APInt, APInt>(lo, hi);
9672
+ };
9673
+
9674
+ // NSW: 'add nsw x, C'
9675
+ // if C<0: [ SINT_MIN .. SINT_MAX + C ]
9676
+ // else: [ SINT_MIN + C .. SINT_MAX ]
9677
+ auto makeSignedRange = [&]() {
9629
9678
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 ;
9679
+ APInt lo = APInt::getSignedMinValue (Width);
9680
+ APInt hi = APInt::getSignedMaxValue (Width) + *C;
9681
+ return std::pair<APInt, APInt>(lo, hi);
9682
+ } else {
9683
+ APInt lo = APInt::getSignedMinValue (Width) + *C;
9684
+ APInt hi = APInt::getSignedMaxValue (Width);
9685
+ return std::pair<APInt, APInt>(lo, hi);
9686
+ }
9687
+ };
9688
+
9689
+ // Split [lo..hi] into up to two non‑wrapping intervals:
9690
+ auto splitPieces = [&](std::pair<APInt, APInt> rng,
9691
+ SmallVectorImpl<std::pair<APInt, APInt>> &dst) {
9692
+ APInt lo = rng.first , hi = rng.second ;
9693
+ if (lo.ugt (hi)) {
9694
+ // wraps around 2^n
9695
+ dst.emplace_back (lo, APInt::getMaxValue (Width));
9696
+ dst.emplace_back (APInt::getZero (Width), hi);
9633
9697
} else {
9634
- // 'add nsw x, +C' produces [SINT_MIN + C, SINT_MAX].
9635
- Lower = APInt::getSignedMinValue (Width) + *C;
9636
- Upper = APInt::getSignedMaxValue (Width) + 1 ;
9698
+ dst.emplace_back (lo, hi);
9637
9699
}
9700
+ };
9701
+
9702
+ SmallVector<std::pair<APInt, APInt>, 2 > piecesU, piecesS;
9703
+ if (HasNUW)
9704
+ splitPieces (makeUnsignedRange (), piecesU);
9705
+ if (HasNSW)
9706
+ splitPieces (makeSignedRange (), piecesS);
9707
+
9708
+ // Intersect piecewise
9709
+ SmallVector<std::pair<APInt, APInt>, 2 > inters;
9710
+ for (auto &u : piecesU) {
9711
+ for (auto &s : piecesS) {
9712
+ APInt loI = u.first .ugt (s.first ) ? u.first : s.first ;
9713
+ APInt hiI = u.second .ult (s.second ) ? u.second : s.second ;
9714
+ if (loI.ule (hiI))
9715
+ inters.emplace_back (loI, hiI);
9716
+ }
9717
+ }
9718
+
9719
+ if (inters.size () == 1 ) {
9720
+ // Exactly one contiguous overlap ⇒ use it
9721
+ Lower = inters[0 ].first ;
9722
+ Upper = inters[0 ].second +
9723
+ 1 ; // make Upper exclusive if you’re following [Lo..Hi)
9724
+ } else if (HasNUW && !PreferSignedRange) {
9725
+ // Fallback to plain NUW [C..UINT_MAX]
9726
+ Lower = *C;
9727
+ Upper = APInt::getMaxValue (Width) + 1 ;
9728
+ } else if (HasNSW) {
9729
+ // Fallback to plain NSW
9730
+ auto S = makeSignedRange ();
9731
+ Lower = S.first ;
9732
+ Upper = S.second + 1 ;
9638
9733
}
9639
9734
}
9640
9735
break ;
0 commit comments