diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -92,6 +92,9 @@ /// unsigned domain. static ConstantRange fromKnownBits(const KnownBits &Known, bool IsSigned); + /// Get a known bits valid for a given range. + static KnownBits toKnownBits(const ConstantRange &Range); + /// Produce the smallest range such that all values that may satisfy the given /// predicate with any value contained within Other is contained in the /// returned range. Formally, this returns a superset of diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h --- a/llvm/include/llvm/Support/KnownBits.h +++ b/llvm/include/llvm/Support/KnownBits.h @@ -35,6 +35,12 @@ /// Create a known bits object of BitWidth bits initialized to unknown. KnownBits(unsigned BitWidth) : Zero(BitWidth, 0), One(BitWidth, 0) {} + /// Return true if this KnownBits is equal to another KnownBits. + bool operator==(const KnownBits &CR) const { + return Zero == CR.Zero && One == CR.One; + } + bool operator!=(const KnownBits &KB) const { return !operator==(KB); } + /// Get the bit width of this value. unsigned getBitWidth() const { assert(Zero.getBitWidth() == One.getBitWidth() && @@ -209,8 +215,19 @@ /// Compute known bits resulting from adding LHS and RHS. static KnownBits computeForAddSub(bool Add, bool NSW, const KnownBits &LHS, KnownBits RHS); + + /// Print out the bounds to a stream. + void print(raw_ostream &OS) const; + + /// Allow printing from a debugger easily. + void dump() const; }; +inline raw_ostream &operator<<(raw_ostream &OS, const KnownBits &KB) { + KB.print(OS); + return OS; +} + } // end namespace llvm #endif diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -74,6 +74,30 @@ return ConstantRange(Lower, Upper + 1); } +// The implementation of ConstantRange::toKnownBits() is a verbatim +// backtransform of what is being done in the ConstantRange::fromKnownBits(). +KnownBits ConstantRange::toKnownBits(const ConstantRange &Range) { + KnownBits Known(Range.getBitWidth()); + + if (Range.isFullSet()) + return Known; // No bits known. + + if (Range.isAllNonNegative() || Range.isAllNegative()) { + Known.One = Range.getLower(); + Known.Zero = ~(Range.getUpper() - 1); + return Known; + } + + Known.One = Range.getLower(); + Known.One.clearSignBit(); + + Known.Zero = Range.getUpper() - 1; + Known.Zero.setSignBit(); + Known.Zero = ~Known.Zero; + + return Known; +} + ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &CR) { if (CR.isEmptySet()) diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp --- a/llvm/lib/Support/KnownBits.cpp +++ b/llvm/lib/Support/KnownBits.cpp @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/KnownBits.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -81,3 +83,11 @@ return KnownOut; } + +void KnownBits::print(raw_ostream &OS) const { + OS << "Known-zero: " << Zero << ", Known-one: " << One; +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void KnownBits::dump() const { print(dbgs()); } +#endif diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp --- a/llvm/unittests/IR/ConstantRangeTest.cpp +++ b/llvm/unittests/IR/ConstantRangeTest.cpp @@ -2095,7 +2095,7 @@ EXPECT_EQ(CR2, ConstantRange::fromKnownBits(Known, /*signed*/true)); } -TEST_F(ConstantRangeTest, FromKnownBitsExhaustive) { +TEST_F(ConstantRangeTest, FromToKnownBitsExhaustive) { unsigned Bits = 4; unsigned Max = 1 << Bits; KnownBits Known(Bits); @@ -2121,10 +2121,27 @@ if (Num.sgt(MaxSigned)) MaxSigned = Num; } - ConstantRange UnsignedCR(MinUnsigned, MaxUnsigned + 1); - ConstantRange SignedCR(MinSigned, MaxSigned + 1); - EXPECT_EQ(UnsignedCR, ConstantRange::fromKnownBits(Known, false)); - EXPECT_EQ(SignedCR, ConstantRange::fromKnownBits(Known, true)); + ConstantRange ReferenceUnsignedCR(MinUnsigned, MaxUnsigned + 1); + ConstantRange ReferenceSignedCR(MinSigned, MaxSigned + 1); + + ConstantRange UnsignedCRFromKB( + ConstantRange::fromKnownBits(Known, false)); + ConstantRange SignedCRFromKB(ConstantRange::fromKnownBits(Known, true)); + + // Conversion from reference known bits to constant range is precisely + // identical to reference constant range. + EXPECT_EQ(ReferenceUnsignedCR, UnsignedCRFromKB); + EXPECT_EQ(ReferenceSignedCR, SignedCRFromKB); + + KnownBits KBFromReferenceUnsignedCR( + ConstantRange::toKnownBits(ReferenceUnsignedCR)); + KnownBits KBFromReferenceSignedCR( + ConstantRange::toKnownBits(ReferenceSignedCR)); + + // Conversion from reference constant range is precisely + // identical to reference known bits. + EXPECT_EQ(KBFromReferenceUnsignedCR, KBFromReferenceSignedCR); + EXPECT_EQ(KBFromReferenceUnsignedCR, Known); } } }