From bad648a23e15829a7210cd194e3d3f3ea13a91f8 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 7 Apr 2019 17:52:40 +0000 Subject: [PATCH] [ConstantRange] Add isAllNegative() and isAllNonNegative() methods Add isAllNegative() and isAllNonNegative() methods to ConstantRange, which determine whether all values in the constant range are negative/non-negative. This is useful for replacing KnownBits isNegative() and isNonNegative() calls when changing code to use constant ranges. Differential Revision: https://reviews.llvm.org/D60264 llvm-svn: 357871 --- llvm/include/llvm/IR/ConstantRange.h | 8 ++- llvm/lib/IR/ConstantRange.cpp | 15 ++++++ llvm/unittests/IR/ConstantRangeTest.cpp | 67 +++++++++++++++++++------ 3 files changed, 74 insertions(+), 16 deletions(-) diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h index be5e297bf7109..71b55ccd346f1 100644 --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -219,9 +219,15 @@ class LLVM_NODISCARD ConstantRange { /// Compare set size of this range with the range CR. bool isSizeStrictlySmallerThan(const ConstantRange &CR) const; - // Compare set size of this range with Value. + /// Compare set size of this range with Value. bool isSizeLargerThan(uint64_t MaxSize) const; + /// Return true if all values in this range are negative. + bool isAllNegative() const; + + /// Return true if all values in this range are non-negative. + bool isAllNonNegative() const; + /// Return the largest unsigned value contained in the ConstantRange. APInt getUnsignedMax() const; diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp index f07ec9d5a3f16..d048b8c2ed51b 100644 --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -389,6 +389,21 @@ ConstantRange::isSizeLargerThan(uint64_t MaxSize) const { return (Upper - Lower).ugt(MaxSize); } +bool ConstantRange::isAllNegative() const { + // Empty set is all negative, full set is not. + if (isEmptySet()) + return true; + if (isFullSet()) + return false; + + return !isUpperSignWrapped() && !Upper.isStrictlyPositive(); +} + +bool ConstantRange::isAllNonNegative() const { + // Empty and full set are automatically treated correctly. + return !isSignWrappedSet() && Lower.isNonNegative(); +} + APInt ConstantRange::getUnsignedMax() const { if (isFullSet() || isUpperWrapped()) return APInt::getMaxValue(getBitWidth()); diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp index db298bc0d4e15..be4b4766b5d0d 100644 --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -26,29 +26,39 @@ class ConstantRangeTest : public ::testing::Test { }; template -static void EnumerateTwoConstantRanges(unsigned Bits, Fn TestFn) { +static void EnumerateConstantRanges(unsigned Bits, Fn TestFn) { unsigned Max = 1 << Bits; - for (unsigned Lo1 = 0; Lo1 < Max; Lo1++) { - for (unsigned Hi1 = 0; Hi1 < Max; Hi1++) { + for (unsigned Lo = 0; Lo < Max; Lo++) { + for (unsigned Hi = 0; Hi < Max; Hi++) { // Enforce ConstantRange invariant. - if (Lo1 == Hi1 && Lo1 != 0 && Lo1 != Max - 1) + if (Lo == Hi && Lo != 0 && Lo != Max - 1) continue; - ConstantRange CR1(APInt(Bits, Lo1), APInt(Bits, Hi1)); - for (unsigned Lo2 = 0; Lo2 < Max; Lo2++) { - for (unsigned Hi2 = 0; Hi2 < Max; Hi2++) { - // Enforce ConstantRange invariant. - if (Lo2 == Hi2 && Lo2 != 0 && Lo2 != Max - 1) - continue; - - ConstantRange CR2(APInt(Bits, Lo2), APInt(Bits, Hi2)); - TestFn(CR1, CR2); - } - } + ConstantRange CR(APInt(Bits, Lo), APInt(Bits, Hi)); + TestFn(CR); } } } +template +static void EnumerateTwoConstantRanges(unsigned Bits, Fn TestFn) { + EnumerateConstantRanges(Bits, [&](const ConstantRange &CR1) { + EnumerateConstantRanges(Bits, [&](const ConstantRange &CR2) { + TestFn(CR1, CR2); + }); + }); +} + +template +static void ForeachNumInConstantRange(const ConstantRange &CR, Fn TestFn) { + // The loop is based on the set size to correctly handle empty/full ranges. + unsigned Size = CR.getSetSize().getLimitedValue(); + APInt N = CR.getLower(); + for (unsigned I = 0; I < Size; ++I, ++N) { + TestFn(N); + } +} + ConstantRange ConstantRangeTest::Full(16, true); ConstantRange ConstantRangeTest::Empty(16, false); ConstantRange ConstantRangeTest::One(APInt(16, 0xa)); @@ -1597,4 +1607,31 @@ TEST_F(ConstantRangeTest, FromKnownBitsExhaustive) { } } +TEST_F(ConstantRangeTest, Negative) { + // All elements in an empty set (of which there are none) are both negative + // and non-negative. Empty & full sets checked explicitly for clarity, but + // they are also covered by the exhaustive test below. + EXPECT_TRUE(Empty.isAllNegative()); + EXPECT_TRUE(Empty.isAllNonNegative()); + EXPECT_FALSE(Full.isAllNegative()); + EXPECT_FALSE(Full.isAllNonNegative()); + + unsigned Bits = 4; + EnumerateConstantRanges(Bits, [](const ConstantRange &CR) { + bool AllNegative = true; + bool AllNonNegative = true; + ForeachNumInConstantRange(CR, [&](const APInt &N) { + if (!N.isNegative()) + AllNegative = false; + if (!N.isNonNegative()) + AllNonNegative = false; + }); + assert((CR.isEmptySet() || !AllNegative || !AllNonNegative) && + "Only empty set can be both all negative and all non-negative"); + + EXPECT_EQ(AllNegative, CR.isAllNegative()); + EXPECT_EQ(AllNonNegative, CR.isAllNonNegative()); + }); +} + } // anonymous namespace