From a2b7ded40ca486ea8a6b5a4b025d9d48e31bfca6 Mon Sep 17 00:00:00 2001 From: Guillaume Chatelet Date: Fri, 8 Dec 2023 17:11:05 +0100 Subject: [libc] Make BigInt bit_cast-able to compatible types (#74837) Fix #74258 --- 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 f72b995..06954d4 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 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 740209b..187b707 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 971bac5..e4d24b0 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 // 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::value); + static_assert(cpp::is_trivially_copyable::value); + static_assert(sizeof(LL_UInt64) == sizeof(double)); + const double inf = HUGE_VAL; + const double max = DBL_MAX; + const double array[] = {0.0, 0.1, 1.0, max, inf}; + for (double value : array) { + LL_UInt64 back = cpp::bit_cast(value); + double forth = cpp::bit_cast(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::value); + static_assert(cpp::is_trivially_copyable::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(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::value); + static_assert(cpp::is_trivially_copyable::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(value); + float128 forth = cpp::bit_cast(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 a973e65..f775183 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", ], ) -- cgit v1.1