[libc-commits] [libc] [llvm] [libc] Make BigInt bit_cast-able to compatible types (PR #74837)

Guillaume Chatelet via libc-commits libc-commits at lists.llvm.org
Fri Dec 8 06:16:56 PST 2023


https://github.com/gchatelet updated https://github.com/llvm/llvm-project/pull/74837

>From 57ca6026970bdd0493648e963e0242b9df2585c4 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Fri, 8 Dec 2023 13:37:44 +0000
Subject: [PATCH 1/2] [libc] Make BigInt bit_cast-able to compatible types

---
 libc/src/__support/UInt.h                     |  5 +-
 libc/test/src/__support/CMakeLists.txt        |  5 +-
 libc/test/src/__support/uint_test.cpp         | 70 ++++++++++++++++---
 .../libc/test/src/__support/BUILD.bazel       |  3 +
 4 files changed, 71 insertions(+), 12 deletions(-)

diff --git a/libc/src/__support/UInt.h b/libc/src/__support/UInt.h
index f72b995f8788db..06954d4f78c2ac 100644
--- a/libc/src/__support/UInt.h
+++ b/libc/src/__support/UInt.h
@@ -25,12 +25,13 @@
 
 namespace LIBC_NAMESPACE::cpp {
 
+// BigInt has the same semantics as the 'standard integer types' and can be
+// safely 'bit_cast'ed to compatible types.
 template <size_t Bits, bool Signed> struct BigInt {
-
   static_assert(Bits > 0 && Bits % 64 == 0,
                 "Number of bits in BigInt should be a multiple of 64.");
   LIBC_INLINE_VAR static constexpr size_t WORDCOUNT = Bits / 64;
-  uint64_t val[WORDCOUNT]{};
+  uint64_t val[WORDCOUNT];
 
   LIBC_INLINE_VAR static constexpr uint64_t MASK32 = 0xFFFFFFFFu;
 
diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt
index 740209bc83d75e..187b70781bdad7 100644
--- a/libc/test/src/__support/CMakeLists.txt
+++ b/libc/test/src/__support/CMakeLists.txt
@@ -89,8 +89,11 @@ add_libc_test(
   SRCS
     uint_test.cpp
   DEPENDS
-    libc.src.__support.uint
+    libc.src.__support.CPP.bit
     libc.src.__support.CPP.optional
+    libc.src.__support.CPP.type_traits
+    libc.src.__support.macros.properties.float
+    libc.src.__support.uint
 )
 
 add_libc_test(
diff --git a/libc/test/src/__support/uint_test.cpp b/libc/test/src/__support/uint_test.cpp
index 971bac55bd9d3f..d4f5f3b3a31869 100644
--- a/libc/test/src/__support/uint_test.cpp
+++ b/libc/test/src/__support/uint_test.cpp
@@ -6,23 +6,73 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/CPP/bit.h" // bit_cast
 #include "src/__support/CPP/optional.h"
+#include "src/__support/CPP/type_traits.h" // is_trivially_constructible
 #include "src/__support/UInt.h"
+#include "src/__support/macros/properties/float.h" // LIBC_COMPILER_HAS_FLOAT128
 
 #include "test/UnitTest/Test.h"
 
-// We want to test LIBC_NAMESPACE::cpp::UInt<128> explicitly. So, for
+#include <math.h> // HUGE_VALF, HUGE_VALF
+
+namespace LIBC_NAMESPACE {
+
+using LL_UInt64 = cpp::UInt<64>;
+// We want to test cpp::UInt<128> explicitly. So, for
 // convenience, 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 = LIBC_NAMESPACE::cpp::UInt<128>;
-using LL_UInt192 = LIBC_NAMESPACE::cpp::UInt<192>;
-using LL_UInt256 = LIBC_NAMESPACE::cpp::UInt<256>;
-using LL_UInt320 = LIBC_NAMESPACE::cpp::UInt<320>;
-using LL_UInt512 = LIBC_NAMESPACE::cpp::UInt<512>;
-using LL_UInt1024 = LIBC_NAMESPACE::cpp::UInt<1024>;
+using LL_UInt128 = cpp::UInt<128>;
+using LL_UInt192 = cpp::UInt<192>;
+using LL_UInt256 = cpp::UInt<256>;
+using LL_UInt320 = cpp::UInt<320>;
+using LL_UInt512 = cpp::UInt<512>;
+using LL_UInt1024 = cpp::UInt<1024>;
+
+using LL_Int128 = cpp::Int<128>;
+using LL_Int192 = cpp::Int<192>;
+
+TEST(LlvmLibcUIntClassTest, BitCastToFromDouble) {
+  static_assert(cpp::is_trivially_constructible<LL_UInt64>::value);
+  static_assert(cpp::is_trivially_copyable<LL_UInt64>::value);
+  static_assert(sizeof(LL_UInt64) == sizeof(double));
+  const double inf = HUGE_VAL;
+  const double max = DBL_MAX;
+  const double array[] = {0.0f, 0.1f, 1.0f, max, inf};
+  for (double value : array) {
+    LL_UInt64 back = cpp::bit_cast<LL_UInt64>(value);
+    double forth = cpp::bit_cast<double>(back);
+    EXPECT_TRUE(value == forth);
+  }
+}
 
-using LL_Int128 = LIBC_NAMESPACE::cpp::Int<128>;
-using LL_Int192 = LIBC_NAMESPACE::cpp::Int<192>;
+#ifdef __SIZEOF_INT128__
+TEST(LlvmLibcUIntClassTest, BitCastToFromNativeUint128) {
+  static_assert(cpp::is_trivially_constructible<LL_UInt128>::value);
+  static_assert(cpp::is_trivially_copyable<LL_UInt128>::value);
+  static_assert(sizeof(LL_UInt128) == sizeof(__uint128_t));
+  const __uint128_t array[] = {0, 1, ~__uint128_t(0)};
+  for (__uint128_t value : array) {
+    LL_UInt128 back = cpp::bit_cast<LL_UInt128>(value);
+    __uint128_t forth = cpp::bit_cast<__uint128_t>(back);
+    EXPECT_TRUE(value == forth);
+  }
+}
+#endif
+
+#ifdef LIBC_COMPILER_HAS_FLOAT128
+TEST(LlvmLibcUIntClassTest, BitCastToFromNativeFloat128) {
+  static_assert(cpp::is_trivially_constructible<LL_UInt128>::value);
+  static_assert(cpp::is_trivially_copyable<LL_UInt128>::value);
+  static_assert(sizeof(LL_UInt128) == sizeof(float128));
+  const float128 array[] = {0, 0.1, 1};
+  for (float128 value : array) {
+    LL_UInt128 back = cpp::bit_cast<LL_UInt128>(value);
+    float128 forth = cpp::bit_cast<float128>(back);
+    EXPECT_TRUE(value == forth);
+  }
+}
+#endif
 
 TEST(LlvmLibcUIntClassTest, BasicInit) {
   LL_UInt128 half_val(12345);
@@ -634,3 +684,5 @@ TEST(LlvmLibcUIntClassTest, ConstructorFromUInt128Tests) {
 }
 
 #endif // __SIZEOF_INT128__
+
+} // namespace LIBC_NAMESPACE
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel
index a973e6541da015..f775183296636e 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel
@@ -74,7 +74,10 @@ libc_test(
     name = "uint_test",
     srcs = ["uint_test.cpp"],
     deps = [
+        "//libc:__support_cpp_bit",
         "//libc:__support_cpp_optional",
+        "//libc:__support_cpp_type_traits",
+        "//libc:__support_macros_properties_float",
         "//libc:__support_uint",
     ],
 )

>From 0d8a1400da2cca50e46d91f7c371818a315d8cd1 Mon Sep 17 00:00:00 2001
From: Guillaume Chatelet <gchatelet at google.com>
Date: Fri, 8 Dec 2023 14:16:42 +0000
Subject: [PATCH 2/2] Remove f suffices

---
 libc/test/src/__support/uint_test.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/test/src/__support/uint_test.cpp b/libc/test/src/__support/uint_test.cpp
index d4f5f3b3a31869..e4d24b08da867c 100644
--- a/libc/test/src/__support/uint_test.cpp
+++ b/libc/test/src/__support/uint_test.cpp
@@ -38,7 +38,7 @@ TEST(LlvmLibcUIntClassTest, BitCastToFromDouble) {
   static_assert(sizeof(LL_UInt64) == sizeof(double));
   const double inf = HUGE_VAL;
   const double max = DBL_MAX;
-  const double array[] = {0.0f, 0.1f, 1.0f, max, inf};
+  const double array[] = {0.0, 0.1, 1.0, max, inf};
   for (double value : array) {
     LL_UInt64 back = cpp::bit_cast<LL_UInt64>(value);
     double forth = cpp::bit_cast<double>(back);



More information about the libc-commits mailing list