[llvm] 587493b - [ConstantRange] Compute precise shl range for single elements
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 15 14:44:55 PDT 2021
Author: Nikita Popov
Date: 2021-10-15T23:44:41+02:00
New Revision: 587493b441ea87f132fec680933d3628050756b8
URL: https://github.com/llvm/llvm-project/commit/587493b441ea87f132fec680933d3628050756b8
DIFF: https://github.com/llvm/llvm-project/commit/587493b441ea87f132fec680933d3628050756b8.diff
LOG: [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.
Added:
Modified:
llvm/lib/IR/ConstantRange.cpp
llvm/unittests/IR/ConstantRangeTest.cpp
Removed:
################################################################################
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 530a3789527e..d8b4262a8114 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -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
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index d220b70daf71..bc78869f9c54 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -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) {
More information about the llvm-commits
mailing list