[libc-commits] [libc] 360b41c - [libc] Fix undefined behavior in UInt<>::shift_right.

Tue Ly via libc-commits libc-commits at lists.llvm.org
Wed Dec 7 15:38:18 PST 2022


Author: Tue Ly
Date: 2022-12-07T18:38:08-05:00
New Revision: 360b41c7ba7f09e375e27b674ba44e96f3d1f055

URL: https://github.com/llvm/llvm-project/commit/360b41c7ba7f09e375e27b674ba44e96f3d1f055
DIFF: https://github.com/llvm/llvm-project/commit/360b41c7ba7f09e375e27b674ba44e96f3d1f055.diff

LOG: [libc] Fix undefined behavior in UInt<>::shift_right.

Fix undefined behavior of left-shifting uint64_t by 64 in
`UInt<>::shift_right` implementation.

Reviewed By: michaelrj, sivachandra

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

Added: 
    

Modified: 
    libc/src/__support/UInt.h
    libc/test/src/__support/uint_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/UInt.h b/libc/src/__support/UInt.h
index 28bd86a93d160..6068ab6decfd9 100644
--- a/libc/src/__support/UInt.h
+++ b/libc/src/__support/UInt.h
@@ -386,18 +386,39 @@ template <size_t Bits> struct UInt {
   }
 
   constexpr void shift_right(size_t s) {
+#ifdef __SIZEOF_INT128__
+    if constexpr (Bits == 128) {
+      // Use builtin 128 bits if available;
+      if (s >= 128) {
+        val[0] = 0;
+        val[1] = 0;
+        return;
+      }
+      __uint128_t tmp = __uint128_t(val[0]) + (__uint128_t(val[1]) << 64);
+      tmp >>= s;
+      val[0] = uint64_t(tmp);
+      val[1] = uint64_t(tmp >> 64);
+      return;
+    }
+#endif // __SIZEOF_INT128__
+
     const size_t drop = s / 64;  // Number of words to drop
     const size_t shift = s % 64; // Bit shift in the remaining words.
 
     size_t i = 0;
 
     if (drop < WordCount) {
-      size_t j = drop;
-      for (; j < WordCount - 1; ++i, ++j) {
-        val[i] = (val[j] >> shift) | (val[j + 1] << (64 - shift));
+      if (shift > 0) {
+        for (size_t j = drop; j < WordCount - 1; ++i, ++j) {
+          val[i] = (val[j] >> shift) | (val[j + 1] << (64 - shift));
+        }
+        val[i] = val[WordCount - 1] >> shift;
+        ++i;
+      } else {
+        for (size_t j = drop; j < WordCount; ++i, ++j) {
+          val[i] = val[j];
+        }
       }
-      val[i] = val[j] >> shift;
-      ++i;
     }
 
     for (; i < WordCount; ++i) {

diff  --git a/libc/test/src/__support/uint_test.cpp b/libc/test/src/__support/uint_test.cpp
index 2da633ecb267b..3ee20470f2821 100644
--- a/libc/test/src/__support/uint_test.cpp
+++ b/libc/test/src/__support/uint_test.cpp
@@ -352,6 +352,17 @@ TEST(LlvmLibcUIntClassTest, ShiftRightTests) {
   LL_UInt128 result6({0, 0});
   EXPECT_EQ((val2 >> 128), result6);
   EXPECT_EQ((val2 >> 256), result6);
+
+  LL_UInt128 v1({0x1111222233334444, 0xaaaabbbbccccdddd});
+  LL_UInt128 r1({0xaaaabbbbccccdddd, 0});
+  EXPECT_EQ((v1 >> 64), r1);
+
+  LL_UInt192 v2({0x1111222233334444, 0x5555666677778888, 0xaaaabbbbccccdddd});
+  LL_UInt192 r2({0x5555666677778888, 0xaaaabbbbccccdddd, 0});
+  LL_UInt192 r3({0xaaaabbbbccccdddd, 0, 0});
+  EXPECT_EQ((v2 >> 64), r2);
+  EXPECT_EQ((v2 >> 128), r3);
+  EXPECT_EQ((r2 >> 64), r3);
 }
 
 TEST(LlvmLibcUIntClassTest, AndTests) {
@@ -502,11 +513,8 @@ TEST(LlvmLibcUIntClassTest, FullMulTests) {
   } while (0)
 
 TEST(LlvmLibcUIntClassTest, QuickMulHiTests) {
-  // TODO(lntue): Investigate / Analyze the error bounds for other rounding
-  // modes.  It the error bounds seems to be able to reach to WordCount instead
-  // of WordCount - 1 in the CI environment.
-  TEST_QUICK_MUL_HI(128, 2);
-  TEST_QUICK_MUL_HI(192, 3);
-  TEST_QUICK_MUL_HI(256, 4);
-  TEST_QUICK_MUL_HI(512, 8);
+  TEST_QUICK_MUL_HI(128, 1);
+  TEST_QUICK_MUL_HI(192, 2);
+  TEST_QUICK_MUL_HI(256, 3);
+  TEST_QUICK_MUL_HI(512, 7);
 }


        


More information about the libc-commits mailing list