forked from OSchip/llvm-project
[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:
parent
f92db6d3ff
commit
587493b441
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in New Issue