[libc-commits] [libc] bc10a41 - [libc][math] Improve the performance and error printing of UInt.

Tue Ly via libc-commits libc-commits at lists.llvm.org
Tue Nov 15 11:18:28 PST 2022


Author: Tue Ly
Date: 2022-11-15T14:17:59-05:00
New Revision: bc10a4108055eb169b8026b8d9bf618025bbedb8

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

LOG: [libc][math] Improve the performance and error printing of UInt.

Use add_with_carry builtin to improve the performance of
addition and multiplication of UInt class.  For 128-bit, it is as
fast as using __uint128_t.

Microbenchmark for addition:
https://quick-bench.com/q/-5a6xM4T8rIXBhqMTtLE-DD2h8w

Microbenchmark for multiplication:
https://quick-bench.com/q/P2muLAzJ_W-VqWCuxEJ0CU0bLDg

Microbenchmark for shift right:
https://quick-bench.com/q/N-jkKXaVsGQ4AAv3k8VpsVkua5Y

Microbenchmark for shift left:
https://quick-bench.com/q/5-RzwF8UdslC-zuhNajXtXdzLRM

Reviewed By: sivachandra

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

Added: 
    libc/src/__support/integer_utils.h
    libc/src/__support/number_pair.h

Modified: 
    libc/src/__support/CMakeLists.txt
    libc/src/__support/UInt.h
    libc/test/src/__support/uint128_test.cpp
    libc/utils/UnitTest/LibcTest.cpp
    utils/bazel/llvm-project-overlay/libc/BUILD.bazel

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index 92a13d51a591c..75575cdfef90f 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -106,12 +106,34 @@ add_header_library(
     libc.src.__support.CPP.array
 )
 
+add_header_library(
+  number_pair
+  HDRS
+    number_pair.h
+  DEPENDS
+    libc.src.__support.CPP.type_traits
+)
+
+add_header_library(
+  integer_utils
+  HDRS
+    integer_utils.h
+  DEPENDS
+    .builtin_wrappers
+    .number_pair
+    libc.src.__support.CPP.type_traits
+)
+
 add_header_library(
   uint
   HDRS
     UInt.h
   DEPENDS
+    .builtin_wrappers
+    .number_pair
+    .integer_utils
     libc.src.__support.CPP.array
+    libc.src.__support.CPP.type_traits
 )
 
 add_header_library(

diff  --git a/libc/src/__support/UInt.h b/libc/src/__support/UInt.h
index ecaa696a1aabf..06f28f90b66ee 100644
--- a/libc/src/__support/UInt.h
+++ b/libc/src/__support/UInt.h
@@ -6,21 +6,23 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_LIBC_UTILS_UINT_H
-#define LLVM_LIBC_UTILS_UINT_H
+#ifndef LLVM_LIBC_SRC_SUPPORT_UINT_H
+#define LLVM_LIBC_SRC_SUPPORT_UINT_H
 
 #include "src/__support/CPP/array.h"
 #include "src/__support/CPP/limits.h"
 #include "src/__support/CPP/optional.h"
 #include "src/__support/CPP/type_traits.h"
 #include "src/__support/builtin_wrappers.h"
+#include "src/__support/integer_utils.h"
+#include "src/__support/number_pair.h"
 
 #include <stddef.h> // For size_t
 #include <stdint.h>
 
 namespace __llvm_libc::cpp {
 
-template <size_t Bits> class UInt {
+template <size_t Bits> struct UInt {
 
   static_assert(Bits > 0 && Bits % 64 == 0,
                 "Number of bits in UInt should be a multiple of 64.");
@@ -32,7 +34,6 @@ template <size_t Bits> class UInt {
   static constexpr uint64_t low(uint64_t v) { return v & MASK32; }
   static constexpr uint64_t high(uint64_t v) { return (v >> 32) & MASK32; }
 
-public:
   constexpr UInt() {}
 
   constexpr UInt(const UInt<Bits> &other) {
@@ -100,37 +101,28 @@ template <size_t Bits> class UInt {
   // property of unsigned integers:
   //   x + (~x) = 2^(sizeof(x)) - 1.
   constexpr uint64_t add(const UInt<Bits> &x) {
-    bool carry = false;
+    uint64_t carry_in = 0;
+    uint64_t carry_out = 0;
     for (size_t i = 0; i < WordCount; ++i) {
-      uint64_t complement = ~x.val[i];
-      if (!carry) {
-        if (val[i] <= complement)
-          val[i] += x.val[i];
-        else {
-          val[i] -= complement + 1;
-          carry = true;
-        }
-      } else {
-        if (val[i] < complement) {
-          val[i] += x.val[i] + 1;
-          carry = false;
-        } else
-          val[i] -= complement;
-      }
+      val[i] = add_with_carry(val[i], x.val[i], carry_in, carry_out);
+      carry_in = carry_out;
     }
-    return carry ? 1 : 0;
+    return carry_out;
   }
 
   constexpr UInt<Bits> operator+(const UInt<Bits> &other) const {
-    UInt<Bits> result(*this);
-    result.add(other);
-    // TODO(lntue): Set overflow flag / errno when carry is true.
+    UInt<Bits> result;
+    uint64_t carry_in = 0;
+    uint64_t carry_out = 0;
+    for (size_t i = 0; i < WordCount; ++i) {
+      result.val[i] = add_with_carry(val[i], other.val[i], carry_in, carry_out);
+      carry_in = carry_out;
+    }
     return result;
   }
 
   constexpr UInt<Bits> operator+=(const UInt<Bits> &other) {
-    // TODO(lntue): Set overflow flag / errno when carry is true.
-    add(other);
+    add(other); // Returned carry value is ignored.
     return *this;
   }
 
@@ -183,68 +175,40 @@ template <size_t Bits> class UInt {
   // carry bits.
   // Returns the carry value produced by the multiplication operation.
   constexpr uint64_t mul(uint64_t x) {
-    uint64_t x_lo = low(x);
-    uint64_t x_hi = high(x);
-
-    cpp::array<uint64_t, WordCount + 1> row1;
+    UInt<128> partial_sum(0);
     uint64_t carry = 0;
     for (size_t i = 0; i < WordCount; ++i) {
-      uint64_t l = low(val[i]);
-      uint64_t h = high(val[i]);
-      uint64_t p1 = x_lo * l;
-      uint64_t p2 = x_lo * h;
-
-      uint64_t res_lo = low(p1) + carry;
-      carry = high(res_lo);
-      uint64_t res_hi = high(p1) + low(p2) + carry;
-      carry = high(res_hi) + high(p2);
-
-      res_lo = low(res_lo);
-      res_hi = low(res_hi);
-      row1[i] = res_lo + (res_hi << 32);
-    }
-    row1[WordCount] = carry;
-
-    cpp::array<uint64_t, WordCount + 1> row2;
-    row2[0] = 0;
-    carry = 0;
-    for (size_t i = 0; i < WordCount; ++i) {
-      uint64_t l = low(val[i]);
-      uint64_t h = high(val[i]);
-      uint64_t p1 = x_hi * l;
-      uint64_t p2 = x_hi * h;
-
-      uint64_t res_lo = low(p1) + carry;
-      carry = high(res_lo);
-      uint64_t res_hi = high(p1) + low(p2) + carry;
-      carry = high(res_hi) + high(p2);
-
-      res_lo = low(res_lo);
-      res_hi = low(res_hi);
-      row2[i] = res_lo + (res_hi << 32);
-    }
-    row2[WordCount] = carry;
-
-    UInt<(WordCount + 1) * 64> r1(row1), r2(row2);
-    r2.shift_left(32);
-    r1.add(r2);
-    for (size_t i = 0; i < WordCount; ++i) {
-      val[i] = r1[i];
+      NumberPair<uint64_t> prod = full_mul(val[i], x);
+      UInt<128> tmp({prod.lo, prod.hi});
+      carry += partial_sum.add(tmp);
+      val[i] = partial_sum.val[0];
+      partial_sum.val[0] = partial_sum.val[1];
+      partial_sum.val[1] = carry;
+      carry = 0;
     }
-    return r1[WordCount];
+    return partial_sum.val[1];
   }
 
   constexpr UInt<Bits> operator*(const UInt<Bits> &other) const {
-    UInt<Bits> result(0);
-    for (size_t i = 0; i < WordCount; ++i) {
-      if (other[i] == 0)
-        continue;
-      UInt<Bits> row_result(*this);
-      row_result.mul(other[i]);
-      row_result.shift_left(64 * i);
-      result = result + row_result;
+    if constexpr (WordCount == 1) {
+      return {val[0] * other.val[0]};
+    } else {
+      UInt<Bits> result(0);
+      UInt<128> partial_sum(0);
+      uint64_t carry = 0;
+      for (size_t i = 0; i < WordCount; ++i) {
+        for (size_t j = 0; j <= i; j++) {
+          NumberPair<uint64_t> prod = full_mul(val[j], other.val[i - j]);
+          UInt<128> tmp({prod.lo, prod.hi});
+          carry += partial_sum.add(tmp);
+        }
+        result.val[i] = partial_sum.val[0];
+        partial_sum.val[0] = partial_sum.val[1];
+        partial_sum.val[1] = carry;
+        carry = 0;
+      }
+      return result;
     }
-    return result;
   }
 
   // pow takes a power and sets this to its starting value to that power. Zero
@@ -325,21 +289,36 @@ template <size_t Bits> class UInt {
   }
 
   constexpr void shift_left(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; // Bits to shift in the remaining words.
-    const uint64_t mask = ((uint64_t(1) << shift) - 1) << (64 - shift);
+    size_t i = WordCount;
 
-    for (size_t i = WordCount; drop > 0 && i > 0; --i) {
-      if (i > drop)
-        val[i - 1] = val[i - drop - 1];
-      else
-        val[i - 1] = 0;
+    if (drop < WordCount) {
+      i = WordCount - 1;
+      size_t j = WordCount - 1 - drop;
+      for (; j > 0; --i, --j) {
+        val[i] = (val[j] << shift) | (val[j - 1] >> (64 - shift));
+      }
+      val[i] = val[0] << shift;
     }
-    for (size_t i = WordCount; shift > 0 && i > drop; --i) {
-      uint64_t drop_val = (val[i - 1] & mask) >> (64 - shift);
-      val[i - 1] <<= shift;
-      if (i < WordCount)
-        val[i] |= drop_val;
+
+    for (size_t j = 0; j < i; ++j) {
+      val[j] = 0;
     }
   }
 
@@ -357,19 +336,20 @@ template <size_t Bits> class UInt {
   constexpr void shift_right(size_t s) {
     const size_t drop = s / 64;  // Number of words to drop
     const size_t shift = s % 64; // Bit shift in the remaining words.
-    const uint64_t mask = (uint64_t(1) << shift) - 1;
 
-    for (size_t i = 0; drop > 0 && i < WordCount; ++i) {
-      if (i + drop < WordCount)
-        val[i] = val[i + drop];
-      else
-        val[i] = 0;
+    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));
+      }
+      val[i] = val[j] >> shift;
+      ++i;
     }
-    for (size_t i = 0; shift > 0 && i < WordCount; ++i) {
-      uint64_t drop_val = ((val[i] & mask) << (64 - shift));
-      val[i] >>= shift;
-      if (i > 0)
-        val[i - 1] |= drop_val;
+
+    for (; i < WordCount; ++i) {
+      val[i] = 0;
     }
   }
 
@@ -556,9 +536,18 @@ template <> class numeric_limits<UInt<128>> {
   static constexpr UInt<128> min() { return 0; }
 };
 
-// Provides is_integral of UInt<128>.
-template <> struct is_integral<UInt<128>> : public cpp::true_type {};
+// Provides is_integral of UInt<128>, UInt<192>, UInt<256>.
+template <size_t Bits> struct is_integral<UInt<Bits>> : public cpp::true_type {
+  static_assert(Bits > 0 && Bits % 64 == 0,
+                "Number of bits in UInt should be a multiple of 64.");
+};
+
+// Provides is_unsigned of UInt<128>, UInt<192>, UInt<256>.
+template <size_t Bits> struct is_unsigned<UInt<Bits>> : public cpp::true_type {
+  static_assert(Bits > 0 && Bits % 64 == 0,
+                "Number of bits in UInt should be a multiple of 64.");
+};
 
 } // namespace __llvm_libc::cpp
 
-#endif // LLVM_LIBC_UTILS_UINT_H
+#endif // LLVM_LIBC_SRC_SUPPORT_UINT_H

diff  --git a/libc/src/__support/integer_utils.h b/libc/src/__support/integer_utils.h
new file mode 100644
index 0000000000000..b9cddb913702b
--- /dev/null
+++ b/libc/src/__support/integer_utils.h
@@ -0,0 +1,63 @@
+//===-- Utilities for integers. ---------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_INTEGER_UTILS_H
+#define LLVM_LIBC_SRC_SUPPORT_INTEGER_UTILS_H
+
+#include "CPP/type_traits.h"
+#include "builtin_wrappers.h"
+#include "number_pair.h"
+
+#include <stdint.h>
+
+namespace __llvm_libc {
+
+template <typename T> NumberPair<T> full_mul(T a, T b);
+
+template <>
+inline NumberPair<uint32_t> full_mul<uint32_t>(uint32_t a, uint32_t b) {
+  uint64_t prod = uint64_t(a) * uint64_t(b);
+  NumberPair<uint32_t> result;
+  result.lo = uint32_t(prod);
+  result.hi = uint32_t(prod >> 32);
+  return result;
+}
+
+template <>
+inline NumberPair<uint64_t> full_mul<uint64_t>(uint64_t a, uint64_t b) {
+#ifdef __SIZEOF_INT128__
+  __uint128_t prod = __uint128_t(a) * __uint128_t(b);
+  NumberPair<uint64_t> result;
+  result.lo = uint64_t(prod);
+  result.hi = uint64_t(prod >> 64);
+  return result;
+#else
+  NumberPair<uint64_t> pa = split(a);
+  NumberPair<uint64_t> pb = split(b);
+  NumberPair<uint64_t> prod;
+
+  prod.lo = pa.lo * pb.lo;                           // exact
+  prod.hi = pa.hi * pb.hi;                           // exact
+  NumberPair<uint64_t> lo_hi = split(pa.lo * pb.hi); // exact
+  NumberPair<uint64_t> hi_lo = split(pa.hi * pb.lo); // exact
+
+  uint64_t carry_in = 0;
+  uint64_t carry_out = 0;
+  uint64_t carry_unused = 0;
+  prod.lo = add_with_carry(prod.lo, lo_hi.lo << 32, carry_in, carry_out);
+  prod.hi = add_with_carry(prod.hi, lo_hi.hi, carry_out, carry_unused);
+  prod.lo = add_with_carry(prod.lo, hi_lo.lo << 32, carry_in, carry_out);
+  prod.hi = add_with_carry(prod.hi, hi_lo.hi, carry_out, carry_unused);
+
+  return prod;
+#endif // __SIZEOF_INT128__
+}
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SUPPORT_INTEGER_UTILS_H

diff  --git a/libc/src/__support/number_pair.h b/libc/src/__support/number_pair.h
new file mode 100644
index 0000000000000..665a096225718
--- /dev/null
+++ b/libc/src/__support/number_pair.h
@@ -0,0 +1,38 @@
+//===-- Utilities for pairs of numbers. -------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_NUMBER_PAIR_H
+#define LLVM_LIBC_SRC_SUPPORT_NUMBER_PAIR_H
+
+#include "CPP/type_traits.h"
+
+#include <stdint.h>
+
+namespace __llvm_libc {
+
+template <typename T> struct NumberPair {
+  T lo;
+  T hi;
+};
+
+using DoubleDouble = NumberPair<double>;
+
+template <typename T>
+cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T>, NumberPair<T>>
+split(T a) {
+  constexpr size_t HALF_BIT_WIDTH = sizeof(T) * 4;
+  constexpr T LOWER_HALF_MASK = (T(1) << HALF_BIT_WIDTH) - T(1);
+  NumberPair<T> result;
+  result.lo = a & LOWER_HALF_MASK;
+  result.hi = a >> HALF_BIT_WIDTH;
+  return result;
+}
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SUPPORT_NUMBER_PAIR_H

diff  --git a/libc/test/src/__support/uint128_test.cpp b/libc/test/src/__support/uint128_test.cpp
index dcc844a08984d..48f624223fb3d 100644
--- a/libc/test/src/__support/uint128_test.cpp
+++ b/libc/test/src/__support/uint128_test.cpp
@@ -15,6 +15,8 @@
 // we use a sugar which does not conflict with the UInt128 type which can
 // resolve to __uint128_t if the platform has it.
 using LL_UInt128 = __llvm_libc::cpp::UInt<128>;
+using LL_UInt192 = __llvm_libc::cpp::UInt<192>;
+using LL_UInt256 = __llvm_libc::cpp::UInt<256>;
 
 TEST(LlvmLibcUInt128ClassTest, BasicInit) {
   LL_UInt128 empty;
@@ -43,6 +45,24 @@ TEST(LlvmLibcUInt128ClassTest, AdditionTests) {
   LL_UInt128 result3({0x12346789bcdf1233, 0xa987765443210fed});
   EXPECT_EQ(val5 + val6, result3);
   EXPECT_EQ(val5 + val6, val6 + val5);
+
+  // Test 192-bit addition
+  LL_UInt192 val7({0x0123456789abcdef, 0xfedcba9876543210, 0xfedcba9889abcdef});
+  LL_UInt192 val8({0x1111222233334444, 0xaaaabbbbccccdddd, 0xeeeeffffeeeeffff});
+  LL_UInt192 result4(
+      {0x12346789bcdf1233, 0xa987765443210fed, 0xedcbba98789acdef});
+  EXPECT_EQ(val7 + val8, result4);
+  EXPECT_EQ(val7 + val8, val8 + val7);
+
+  // Test 256-bit addition
+  LL_UInt256 val9({0x1f1e1d1c1b1a1918, 0xf1f2f3f4f5f6f7f8, 0x0123456789abcdef,
+                   0xfedcba9876543210});
+  LL_UInt256 val10({0x1111222233334444, 0xaaaabbbbccccdddd, 0x1111222233334444,
+                    0xaaaabbbbccccdddd});
+  LL_UInt256 result5({0x302f3f3e4e4d5d5c, 0x9c9dafb0c2c3d5d5,
+                      0x12346789bcdf1234, 0xa987765443210fed});
+  EXPECT_EQ(val9 + val10, result5);
+  EXPECT_EQ(val9 + val10, val10 + val9);
 }
 
 TEST(LlvmLibcUInt128ClassTest, SubtractionTests) {
@@ -112,6 +132,26 @@ TEST(LlvmLibcUInt128ClassTest, MultiplicationTests) {
   LL_UInt128 result5({0x917cf11d1e039c50, 0x3a4f32d17f40d08f});
   EXPECT_EQ((val9 * val10), result5);
   EXPECT_EQ((val9 * val10), (val10 * val9));
+
+  // Test 192-bit multiplication
+  LL_UInt192 val11(
+      {0xffffffffffffffff, 0x01D762422C946590, 0x9F4F2726179A2245});
+  LL_UInt192 val12(
+      {0xffffffffffffffff, 0x3792F412CB06794D, 0xCDB02555653131B6});
+
+  LL_UInt192 result6(
+      {0x0000000000000001, 0xc695a9ab08652121, 0x5de7faf698d32732});
+  EXPECT_EQ((val11 * val12), result6);
+  EXPECT_EQ((val11 * val12), (val12 * val11));
+
+  LL_UInt256 val13({0xffffffffffffffff, 0x01D762422C946590, 0x9F4F2726179A2245,
+                    0xffffffffffffffff});
+  LL_UInt256 val14({0xffffffffffffffff, 0xffffffffffffffff, 0x3792F412CB06794D,
+                    0xCDB02555653131B6});
+  LL_UInt256 result7({0x0000000000000001, 0xfe289dbdd36b9a6f,
+                      0x291de4c71d5f646c, 0xfd37221cb06d4978});
+  EXPECT_EQ((val13 * val14), result7);
+  EXPECT_EQ((val13 * val14), (val14 * val13));
 }
 
 TEST(LlvmLibcUInt128ClassTest, DivisionTests) {

diff  --git a/libc/utils/UnitTest/LibcTest.cpp b/libc/utils/UnitTest/LibcTest.cpp
index 8a90d8df9d90f..7fe08bff4621e 100644
--- a/libc/utils/UnitTest/LibcTest.cpp
+++ b/libc/utils/UnitTest/LibcTest.cpp
@@ -35,47 +35,43 @@ class RunContext {
 
 namespace internal {
 
-// When the value is of integral type, just display it as normal.
-template <typename ValType>
-cpp::enable_if_t<cpp::is_integral_v<ValType>, std::string>
-describeValue(ValType Value) {
-  return std::to_string(Value);
-}
-
-std::string describeValue(std::string Value) { return std::string(Value); }
-std::string describeValue(cpp::string_view Value) {
-  return std::string(Value.data(), Value.size());
-}
-
 // When the value is UInt128 or __uint128_t, show its hexadecimal digits.
 // We cannot just use a UInt128 specialization as that resolves to only
 // one type, UInt<128> or __uint128_t. We want both overloads as we want to
 // be able to unittest UInt<128> on platforms where UInt128 resolves to
 // UInt128.
-// TODO(lntue): Investigate why UInt<128> was printed backward, with the lower
-// 64-bits first.
-template <typename UInt128Type>
-std::string describeValue128(UInt128Type Value) {
-  std::string S(sizeof(UInt128) * 2, '0');
-
-  for (auto I = S.rbegin(), End = S.rend(); I != End; ++I, Value >>= 4) {
-    unsigned char Mod = static_cast<unsigned char>(Value) & 15;
-    *I = Mod < 10 ? '0' + Mod : 'a' + Mod - 10;
+template <typename T>
+cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T>, std::string>
+describeValueUInt(T Value) {
+  static_assert(sizeof(T) % 8 == 0, "Unsupported size of UInt");
+  std::string S(sizeof(T) * 2, '0');
+
+  constexpr char HEXADECIMALS[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+                                     '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+  for (auto I = S.rbegin(), End = S.rend(); I != End; ++I, Value >>= 8) {
+    unsigned char Mod = static_cast<unsigned char>(Value) & 0xFF;
+    *(I++) = HEXADECIMALS[Mod & 0x0F];
+    *I = HEXADECIMALS[Mod >> 4];
   }
 
   return "0x" + S;
 }
 
-#ifdef __SIZEOF_INT128__
-template <> std::string describeValue<__uint128_t>(__uint128_t Value) {
-  return describeValue128(Value);
+// When the value is of integral type, just display it as normal.
+template <typename ValType>
+cpp::enable_if_t<cpp::is_integral_v<ValType>, std::string>
+describeValue(ValType Value) {
+  if constexpr (sizeof(ValType) <= sizeof(uint64_t)) {
+    return std::to_string(Value);
+  } else {
+    return describeValueUInt(Value);
+  }
 }
-#endif
 
-template <>
-std::string
-describeValue<__llvm_libc::cpp::UInt<128>>(__llvm_libc::cpp::UInt<128> Value) {
-  return describeValue128(Value);
+std::string describeValue(std::string Value) { return std::string(Value); }
+std::string describeValue(cpp::string_view Value) {
+  return std::string(Value.data(), Value.size());
 }
 
 template <typename ValType>
@@ -282,6 +278,16 @@ template bool test<__llvm_libc::cpp::UInt<128>>(
     __llvm_libc::cpp::UInt<128> RHS, const char *LHSStr, const char *RHSStr,
     const char *File, unsigned long Line);
 
+template bool test<__llvm_libc::cpp::UInt<192>>(
+    RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::UInt<192> LHS,
+    __llvm_libc::cpp::UInt<192> RHS, const char *LHSStr, const char *RHSStr,
+    const char *File, unsigned long Line);
+
+template bool test<__llvm_libc::cpp::UInt<256>>(
+    RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::UInt<256> LHS,
+    __llvm_libc::cpp::UInt<256> RHS, const char *LHSStr, const char *RHSStr,
+    const char *File, unsigned long Line);
+
 template bool test<__llvm_libc::cpp::string_view>(
     RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::string_view LHS,
     __llvm_libc::cpp::string_view RHS, const char *LHSStr, const char *RHSStr,

diff  --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index abcb4cd136520..ac84bbc4274c3 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -127,6 +127,26 @@ cc_library(
     ],
 )
 
+cc_library(
+    name = "__support_number_pair",
+    hdrs = ["src/__support/number_pair.h"],
+    deps = [
+        "__support_cpp_type_traits",
+        ":libc_root",
+    ],
+)
+
+cc_library(
+    name = "__support_integer_utils",
+    hdrs = ["src/__support/integer_utils.h"],
+    deps = [
+        "__support_builtin_wrappers",
+        "__support_cpp_type_traits",
+        "__support_number_pair",
+        ":libc_root",
+    ],
+)
+
 cc_library(
     name = "__support_uint",
     hdrs = ["src/__support/UInt.h"],
@@ -136,6 +156,8 @@ cc_library(
         "__support_cpp_type_traits",
         "__support_cpp_optional",
         "__support_builtin_wrappers",
+        "__support_number_pair",
+        "__support_integer_utils",
         ":libc_root",
     ],
 )


        


More information about the libc-commits mailing list