[llvm] 5596810 - [APInt] provide a safe API for zext value and sext value.

Peter Rong via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 15 10:06:32 PST 2022


Author: Peter Rong
Date: 2022-12-15T10:06:26-08:00
New Revision: 55968109d1f9c8655d30928b9fde9993e341c97f

URL: https://github.com/llvm/llvm-project/commit/55968109d1f9c8655d30928b9fde9993e341c97f
DIFF: https://github.com/llvm/llvm-project/commit/55968109d1f9c8655d30928b9fde9993e341c97f.diff

LOG: [APInt] provide a safe API for zext value and sext value.

Currently, APInt::getSExtValue and getZExtValue crashes on values with more than 64 bits.
Users may accidently crash the compiler with this setting when the integer may be i128.
As shown in https://github.com/llvm/llvm-project/issues/59316

In this patch we provide a trySExtValue and tryZExtValue to return an Optional, the user
needs to explictly unwrap it and condsier the possibility where there my no value in it.

Reviewed By: RKSimon

Differential Revision: https://reviews.llvm.org/D139683

Added: 
    

Modified: 
    llvm/include/llvm/ADT/APInt.h
    llvm/unittests/ADT/APIntTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index 15e696ef91935..33b38653f6da7 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1490,6 +1490,16 @@ class [[nodiscard]] APInt {
     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<uint64_t> tryZExtValue() const {
+    return (getActiveBits() <= 64) ? std::optional<uint64_t>(getZExtValue())
+                                   : std::nullopt;
+  };
+
   /// Get sign extended value
   ///
   /// This method attempts to return the value of this APInt as a sign extended
@@ -1502,6 +1512,16 @@ class [[nodiscard]] APInt {
     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<int64_t> trySExtValue() const {
+    return (getSignificantBits() <= 64) ? std::optional<int64_t>(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/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index 3055581c7dd30..09c9c8ddcf3c9 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -3134,4 +3134,25 @@ TEST(APIntTest, DenseMap) {
   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


        


More information about the llvm-commits mailing list