From 587493b441ea87f132fec680933d3628050756b8 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 15 Oct 2021 21:25:39 +0200 Subject: [PATCH] [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. --- llvm/lib/IR/ConstantRange.cpp | 33 +++++++++++++++++++++------------ llvm/unittests/IR/ConstantRangeTest.cpp | 18 +++++++++++++++++- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index 530a378..d8b4262 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 d220b70..bc78869 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 { + 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) { -- 2.7.4