Skip to content

Commit a2b7ded

Browse files
authored
[libc] Make BigInt bit_cast-able to compatible types (#74837)
Fix #74258
1 parent 7686d49 commit a2b7ded

File tree

4 files changed

+71
-12
lines changed

4 files changed

+71
-12
lines changed

libc/src/__support/UInt.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@
2525

2626
namespace LIBC_NAMESPACE::cpp {
2727

28+
// BigInt has the same semantics as the 'standard integer types' and can be
29+
// safely 'bit_cast'ed to compatible types.
2830
template <size_t Bits, bool Signed> struct BigInt {
29-
3031
static_assert(Bits > 0 && Bits % 64 == 0,
3132
"Number of bits in BigInt should be a multiple of 64.");
3233
LIBC_INLINE_VAR static constexpr size_t WORDCOUNT = Bits / 64;
33-
uint64_t val[WORDCOUNT]{};
34+
uint64_t val[WORDCOUNT];
3435

3536
LIBC_INLINE_VAR static constexpr uint64_t MASK32 = 0xFFFFFFFFu;
3637

libc/test/src/__support/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,11 @@ add_libc_test(
8989
SRCS
9090
uint_test.cpp
9191
DEPENDS
92-
libc.src.__support.uint
92+
libc.src.__support.CPP.bit
9393
libc.src.__support.CPP.optional
94+
libc.src.__support.CPP.type_traits
95+
libc.src.__support.macros.properties.float
96+
libc.src.__support.uint
9497
)
9598

9699
add_libc_test(

libc/test/src/__support/uint_test.cpp

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,73 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "src/__support/CPP/bit.h" // bit_cast
910
#include "src/__support/CPP/optional.h"
11+
#include "src/__support/CPP/type_traits.h" // is_trivially_constructible
1012
#include "src/__support/UInt.h"
13+
#include "src/__support/macros/properties/float.h" // LIBC_COMPILER_HAS_FLOAT128
1114

1215
#include "test/UnitTest/Test.h"
1316

14-
// We want to test LIBC_NAMESPACE::cpp::UInt<128> explicitly. So, for
17+
#include <math.h> // HUGE_VALF, HUGE_VALF
18+
19+
namespace LIBC_NAMESPACE {
20+
21+
using LL_UInt64 = cpp::UInt<64>;
22+
// We want to test cpp::UInt<128> explicitly. So, for
1523
// convenience, we use a sugar which does not conflict with the UInt128 type
1624
// which can resolve to __uint128_t if the platform has it.
17-
using LL_UInt128 = LIBC_NAMESPACE::cpp::UInt<128>;
18-
using LL_UInt192 = LIBC_NAMESPACE::cpp::UInt<192>;
19-
using LL_UInt256 = LIBC_NAMESPACE::cpp::UInt<256>;
20-
using LL_UInt320 = LIBC_NAMESPACE::cpp::UInt<320>;
21-
using LL_UInt512 = LIBC_NAMESPACE::cpp::UInt<512>;
22-
using LL_UInt1024 = LIBC_NAMESPACE::cpp::UInt<1024>;
25+
using LL_UInt128 = cpp::UInt<128>;
26+
using LL_UInt192 = cpp::UInt<192>;
27+
using LL_UInt256 = cpp::UInt<256>;
28+
using LL_UInt320 = cpp::UInt<320>;
29+
using LL_UInt512 = cpp::UInt<512>;
30+
using LL_UInt1024 = cpp::UInt<1024>;
31+
32+
using LL_Int128 = cpp::Int<128>;
33+
using LL_Int192 = cpp::Int<192>;
34+
35+
TEST(LlvmLibcUIntClassTest, BitCastToFromDouble) {
36+
static_assert(cpp::is_trivially_constructible<LL_UInt64>::value);
37+
static_assert(cpp::is_trivially_copyable<LL_UInt64>::value);
38+
static_assert(sizeof(LL_UInt64) == sizeof(double));
39+
const double inf = HUGE_VAL;
40+
const double max = DBL_MAX;
41+
const double array[] = {0.0, 0.1, 1.0, max, inf};
42+
for (double value : array) {
43+
LL_UInt64 back = cpp::bit_cast<LL_UInt64>(value);
44+
double forth = cpp::bit_cast<double>(back);
45+
EXPECT_TRUE(value == forth);
46+
}
47+
}
2348

24-
using LL_Int128 = LIBC_NAMESPACE::cpp::Int<128>;
25-
using LL_Int192 = LIBC_NAMESPACE::cpp::Int<192>;
49+
#ifdef __SIZEOF_INT128__
50+
TEST(LlvmLibcUIntClassTest, BitCastToFromNativeUint128) {
51+
static_assert(cpp::is_trivially_constructible<LL_UInt128>::value);
52+
static_assert(cpp::is_trivially_copyable<LL_UInt128>::value);
53+
static_assert(sizeof(LL_UInt128) == sizeof(__uint128_t));
54+
const __uint128_t array[] = {0, 1, ~__uint128_t(0)};
55+
for (__uint128_t value : array) {
56+
LL_UInt128 back = cpp::bit_cast<LL_UInt128>(value);
57+
__uint128_t forth = cpp::bit_cast<__uint128_t>(back);
58+
EXPECT_TRUE(value == forth);
59+
}
60+
}
61+
#endif
62+
63+
#ifdef LIBC_COMPILER_HAS_FLOAT128
64+
TEST(LlvmLibcUIntClassTest, BitCastToFromNativeFloat128) {
65+
static_assert(cpp::is_trivially_constructible<LL_UInt128>::value);
66+
static_assert(cpp::is_trivially_copyable<LL_UInt128>::value);
67+
static_assert(sizeof(LL_UInt128) == sizeof(float128));
68+
const float128 array[] = {0, 0.1, 1};
69+
for (float128 value : array) {
70+
LL_UInt128 back = cpp::bit_cast<LL_UInt128>(value);
71+
float128 forth = cpp::bit_cast<float128>(back);
72+
EXPECT_TRUE(value == forth);
73+
}
74+
}
75+
#endif
2676

2777
TEST(LlvmLibcUIntClassTest, BasicInit) {
2878
LL_UInt128 half_val(12345);
@@ -634,3 +684,5 @@ TEST(LlvmLibcUIntClassTest, ConstructorFromUInt128Tests) {
634684
}
635685

636686
#endif // __SIZEOF_INT128__
687+
688+
} // namespace LIBC_NAMESPACE

utils/bazel/llvm-project-overlay/libc/test/src/__support/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ libc_test(
7474
name = "uint_test",
7575
srcs = ["uint_test.cpp"],
7676
deps = [
77+
"//libc:__support_cpp_bit",
7778
"//libc:__support_cpp_optional",
79+
"//libc:__support_cpp_type_traits",
80+
"//libc:__support_macros_properties_float",
7881
"//libc:__support_uint",
7982
],
8083
)

0 commit comments

Comments
 (0)