Skip to content

Commit 1971040

Browse files
committed
[ValueTracking] If overlap in unsigned and signed range is contiguous, return it
We have to choose between unsigned and signed if there are two overlaps, aka the range wraps around, meaning [254,255] vs. signed [-128, 125], but [254,255] correspond to [-2 -1] which is in the range [-128, 125]. However, a range that would not work would be one where one has to pick between [0, 129] vs [-127, 127] because 129 is -2 signed. Update ValueTracking.cpp Revert "[ValueTracking] If overlap in unsigned and signed range is contiguous, return it" This reverts commit 22e997c489aad3173db78f6fee17212bd16be96d. ok
1 parent f4a6352 commit 1971040

File tree

1 file changed

+140
-53
lines changed

1 file changed

+140
-53
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 140 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -9581,63 +9581,150 @@ static void setLimitsForBinOp(const BinaryOperator &BO, APInt &Lower,
95819581
const APInt *C;
95829582
switch (BO.getOpcode()) {
95839583
case Instruction::Sub:
9584-
if (match(BO.getOperand(0), m_APInt(C))) {
9585-
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
9586-
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
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) {
9600-
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);
9604-
} 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);
9609-
}
9584+
if (match(BO.getOperand(0), m_APInt(C))) {
9585+
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
9586+
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
9587+
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 - SINT_MAX .. SINT_MAX]
9591+
auto makeUnsignedRange = [&]() {
9592+
return std::pair<APInt,APInt>(APInt::getZero(Width), *C);
9593+
};
9594+
auto makeSignedRange = [&]() {
9595+
if (C->isNegative()) {
9596+
// sub nsw -C, x
9597+
APInt lo = APInt::getSignedMinValue(Width);
9598+
APInt hi = *C - APInt::getSignedMinValue(Width);
9599+
return std::pair<APInt,APInt>(lo, hi);
9600+
} else {
9601+
// sub nsw C, x
9602+
APInt lo = *C - APInt::getSignedMaxValue(Width);
9603+
APInt hi = APInt::getSignedMaxValue(Width);
9604+
return std::pair<APInt,APInt>(lo, hi);
9605+
}
9606+
};
9607+
9608+
// Split a (possibly wrapping) [lo..hi] into up to two non‑wrapping pieces:
9609+
auto splitPieces = [&](std::pair<APInt,APInt> rng,
9610+
SmallVectorImpl<std::pair<APInt,APInt>>& pieces) {
9611+
APInt lo = rng.first, hi = rng.second;
9612+
if (lo.ugt(hi)) {
9613+
// wraps around 2^n
9614+
pieces.emplace_back(lo, APInt::getMaxValue(Width)); // [lo..2^n-1]
9615+
pieces.emplace_back(APInt::getZero(Width), hi); // [0..hi]
9616+
} else {
9617+
pieces.emplace_back(lo, hi);
9618+
}
9619+
};
9620+
9621+
SmallVector<std::pair<APInt,APInt>,2> piecesU, piecesS;
9622+
if (HasNUW) splitPieces(makeUnsignedRange(), piecesU);
9623+
if (HasNSW) splitPieces(makeSignedRange(), piecesS);
9624+
9625+
// Intersect piecewise:
9626+
SmallVector<std::pair<APInt,APInt>,2> inters;
9627+
for (auto &u : piecesU) {
9628+
for (auto &s : piecesS) {
9629+
APInt loI = u.first.ugt(s.first) ? u.first : s.first;
9630+
APInt hiI = u.second.ult(s.second) ? u.second : s.second;
9631+
if (loI.ule(hiI))
9632+
inters.emplace_back(loI, hiI);
96109633
}
96119634
}
9612-
break;
9613-
case Instruction::Add:
9614-
if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) {
9615-
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
9616-
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
9617-
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;
9624-
9625-
if (HasNUW) {
9626-
// 'add nuw x, C' produces [C, UINT_MAX].
9627-
Lower = *C;
9628-
} else if (HasNSW) {
9629-
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;
9633-
} else {
9634-
// 'add nsw x, +C' produces [SINT_MIN + C, SINT_MAX].
9635-
Lower = APInt::getSignedMinValue(Width) + *C;
9636-
Upper = APInt::getSignedMaxValue(Width) + 1;
9637-
}
9635+
9636+
if (inters.size() == 1) {
9637+
// Exactly one contiguous overlap → use it
9638+
Lower = inters[0].first;
9639+
Upper = inters[0].second;
9640+
} else if (HasNUW && !PreferSignedRange) {
9641+
// Fallback to plain NUW result [0..C]
9642+
Lower = APInt::getZero(Width);
9643+
Upper = *C;
9644+
} else if (HasNSW) {
9645+
// Fallback to plain NSW result
9646+
auto S = makeSignedRange();
9647+
Lower = S.first;
9648+
Upper = S.second;
9649+
}
9650+
}
9651+
break;
9652+
case Instruction::Add:
9653+
if (match(BO.getOperand(1), m_APInt(C)) && !C->isZero()) {
9654+
bool HasNSW = IIQ.hasNoSignedWrap(&BO);
9655+
bool HasNUW = IIQ.hasNoUnsignedWrap(&BO);
9656+
9657+
// If the caller prefers signed ranges when both wraps are forbidden:
9658+
if (PreferSignedRange && HasNSW && HasNUW)
9659+
HasNUW = false;
9660+
9661+
// Build the two candidate ranges as [lo..hi] in the unsigned 0..2^n-1 world:
9662+
// NUW: 'add nuw x, C' ⇒ [ C .. UINT_MAX ]
9663+
auto makeUnsignedRange = [&]() {
9664+
APInt lo = *C;
9665+
APInt hi = APInt::getMaxValue(Width);
9666+
return std::pair<APInt,APInt>(lo, hi);
9667+
};
9668+
9669+
// NSW: 'add nsw x, C'
9670+
// if C<0: [ SINT_MIN .. SINT_MAX + C ]
9671+
// else: [ SINT_MIN + C .. SINT_MAX ]
9672+
auto makeSignedRange = [&]() {
9673+
if (C->isNegative()) {
9674+
APInt lo = APInt::getSignedMinValue(Width);
9675+
APInt hi = APInt::getSignedMaxValue(Width) + *C;
9676+
return std::pair<APInt,APInt>(lo, hi);
9677+
} else {
9678+
APInt lo = APInt::getSignedMinValue(Width) + *C;
9679+
APInt hi = APInt::getSignedMaxValue(Width);
9680+
return std::pair<APInt,APInt>(lo, hi);
9681+
}
9682+
};
9683+
9684+
// Split [lo..hi] into up to two non‑wrapping intervals:
9685+
auto splitPieces = [&](std::pair<APInt,APInt> rng,
9686+
SmallVectorImpl<std::pair<APInt,APInt>> &dst) {
9687+
APInt lo = rng.first, hi = rng.second;
9688+
if (lo.ugt(hi)) {
9689+
// wraps around 2^n
9690+
dst.emplace_back(lo, APInt::getMaxValue(Width));
9691+
dst.emplace_back(APInt::getZero(Width), hi);
9692+
} else {
9693+
dst.emplace_back(lo, hi);
9694+
}
9695+
};
9696+
9697+
SmallVector<std::pair<APInt,APInt>,2> piecesU, piecesS;
9698+
if (HasNUW) splitPieces(makeUnsignedRange(), piecesU);
9699+
if (HasNSW) splitPieces(makeSignedRange(), piecesS);
9700+
9701+
// Intersect piecewise
9702+
SmallVector<std::pair<APInt,APInt>,2> inters;
9703+
for (auto &u : piecesU) {
9704+
for (auto &s : piecesS) {
9705+
APInt loI = u.first.ugt(s.first) ? u.first : s.first;
9706+
APInt hiI = u.second.ult(s.second) ? u.second : s.second;
9707+
if (loI.ule(hiI))
9708+
inters.emplace_back(loI, hiI);
96389709
}
96399710
}
9640-
break;
9711+
9712+
if (inters.size() == 1) {
9713+
// Exactly one contiguous overlap ⇒ use it
9714+
Lower = inters[0].first;
9715+
Upper = inters[0].second + 1; // make Upper exclusive if you’re following [Lo..Hi)
9716+
} else if (HasNUW && !PreferSignedRange) {
9717+
// Fallback to plain NUW [C..UINT_MAX]
9718+
Lower = *C;
9719+
Upper = APInt::getMaxValue(Width) + 1;
9720+
} else if (HasNSW) {
9721+
// Fallback to plain NSW
9722+
auto S = makeSignedRange();
9723+
Lower = S.first;
9724+
Upper = S.second + 1;
9725+
}
9726+
}
9727+
break;
96419728

96429729
case Instruction::And:
96439730
if (match(BO.getOperand(1), m_APInt(C)))

0 commit comments

Comments
 (0)