[ConstantRange] Compute precise shl range for single elements

For the common case where the shift amount is constant (a single
element range) we can easily compute a precise range (up to
unsigned envelope), so do that.
This commit is contained in:
Nikita Popov 2021-10-15 21:25:39 +02:00
parent f92db6d3ff
commit 587493b441
2 changed files with 38 additions and 13 deletions

View File

@ -1346,24 +1346,33 @@ ConstantRange::shl(const ConstantRange &Other) const {
if (isEmptySet() || Other.isEmptySet())
return getEmpty();
APInt max = getUnsignedMax();
APInt Other_umax = Other.getUnsignedMax();
APInt Min = getUnsignedMin();
APInt Max = getUnsignedMax();
if (const APInt *RHS = Other.getSingleElement()) {
unsigned BW = getBitWidth();
if (RHS->uge(BW))
return getEmpty();
// If we are shifting by maximum amount of
// zero return return the original range.
if (Other_umax.isZero())
return *this;
// there's overflow!
if (Other_umax.ugt(max.countLeadingZeros()))
unsigned EqualLeadingBits = (Min ^ Max).countLeadingZeros();
if (RHS->ule(EqualLeadingBits))
return getNonEmpty(Min << *RHS, (Max << *RHS) + 1);
return getNonEmpty(APInt::getZero(BW),
APInt::getBitsSetFrom(BW, RHS->getZExtValue()) + 1);
}
APInt OtherMax = Other.getUnsignedMax();
// There's overflow!
if (OtherMax.ugt(Max.countLeadingZeros()))
return getFull();
// FIXME: implement the other tricky cases
APInt min = getUnsignedMin();
min <<= Other.getUnsignedMin();
max <<= Other_umax;
Min <<= Other.getUnsignedMin();
Max <<= OtherMax;
return ConstantRange(std::move(min), std::move(max) + 1);
return ConstantRange::getNonEmpty(std::move(Min), std::move(Max) + 1);
}
ConstantRange

View File

@ -1400,7 +1400,8 @@ TEST_F(ConstantRangeTest, Shl) {
ConstantRange WrapNullMax(APInt(16, 0x1), APInt(16, 0x0));
EXPECT_EQ(Full.shl(Full), Full);
EXPECT_EQ(Full.shl(Empty), Empty);
EXPECT_EQ(Full.shl(One), Full); // TODO: [0, (-1 << 0xa) + 1)
EXPECT_EQ(Full.shl(One), ConstantRange(APInt(16, 0),
APInt(16, 0xfc00) + 1));
EXPECT_EQ(Full.shl(Some), Full); // TODO: [0, (-1 << 0xa) + 1)
EXPECT_EQ(Full.shl(Wrap), Full);
EXPECT_EQ(Empty.shl(Empty), Empty);
@ -1418,6 +1419,21 @@ TEST_F(ConstantRangeTest, Shl) {
Some2.shl(ConstantRange(APInt(16, 0x1))),
ConstantRange(APInt(16, 0xfff << 0x1), APInt(16, 0x7fff << 0x1) + 1));
EXPECT_EQ(One.shl(WrapNullMax), Full);
TestBinaryOpExhaustive(
[](const ConstantRange &CR1, const ConstantRange &CR2) {
return CR1.shl(CR2);
},
[](const APInt &N1, const APInt &N2) -> Optional<APInt> {
if (N2.uge(N2.getBitWidth()))
return None;
return N1.shl(N2);
},
PreferSmallestUnsigned,
[](const ConstantRange &, const ConstantRange &CR2) {
// We currently only produce precise results for single element RHS.
return CR2.isSingleElement();
});
}
TEST_F(ConstantRangeTest, Lshr) {