Skip to content

Commit 587493b

Browse files
committed
[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.
1 parent f92db6d commit 587493b

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

llvm/lib/IR/ConstantRange.cpp

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,24 +1346,33 @@ ConstantRange::shl(const ConstantRange &Other) const {
13461346
if (isEmptySet() || Other.isEmptySet())
13471347
return getEmpty();
13481348

1349-
APInt max = getUnsignedMax();
1350-
APInt Other_umax = Other.getUnsignedMax();
1349+
APInt Min = getUnsignedMin();
1350+
APInt Max = getUnsignedMax();
1351+
if (const APInt *RHS = Other.getSingleElement()) {
1352+
unsigned BW = getBitWidth();
1353+
if (RHS->uge(BW))
1354+
return getEmpty();
13511355

1352-
// If we are shifting by maximum amount of
1353-
// zero return return the original range.
1354-
if (Other_umax.isZero())
1355-
return *this;
1356-
// there's overflow!
1357-
if (Other_umax.ugt(max.countLeadingZeros()))
1356+
unsigned EqualLeadingBits = (Min ^ Max).countLeadingZeros();
1357+
if (RHS->ule(EqualLeadingBits))
1358+
return getNonEmpty(Min << *RHS, (Max << *RHS) + 1);
1359+
1360+
return getNonEmpty(APInt::getZero(BW),
1361+
APInt::getBitsSetFrom(BW, RHS->getZExtValue()) + 1);
1362+
}
1363+
1364+
APInt OtherMax = Other.getUnsignedMax();
1365+
1366+
// There's overflow!
1367+
if (OtherMax.ugt(Max.countLeadingZeros()))
13581368
return getFull();
13591369

13601370
// FIXME: implement the other tricky cases
13611371

1362-
APInt min = getUnsignedMin();
1363-
min <<= Other.getUnsignedMin();
1364-
max <<= Other_umax;
1372+
Min <<= Other.getUnsignedMin();
1373+
Max <<= OtherMax;
13651374

1366-
return ConstantRange(std::move(min), std::move(max) + 1);
1375+
return ConstantRange::getNonEmpty(std::move(Min), std::move(Max) + 1);
13671376
}
13681377

13691378
ConstantRange

llvm/unittests/IR/ConstantRangeTest.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1400,7 +1400,8 @@ TEST_F(ConstantRangeTest, Shl) {
14001400
ConstantRange WrapNullMax(APInt(16, 0x1), APInt(16, 0x0));
14011401
EXPECT_EQ(Full.shl(Full), Full);
14021402
EXPECT_EQ(Full.shl(Empty), Empty);
1403-
EXPECT_EQ(Full.shl(One), Full); // TODO: [0, (-1 << 0xa) + 1)
1403+
EXPECT_EQ(Full.shl(One), ConstantRange(APInt(16, 0),
1404+
APInt(16, 0xfc00) + 1));
14041405
EXPECT_EQ(Full.shl(Some), Full); // TODO: [0, (-1 << 0xa) + 1)
14051406
EXPECT_EQ(Full.shl(Wrap), Full);
14061407
EXPECT_EQ(Empty.shl(Empty), Empty);
@@ -1418,6 +1419,21 @@ TEST_F(ConstantRangeTest, Shl) {
14181419
Some2.shl(ConstantRange(APInt(16, 0x1))),
14191420
ConstantRange(APInt(16, 0xfff << 0x1), APInt(16, 0x7fff << 0x1) + 1));
14201421
EXPECT_EQ(One.shl(WrapNullMax), Full);
1422+
1423+
TestBinaryOpExhaustive(
1424+
[](const ConstantRange &CR1, const ConstantRange &CR2) {
1425+
return CR1.shl(CR2);
1426+
},
1427+
[](const APInt &N1, const APInt &N2) -> Optional<APInt> {
1428+
if (N2.uge(N2.getBitWidth()))
1429+
return None;
1430+
return N1.shl(N2);
1431+
},
1432+
PreferSmallestUnsigned,
1433+
[](const ConstantRange &, const ConstantRange &CR2) {
1434+
// We currently only produce precise results for single element RHS.
1435+
return CR2.isSingleElement();
1436+
});
14211437
}
14221438

14231439
TEST_F(ConstantRangeTest, Lshr) {

0 commit comments

Comments
 (0)