[PATCH] D71011: [ConstantRange] Add `shlWithNoWrap()` method
Nikita Popov via Phabricator via llvm-commits
llvm-commits at lists.llvm.org
Sun Dec 8 08:47:37 PST 2019
nikic added a comment.
Unlike the mul case, it should be possible to efficiently compute a precise shl range. This is the implementation I came up with for the nuw case:
if (NoWrapKind == OBO::NoUnsignedWrap) {
APInt Min = getUnsignedMin(), Max = getUnsignedMax();
unsigned MinLeadingZeros = Max.countLeadingZeros();
unsigned MaxLeadingZeros = Min.countLeadingZeros();
unsigned ShAmtMax = ShAmt.getUnsignedMax().getLimitedValue();
unsigned ShAmtMin = ShAmt.getUnsignedMin().getLimitedValue();
if (ShAmtMin > MaxLeadingZeros)
// All possible shifts will overflow.
return getEmpty();
APInt ResMin = Min.shl(ShAmtMin);
// We'll pick the larger of two possible upper bounds, initialize to zero.
APInt ResMax = APInt::getNullValue(BitWidth);
// Shift the maximum as far as possible without overflowing.
if (ShAmtMin <= MinLeadingZeros)
ResMax = Max.shl(std::min(ShAmtMax, MinLeadingZeros));
// Pick the largest number with all low bits sets that is both in the LHS
// range and can be shifted without overflowing.
if (MinLeadingZeros != MaxLeadingZeros && ShAmtMax >= MinLeadingZeros + 1) {
unsigned Shift = std::max(ShAmtMin, MinLeadingZeros + 1);
ResMax = APIntOps::umax(ResMax,
APInt::getLowBitsSet(BitWidth, BitWidth - Shift).shl(Shift));
}
return getNonEmpty(ResMin, ResMax + 1);
}
It passes the exhaustive test without the correctness only flag.
Extending this to the nuw+nsw case should be fairly simple, as it basically just has one less usable bit. I haven't thought about the nsw case yet.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D71011/new/
https://reviews.llvm.org/D71011
More information about the llvm-commits
mailing list