Index: llvm/trunk/include/llvm/IR/ConstantRange.h =================================================================== --- llvm/trunk/include/llvm/IR/ConstantRange.h +++ llvm/trunk/include/llvm/IR/ConstantRange.h @@ -219,9 +219,15 @@ /// 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; Index: llvm/trunk/lib/IR/ConstantRange.cpp =================================================================== --- llvm/trunk/lib/IR/ConstantRange.cpp +++ llvm/trunk/lib/IR/ConstantRange.cpp @@ -389,6 +389,21 @@ 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()); Index: llvm/trunk/unittests/IR/ConstantRangeTest.cpp =================================================================== --- llvm/trunk/unittests/IR/ConstantRangeTest.cpp +++ llvm/trunk/unittests/IR/ConstantRangeTest.cpp @@ -26,29 +26,39 @@ }; 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, 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