[llvm] 169ae6d - [APInt] Allow extending and truncating to the same width

Jay Foad via llvm-commits llvm-commits at lists.llvm.org
Sat May 14 02:03:49 PDT 2022


Author: Jay Foad
Date: 2022-05-14T09:54:24+01:00
New Revision: 169ae6db69882605a69e184237640f0c557243ee

URL: https://github.com/llvm/llvm-project/commit/169ae6db69882605a69e184237640f0c557243ee
DIFF: https://github.com/llvm/llvm-project/commit/169ae6db69882605a69e184237640f0c557243ee.diff

LOG: [APInt] Allow extending and truncating to the same width

Allow zext, sext, trunc, truncUSat and truncSSat to extend or truncate
to the same bit width, which is a no-op.

Disallowing this forced clients to use workarounds like using
zextOrTrunc (even though they never wanted truncation) or zextOrSelf
(even though they did not want its strange behaviour of allowing a
*smaller* bit width, which is also treated as a no-op).

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

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index c364679aa457a..3c75417872f5b 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -1218,7 +1218,7 @@ class LLVM_NODISCARD APInt {
   /// Truncate to new width.
   ///
   /// Truncate the APInt to a specified width. It is an error to specify a width
-  /// that is greater than or equal to the current width.
+  /// that is greater than the current width.
   APInt trunc(unsigned width) const;
 
   /// Truncate to new width with unsigned saturation.
@@ -1238,7 +1238,7 @@ class LLVM_NODISCARD APInt {
   ///
   /// This operation sign extends the APInt to a new width. If the high order
   /// bit is set, the fill on the left will be done with 1 bits, otherwise zero.
-  /// It is an error to specify a width that is less than or equal to the
+  /// It is an error to specify a width that is less than the
   /// current width.
   APInt sext(unsigned width) const;
 
@@ -1246,7 +1246,7 @@ class LLVM_NODISCARD APInt {
   ///
   /// This operation zero extends the APInt to a new width. The high order bits
   /// are filled with 0 bits.  It is an error to specify a width that is less
-  /// than or equal to the current width.
+  /// than the current width.
   APInt zext(unsigned width) const;
 
   /// Sign extend or truncate to width

diff  --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 401b4f7a76206..3fc0415790ec7 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -896,11 +896,14 @@ double APInt::roundToDouble(bool isSigned) const {
 
 // Truncate to new width.
 APInt APInt::trunc(unsigned width) const {
-  assert(width < BitWidth && "Invalid APInt Truncate request");
+  assert(width <= BitWidth && "Invalid APInt Truncate request");
 
   if (width <= APINT_BITS_PER_WORD)
     return APInt(width, getRawData()[0]);
 
+  if (width == BitWidth)
+    return *this;
+
   APInt Result(getMemory(getNumWords(width)), width);
 
   // Copy full words.
@@ -918,7 +921,7 @@ APInt APInt::trunc(unsigned width) const {
 
 // Truncate to new width with unsigned saturation.
 APInt APInt::truncUSat(unsigned width) const {
-  assert(width < BitWidth && "Invalid APInt Truncate request");
+  assert(width <= BitWidth && "Invalid APInt Truncate request");
 
   // Can we just losslessly truncate it?
   if (isIntN(width))
@@ -929,7 +932,7 @@ APInt APInt::truncUSat(unsigned width) const {
 
 // Truncate to new width with signed saturation.
 APInt APInt::truncSSat(unsigned width) const {
-  assert(width < BitWidth && "Invalid APInt Truncate request");
+  assert(width <= BitWidth && "Invalid APInt Truncate request");
 
   // Can we just losslessly truncate it?
   if (isSignedIntN(width))
@@ -941,11 +944,14 @@ APInt APInt::truncSSat(unsigned width) const {
 
 // Sign extend to a new width.
 APInt APInt::sext(unsigned Width) const {
-  assert(Width > BitWidth && "Invalid APInt SignExtend request");
+  assert(Width >= BitWidth && "Invalid APInt SignExtend request");
 
   if (Width <= APINT_BITS_PER_WORD)
     return APInt(Width, SignExtend64(U.VAL, BitWidth));
 
+  if (Width == BitWidth)
+    return *this;
+
   APInt Result(getMemory(getNumWords(Width)), Width);
 
   // Copy words.
@@ -965,11 +971,14 @@ APInt APInt::sext(unsigned Width) const {
 
 //  Zero extend to a new width.
 APInt APInt::zext(unsigned width) const {
-  assert(width > BitWidth && "Invalid APInt ZeroExtend request");
+  assert(width >= BitWidth && "Invalid APInt ZeroExtend request");
 
   if (width <= APINT_BITS_PER_WORD)
     return APInt(width, U.VAL);
 
+  if (width == BitWidth)
+    return *this;
+
   APInt Result(getMemory(getNumWords(width)), width);
 
   // Copy words.

diff  --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index ec3d5f82337f2..aca4a9ade8ff6 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -1181,18 +1181,22 @@ TEST(APIntTest, SaturatingMath) {
   APInt AP_100 = APInt(8, 100);
   APInt AP_200 = APInt(8, 200);
 
+  EXPECT_EQ(APInt(8, 100), AP_100.truncUSat(8));
   EXPECT_EQ(APInt(7, 100), AP_100.truncUSat(7));
   EXPECT_EQ(APInt(6, 63), AP_100.truncUSat(6));
   EXPECT_EQ(APInt(5, 31), AP_100.truncUSat(5));
 
+  EXPECT_EQ(APInt(8, 200), AP_200.truncUSat(8));
   EXPECT_EQ(APInt(7, 127), AP_200.truncUSat(7));
   EXPECT_EQ(APInt(6, 63), AP_200.truncUSat(6));
   EXPECT_EQ(APInt(5, 31), AP_200.truncUSat(5));
 
+  EXPECT_EQ(APInt(8, 42), AP_42.truncSSat(8));
   EXPECT_EQ(APInt(7, 42), AP_42.truncSSat(7));
   EXPECT_EQ(APInt(6, 31), AP_42.truncSSat(6));
   EXPECT_EQ(APInt(5, 15), AP_42.truncSSat(5));
 
+  EXPECT_EQ(APInt(8, -56), AP_200.truncSSat(8));
   EXPECT_EQ(APInt(7, -56), AP_200.truncSSat(7));
   EXPECT_EQ(APInt(6, -32), AP_200.truncSSat(6));
   EXPECT_EQ(APInt(5, -16), AP_200.truncSSat(5));
@@ -2637,23 +2641,28 @@ TEST(APIntTest, sext) {
   EXPECT_EQ(~uint64_t(0), APInt(1, 1).sext(64));
 
   APInt i32_max(APInt::getSignedMaxValue(32).sext(63));
+  EXPECT_EQ(i32_max, i32_max.sext(63));
   EXPECT_EQ(32U, i32_max.countLeadingZeros());
   EXPECT_EQ(0U, i32_max.countTrailingZeros());
   EXPECT_EQ(31U, i32_max.countPopulation());
 
   APInt i32_min(APInt::getSignedMinValue(32).sext(63));
+  EXPECT_EQ(i32_min, i32_min.sext(63));
   EXPECT_EQ(32U, i32_min.countLeadingOnes());
   EXPECT_EQ(31U, i32_min.countTrailingZeros());
   EXPECT_EQ(32U, i32_min.countPopulation());
 
   APInt i32_neg1(APInt(32, ~uint64_t(0)).sext(63));
+  EXPECT_EQ(i32_neg1, i32_neg1.sext(63));
   EXPECT_EQ(63U, i32_neg1.countLeadingOnes());
   EXPECT_EQ(0U, i32_neg1.countTrailingZeros());
   EXPECT_EQ(63U, i32_neg1.countPopulation());
 }
 
-TEST(APIntTest, truncOrSelf) {
+TEST(APIntTest, trunc) {
   APInt val(32, 0xFFFFFFFF);
+  EXPECT_EQ(0xFFFF, val.trunc(16));
+  EXPECT_EQ(0xFFFFFFFF, val.trunc(32));
   EXPECT_EQ(0xFFFF, val.truncOrSelf(16));
   EXPECT_EQ(0xFFFFFFFF, val.truncOrSelf(32));
   EXPECT_EQ(0xFFFFFFFF, val.truncOrSelf(64));


        


More information about the llvm-commits mailing list