diff --git a/llvm/include/llvm/ADT/APSInt.h b/llvm/include/llvm/ADT/APSInt.h --- a/llvm/include/llvm/ADT/APSInt.h +++ b/llvm/include/llvm/ADT/APSInt.h @@ -29,10 +29,10 @@ /// Create an APSInt with the specified width, default to unsigned. explicit APSInt(uint32_t BitWidth, bool isUnsigned = true) - : APInt(BitWidth, 0), IsUnsigned(isUnsigned) {} + : APInt(BitWidth, 0), IsUnsigned(isUnsigned) {} explicit APSInt(APInt I, bool isUnsigned = true) - : APInt(std::move(I)), IsUnsigned(isUnsigned) {} + : APInt(std::move(I)), IsUnsigned(isUnsigned) {} /// Construct an APSInt from a string representation. /// @@ -85,12 +85,27 @@ } using APInt::toString; + /// If this int is representable using an int64_t. + bool isRepresentableByInt64() const { + // For unsigned values with 64 active bits, they technically fit into a + // int64_t, but the user may get negative numbers and has to manually cast + // them to unsigned. Let's not bet the user has the sanity to do that and + // not give them a vague value at the first place. + return (isSigned() && getMinSignedBits() <= 64) || + (!isSigned() && getActiveBits() <= 63); + } + /// Get the correctly-extended \c int64_t value. int64_t getExtValue() const { - assert(getMinSignedBits() <= 64 && "Too many bits for int64_t"); + assert(isRepresentableByInt64() && "Too many bits for int64_t"); return isSigned() ? getSExtValue() : getZExtValue(); } + std::optional tryExtValue() const { + return isRepresentableByInt64() ? std::optional(getExtValue()) + : std::nullopt; + } + APSInt trunc(uint32_t width) const { return APSInt(APInt::trunc(width), IsUnsigned); } @@ -137,7 +152,7 @@ APSInt operator>>(unsigned Amt) const { return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false); } - APSInt& operator>>=(unsigned Amt) { + APSInt &operator>>=(unsigned Amt) { if (IsUnsigned) lshrInPlace(Amt); else @@ -149,29 +164,27 @@ : APSInt(relativeAShr(Amt), false); } - inline bool operator<(const APSInt& RHS) const { + inline bool operator<(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); return IsUnsigned ? ult(RHS) : slt(RHS); } - inline bool operator>(const APSInt& RHS) const { + inline bool operator>(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); return IsUnsigned ? ugt(RHS) : sgt(RHS); } - inline bool operator<=(const APSInt& RHS) const { + inline bool operator<=(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); return IsUnsigned ? ule(RHS) : sle(RHS); } - inline bool operator>=(const APSInt& RHS) const { + inline bool operator>=(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); return IsUnsigned ? uge(RHS) : sge(RHS); } - inline bool operator==(const APSInt& RHS) const { + inline bool operator==(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); return eq(RHS); } - inline bool operator!=(const APSInt& RHS) const { - return !((*this) == RHS); - } + inline bool operator!=(const APSInt &RHS) const { return !((*this) == RHS); } bool operator==(int64_t RHS) const { return compareValues(*this, get(RHS)) == 0; @@ -196,10 +209,10 @@ // signedness information. APSInt operator<<(unsigned Bits) const { - return APSInt(static_cast(*this) << Bits, IsUnsigned); + return APSInt(static_cast(*this) << Bits, IsUnsigned); } - APSInt& operator<<=(unsigned Amt) { - static_cast(*this) <<= Amt; + APSInt &operator<<=(unsigned Amt) { + static_cast(*this) <<= Amt; return *this; } APSInt relativeShl(unsigned Amt) const { @@ -207,97 +220,99 @@ : APSInt(relativeAShl(Amt), false); } - APSInt& operator++() { - ++(static_cast(*this)); + APSInt &operator++() { + ++(static_cast(*this)); return *this; } - APSInt& operator--() { - --(static_cast(*this)); + APSInt &operator--() { + --(static_cast(*this)); return *this; } APSInt operator++(int) { - return APSInt(++static_cast(*this), IsUnsigned); + return APSInt(++static_cast(*this), IsUnsigned); } APSInt operator--(int) { - return APSInt(--static_cast(*this), IsUnsigned); + return APSInt(--static_cast(*this), IsUnsigned); } APSInt operator-() const { - return APSInt(-static_cast(*this), IsUnsigned); + return APSInt(-static_cast(*this), IsUnsigned); } - APSInt& operator+=(const APSInt& RHS) { + APSInt &operator+=(const APSInt &RHS) { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - static_cast(*this) += RHS; + static_cast(*this) += RHS; return *this; } - APSInt& operator-=(const APSInt& RHS) { + APSInt &operator-=(const APSInt &RHS) { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - static_cast(*this) -= RHS; + static_cast(*this) -= RHS; return *this; } - APSInt& operator*=(const APSInt& RHS) { + APSInt &operator*=(const APSInt &RHS) { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - static_cast(*this) *= RHS; + static_cast(*this) *= RHS; return *this; } - APSInt& operator&=(const APSInt& RHS) { + APSInt &operator&=(const APSInt &RHS) { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - static_cast(*this) &= RHS; + static_cast(*this) &= RHS; return *this; } - APSInt& operator|=(const APSInt& RHS) { + APSInt &operator|=(const APSInt &RHS) { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - static_cast(*this) |= RHS; + static_cast(*this) |= RHS; return *this; } - APSInt& operator^=(const APSInt& RHS) { + APSInt &operator^=(const APSInt &RHS) { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - static_cast(*this) ^= RHS; + static_cast(*this) ^= RHS; return *this; } - APSInt operator&(const APSInt& RHS) const { + APSInt operator&(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - return APSInt(static_cast(*this) & RHS, IsUnsigned); + return APSInt(static_cast(*this) & RHS, IsUnsigned); } - APSInt operator|(const APSInt& RHS) const { + APSInt operator|(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - return APSInt(static_cast(*this) | RHS, IsUnsigned); + return APSInt(static_cast(*this) | RHS, IsUnsigned); } APSInt operator^(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - return APSInt(static_cast(*this) ^ RHS, IsUnsigned); + return APSInt(static_cast(*this) ^ RHS, IsUnsigned); } - APSInt operator*(const APSInt& RHS) const { + APSInt operator*(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - return APSInt(static_cast(*this) * RHS, IsUnsigned); + return APSInt(static_cast(*this) * RHS, IsUnsigned); } - APSInt operator+(const APSInt& RHS) const { + APSInt operator+(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - return APSInt(static_cast(*this) + RHS, IsUnsigned); + return APSInt(static_cast(*this) + RHS, IsUnsigned); } - APSInt operator-(const APSInt& RHS) const { + APSInt operator-(const APSInt &RHS) const { assert(IsUnsigned == RHS.IsUnsigned && "Signedness mismatch!"); - return APSInt(static_cast(*this) - RHS, IsUnsigned); + return APSInt(static_cast(*this) - RHS, IsUnsigned); } APSInt operator~() const { - return APSInt(~static_cast(*this), IsUnsigned); + return APSInt(~static_cast(*this), IsUnsigned); } /// Return the APSInt representing the maximum integer value with the given /// bit width and signedness. static APSInt getMaxValue(uint32_t numBits, bool Unsigned) { return APSInt(Unsigned ? APInt::getMaxValue(numBits) - : APInt::getSignedMaxValue(numBits), Unsigned); + : APInt::getSignedMaxValue(numBits), + Unsigned); } /// Return the APSInt representing the minimum integer value with the given /// bit width and signedness. static APSInt getMinValue(uint32_t numBits, bool Unsigned) { return APSInt(Unsigned ? APInt::getMinValue(numBits) - : APInt::getSignedMinValue(numBits), Unsigned); + : APInt::getSignedMinValue(numBits), + Unsigned); } /// Determine if two APSInts have the same value, zero- or @@ -337,7 +352,7 @@ /// Used to insert APSInt objects, or objects that contain APSInt objects, /// into FoldingSets. - void Profile(FoldingSetNodeID& ID) const; + void Profile(FoldingSetNodeID &ID) const; }; inline bool operator==(int64_t V1, const APSInt &V2) { return V2 == V1; } diff --git a/llvm/unittests/ADT/APSIntTest.cpp b/llvm/unittests/ADT/APSIntTest.cpp --- a/llvm/unittests/ADT/APSIntTest.cpp +++ b/llvm/unittests/ADT/APSIntTest.cpp @@ -62,6 +62,13 @@ EXPECT_EQ(UINT64_C(0) - 7, APSInt::getUnsigned(-7).getZExtValue()); } +TEST(APSIntTest, isRepresentableByInt64) { + ASSERT_TRUE(APSInt(APInt(3, 7), true).isRepresentableByInt64()); + ASSERT_TRUE(APSInt(APInt(128, 7), true).isRepresentableByInt64()); + ASSERT_TRUE(APSInt(APInt(128, 7), false).isRepresentableByInt64()); + ASSERT_TRUE(APSInt(APInt(64, -1), false).isRepresentableByInt64()); + ASSERT_FALSE(APSInt(APInt(64, (uint64_t)-1), true).isRepresentableByInt64()); +} TEST(APSIntTest, getExtValue) { EXPECT_TRUE(APSInt(APInt(3, 7), true).isUnsigned()); EXPECT_TRUE(APSInt(APInt(3, 7), false).isSigned()); @@ -76,6 +83,12 @@ EXPECT_EQ(9, APSInt(APInt(4, -7), true).getExtValue()); EXPECT_EQ(-7, APSInt(APInt(4, -7), false).getExtValue()); } +TEST(APSIntTest, tryExtValue) { + ASSERT_EQ(-7, APSInt(APInt(64, -7), false).tryExtValue().value_or(42)); + ASSERT_EQ(42, APSInt(APInt(128, -7), false).tryExtValue().value_or(42)); + ASSERT_EQ(42, APSInt(APInt(64, -7), true).tryExtValue().value_or(42)); + ASSERT_EQ(1, APSInt(APInt(128, 1), true).tryExtValue().value_or(42)); +} TEST(APSIntTest, compareValues) { auto U = [](uint64_t V) { return APSInt::getUnsigned(V); };