Skip to content

Commit

Permalink
[ConstantRange] Add isAllNegative() and isAllNonNegative() methods
Browse files Browse the repository at this point in the history
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
  • Loading branch information
nikic committed Apr 7, 2019
1 parent 3db93ac commit bad648a
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 16 deletions.
8 changes: 7 additions & 1 deletion llvm/include/llvm/IR/ConstantRange.h
Expand Up @@ -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;

Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/IR/ConstantRange.cpp
Expand Up @@ -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());
Expand Down
67 changes: 52 additions & 15 deletions llvm/unittests/IR/ConstantRangeTest.cpp
Expand Up @@ -26,29 +26,39 @@ class ConstantRangeTest : public ::testing::Test {
};

template<typename Fn>
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<typename Fn>
static void EnumerateTwoConstantRanges(unsigned Bits, Fn TestFn) {
EnumerateConstantRanges(Bits, [&](const ConstantRange &CR1) {
EnumerateConstantRanges(Bits, [&](const ConstantRange &CR2) {
TestFn(CR1, CR2);
});
});
}

template<typename Fn>
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));
Expand Down Expand Up @@ -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

0 comments on commit bad648a

Please sign in to comment.