diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h --- a/llvm/include/llvm/ADT/APInt.h +++ b/llvm/include/llvm/ADT/APInt.h @@ -1491,6 +1491,16 @@ return U.pVal[0]; } + /// Get zero extended value if possible + /// + /// This method attempts to return the value of this APInt as a zero extended + /// uint64_t. The bitwidth must be <= 64 or the value must fit within a + /// uint64_t. Otherwise no value is returned. + std::optional tryZExtValue() const { + return (getActiveBits() <= 64) ? std::optional(getZExtValue()) + : std::nullopt; + }; + /// Get sign extended value /// /// This method attempts to return the value of this APInt as a sign extended @@ -1503,6 +1513,16 @@ return int64_t(U.pVal[0]); } + /// Get sign extended value if possible + /// + /// This method attempts to return the value of this APInt as a sign extended + /// int64_t. The bitwidth must be <= 64 or the value must fit within an + /// int64_t. Otherwise no value is returned. + std::optional trySExtValue() const { + return (getActiveBits() <= 64) ? std::optional(getSExtValue()) + : std::nullopt; + }; + /// Get bits required for string value. /// /// This method determines how many bits are required to hold the APInt 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 @@ -91,6 +91,11 @@ return isSigned() ? getSExtValue() : getZExtValue(); } + std::optional tryExtValue() const { + return getMinSignedBits() <= 64 ? std::optional(getExtValue()) + : std::nullopt; + } + APSInt trunc(uint32_t width) const { return APSInt(APInt::trunc(width), IsUnsigned); } diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp --- a/llvm/unittests/ADT/APIntTest.cpp +++ b/llvm/unittests/ADT/APIntTest.cpp @@ -3133,4 +3133,25 @@ Map.find(ZeroWidthInt); } +TEST(APIntTest, TryExt) { + APInt small(32, 42); + APInt large(128, {0xffff, 0xffff}); + ASSERT_TRUE(small.tryZExtValue().has_value()); + ASSERT_TRUE(small.trySExtValue().has_value()); + ASSERT_FALSE(large.tryZExtValue().has_value()); + ASSERT_FALSE(large.trySExtValue().has_value()); + ASSERT_EQ(small.trySExtValue().value_or(41), 42); + ASSERT_EQ(large.trySExtValue().value_or(41), 41); + + APInt negOne32(32, 0); + negOne32.setAllBits(); + ASSERT_EQ(negOne32.trySExtValue().value_or(42), -1); + APInt negOne64(64, 0); + negOne64.setAllBits(); + ASSERT_EQ(negOne64.trySExtValue().value_or(42), -1); + APInt negOne128(128, 0); + negOne128.setAllBits(); + ASSERT_EQ(negOne128.trySExtValue().value_or(42), 42); +} + } // end anonymous namespace 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 @@ -77,6 +77,23 @@ EXPECT_EQ(-7, APSInt(APInt(4, -7), false).getExtValue()); } +TEST(APSIntTest, tryExtValue) { + EXPECT_EQ(7, APSInt(APInt(3, 7), true).tryExtValue().value_or(42)); + EXPECT_EQ(-1, APSInt(APInt(3, 7), false).tryExtValue().value_or(42)); + EXPECT_EQ(7, APSInt(APInt(4, 7), true).tryExtValue().value_or(42)); + EXPECT_EQ(7, APSInt(APInt(4, 7), false).tryExtValue().value_or(42)); + EXPECT_EQ(7, APSInt(APInt(65, 7), false).tryExtValue().value_or(42)); + APInt negOne64(64, 0); + negOne64.setAllBits(); + EXPECT_EQ(-1, APSInt(negOne64, false).tryExtValue().value_or(42)); + APInt negOne128(128, 0); + negOne128.setAllBits(); + EXPECT_EQ(-1, APSInt(negOne128, false).tryExtValue().value_or(42)); + // APInt posMax128(128, 0); + // posMax128.setAllBits(); + // EXPECT_EQ(42, APSInt(posMax128, true).tryExtValue().value_or(42)); +} + TEST(APSIntTest, compareValues) { auto U = [](uint64_t V) { return APSInt::getUnsigned(V); }; auto S = [](int64_t V) { return APSInt::get(V); };