[libc-commits] [libc] [libc][i386] FPBit support for 96b long double (PR #115084)
Nick Desaulniers via libc-commits
libc-commits at lists.llvm.org
Wed Nov 6 16:02:17 PST 2024
https://github.com/nickdesaulniers updated https://github.com/llvm/llvm-project/pull/115084
>From 12468c7634a55ab3b2cb511cc338b95387d00902 Mon Sep 17 00:00:00 2001
From: Nick Desaulniers <ndesaulniers at google.com>
Date: Thu, 31 Oct 2024 13:52:03 -0700
Subject: [PATCH 1/5] [libc][i386] FPBit support for 96b long double
`long double` is haunted on most architectures, but it is especially so on
i386-linux-gnu. While have 80b of significant data, on i386-linux-gnu this type
has 96b of storage.
Fixes for supporting printf family of conversions for `long double` on
i386-linux-gnu. This allows the libc-stdlib-tests and libc_stdio_unittests
ninja target tests to pass on i386-linux-gnu.
Fixes: #110894
Link: #93709
Link: https://developer.android.com/ndk/guides/abis
Co-authored-by: Michael Jones <michaelrj at google.com>
---
libc/config/linux/i386/entrypoints.txt | 49 ++++++
libc/src/__support/FPUtil/FPBits.h | 4 +
.../FPUtil/generic/sqrt_80_bit_long_double.h | 3 +-
libc/src/__support/big_int.h | 10 +-
libc/src/__support/float_to_string.h | 17 +--
libc/src/__support/integer_literals.h | 4 +
libc/src/__support/str_to_float.h | 14 +-
libc/test/UnitTest/LibcTest.cpp | 2 +-
.../test/src/__support/FPUtil/fpbits_test.cpp | 142 +++++++++++++++++-
.../src/__support/str_to_long_double_test.cpp | 11 ++
libc/test/src/stdlib/strtold_test.cpp | 5 +-
11 files changed, 230 insertions(+), 31 deletions(-)
diff --git a/libc/config/linux/i386/entrypoints.txt b/libc/config/linux/i386/entrypoints.txt
index 6548c9b816c93f..3a1952aeaa4e9a 100644
--- a/libc/config/linux/i386/entrypoints.txt
+++ b/libc/config/linux/i386/entrypoints.txt
@@ -1,6 +1,55 @@
set(TARGET_LIBC_ENTRYPOINTS
# errno.h entrypoints
libc.src.errno.errno
+
+ # stdio.h entrypoints
+ libc.src.stdio.fdopen
+ libc.src.stdio.fileno
+ libc.src.stdio.fprintf
+ libc.src.stdio.fscanf
+ libc.src.stdio.vfscanf
+ libc.src.stdio.printf
+ libc.src.stdio.remove
+ libc.src.stdio.rename
+ libc.src.stdio.scanf
+ libc.src.stdio.vscanf
+ libc.src.stdio.snprintf
+ libc.src.stdio.sprintf
+ libc.src.stdio.asprintf
+ libc.src.stdio.sscanf
+ libc.src.stdio.vsscanf
+ libc.src.stdio.vfprintf
+ libc.src.stdio.vprintf
+ libc.src.stdio.vsnprintf
+ libc.src.stdio.vsprintf
+ libc.src.stdio.vasprintf
+
+ # stdlib.h entrypoints
+ libc.src.stdlib.abs
+ libc.src.stdlib.atof
+ libc.src.stdlib.atoi
+ libc.src.stdlib.atol
+ libc.src.stdlib.atoll
+ libc.src.stdlib.bsearch
+ libc.src.stdlib.div
+ libc.src.stdlib.labs
+ libc.src.stdlib.ldiv
+ libc.src.stdlib.llabs
+ libc.src.stdlib.lldiv
+ libc.src.stdlib.qsort
+ libc.src.stdlib.qsort_r
+ libc.src.stdlib.rand
+ libc.src.stdlib.srand
+ libc.src.stdlib.strfromd
+ libc.src.stdlib.strfromf
+ libc.src.stdlib.strfroml
+ libc.src.stdlib.strtod
+ libc.src.stdlib.strtof
+ libc.src.stdlib.strtol
+ libc.src.stdlib.strtold
+ libc.src.stdlib.strtoll
+ libc.src.stdlib.strtoul
+ libc.src.stdlib.strtoull
)
set(TARGET_LIBM_ENTRYPOINTS "")
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 6da89091a8ced9..2994febff2f8a5 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -127,7 +127,11 @@ template <> struct FPLayout<FPType::IEEE754_Binary128> {
};
template <> struct FPLayout<FPType::X86_Binary80> {
+#if __SIZEOF_LONG_DOUBLE__ == 16
using StorageType = UInt128;
+#else
+ using StorageType = UInt<__SIZEOF_LONG_DOUBLE__ * CHAR_BIT>;
+#endif
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;
LIBC_INLINE_VAR static constexpr int EXP_LEN = 15;
LIBC_INLINE_VAR static constexpr int SIG_LEN = 64;
diff --git a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
index 053348d4c975da..9492d52da04558 100644
--- a/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
+++ b/libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
@@ -21,7 +21,8 @@ namespace LIBC_NAMESPACE_DECL {
namespace fputil {
namespace x86 {
-LIBC_INLINE void normalize(int &exponent, UInt128 &mantissa) {
+LIBC_INLINE void normalize(int &exponent,
+ FPBits<long double>::StorageType &mantissa) {
const unsigned int shift = static_cast<unsigned int>(
cpp::countl_zero(static_cast<uint64_t>(mantissa)) -
(8 * sizeof(uint64_t) - 1 - FPBits<long double>::FRACTION_LEN));
diff --git a/libc/src/__support/big_int.h b/libc/src/__support/big_int.h
index bea0abc84b2136..a95ab4ff8e1abf 100644
--- a/libc/src/__support/big_int.h
+++ b/libc/src/__support/big_int.h
@@ -469,7 +469,7 @@ struct BigInt {
!cpp::is_same_v<T, bool>>>
LIBC_INLINE constexpr BigInt(T v) {
constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT;
- const bool is_neg = Signed && (v < 0);
+ const bool is_neg = v < 0;
for (size_t i = 0; i < WORD_COUNT; ++i) {
if (v == 0) {
extend(i, is_neg);
@@ -504,6 +504,12 @@ struct BigInt {
// TODO: Reuse the Sign type.
LIBC_INLINE constexpr bool is_neg() const { return SIGNED && get_msb(); }
+ template <size_t OtherBits, bool OtherSigned, typename OtherWordType>
+ LIBC_INLINE constexpr explicit
+ operator BigInt<OtherBits, OtherSigned, OtherWordType>() const {
+ return BigInt<OtherBits, OtherSigned, OtherWordType>(this);
+ }
+
template <typename T> LIBC_INLINE constexpr explicit operator T() const {
return to<T>();
}
@@ -1058,6 +1064,8 @@ struct WordTypeSelector : cpp::type_identity<
// Except if we request 16 or 32 bits explicitly.
template <> struct WordTypeSelector<16> : cpp::type_identity<uint16_t> {};
template <> struct WordTypeSelector<32> : cpp::type_identity<uint32_t> {};
+template <> struct WordTypeSelector<96> : cpp::type_identity<uint32_t> {};
+
template <size_t Bits>
using WordTypeSelectorT = typename WordTypeSelector<Bits>::type;
} // namespace internal
diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h
index e2e06cd0492a90..d5de6f38cb6557 100644
--- a/libc/src/__support/float_to_string.h
+++ b/libc/src/__support/float_to_string.h
@@ -373,23 +373,12 @@ LIBC_INLINE UInt<MID_INT_SIZE> get_table_negative_df(int exponent, size_t i) {
return result;
}
-LIBC_INLINE uint32_t fast_uint_mod_1e9(const UInt<MID_INT_SIZE> &val) {
- // The formula for mult_const is:
- // 1 + floor((2^(bits in target integer size + log_2(divider))) / divider)
- // Where divider is 10^9 and target integer size is 128.
- const UInt<MID_INT_SIZE> mult_const(
- {0x31680A88F8953031u, 0x89705F4136B4A597u, 0});
- const auto middle = (mult_const * val);
- const uint64_t result = static_cast<uint64_t>(middle[2]);
- const uint64_t shifted = result >> 29;
- return static_cast<uint32_t>(static_cast<uint32_t>(val) -
- (EXP10_9 * shifted));
-}
-
LIBC_INLINE uint32_t mul_shift_mod_1e9(const FPBits::StorageType mantissa,
const UInt<MID_INT_SIZE> &large,
const int32_t shift_amount) {
- UInt<MID_INT_SIZE + FPBits::STORAGE_LEN> val(large);
+ // make sure the number of bits is always divisible by 64
+ UInt<internal::div_ceil(MID_INT_SIZE + FPBits::STORAGE_LEN, 64) * 64> val(
+ large);
val = (val * mantissa) >> shift_amount;
return static_cast<uint32_t>(
val.div_uint_half_times_pow_2(static_cast<uint32_t>(EXP10_9), 0).value());
diff --git a/libc/src/__support/integer_literals.h b/libc/src/__support/integer_literals.h
index af3da1c443d7b7..4c5c4c41666811 100644
--- a/libc/src/__support/integer_literals.h
+++ b/libc/src/__support/integer_literals.h
@@ -165,6 +165,10 @@ LIBC_INLINE constexpr T parse_with_prefix(const char *ptr) {
} // namespace internal
+LIBC_INLINE constexpr UInt<96> operator""_u96(const char *x) {
+ return internal::parse_with_prefix<UInt<96>>(x);
+}
+
LIBC_INLINE constexpr UInt128 operator""_u128(const char *x) {
return internal::parse_with_prefix<UInt128>(x);
}
diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h
index a1f4eef03fc3ce..80ea334d15c03f 100644
--- a/libc/src/__support/str_to_float.h
+++ b/libc/src/__support/str_to_float.h
@@ -206,7 +206,7 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num,
using FPBits = typename fputil::FPBits<long double>;
using StorageType = typename FPBits::StorageType;
- StorageType mantissa = init_num.mantissa;
+ UInt128 mantissa = init_num.mantissa;
int32_t exp10 = init_num.exponent;
// Exp10 Range
@@ -225,7 +225,8 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num,
}
// Normalization
- uint32_t clz = cpp::countl_zero<StorageType>(mantissa);
+ uint32_t clz = cpp::countl_zero(mantissa) -
+ ((sizeof(UInt128) - sizeof(StorageType)) * CHAR_BIT);
mantissa <<= clz;
int32_t exp2 =
@@ -276,9 +277,8 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num,
// Shifting to 65 bits for 80 bit floats and 113 bits for 128 bit floats
uint32_t msb =
static_cast<uint32_t>(final_approx_upper >> (FPBits::STORAGE_LEN - 1));
- StorageType final_mantissa =
- final_approx_upper >>
- (msb + FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3));
+ UInt128 final_mantissa = final_approx_upper >> (msb + FPBits::STORAGE_LEN -
+ (FPBits::FRACTION_LEN + 3));
exp2 -= static_cast<uint32_t>(1 ^ msb); // same as !msb
if (round == RoundDirection::Nearest) {
@@ -315,7 +315,7 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num,
}
ExpandedFloat<long double> output;
- output.mantissa = final_mantissa;
+ output.mantissa = static_cast<StorageType>(final_mantissa);
output.exponent = exp2;
return output;
}
@@ -558,7 +558,7 @@ clinger_fast_path(ExpandedFloat<T> init_num,
FPBits result;
T float_mantissa;
- if constexpr (cpp::is_same_v<StorageType, UInt<128>>) {
+ if constexpr (is_big_int_v<StorageType> || sizeof(T) > sizeof(uint64_t)) {
float_mantissa =
(static_cast<T>(uint64_t(mantissa >> 64)) * static_cast<T>(0x1.0p64)) +
static_cast<T>(uint64_t(mantissa));
diff --git a/libc/test/UnitTest/LibcTest.cpp b/libc/test/UnitTest/LibcTest.cpp
index ad5722f99a4369..afb1368f009050 100644
--- a/libc/test/UnitTest/LibcTest.cpp
+++ b/libc/test/UnitTest/LibcTest.cpp
@@ -44,7 +44,6 @@ cpp::enable_if_t<(cpp::is_integral_v<T> && (sizeof(T) > sizeof(uint64_t))) ||
is_big_int_v<T>,
cpp::string>
describeValue(T Value) {
- static_assert(sizeof(T) % 8 == 0, "Unsupported size of UInt");
const IntegerToString<T, radix::Hex::WithPrefix> buffer(Value);
return buffer.view();
}
@@ -242,6 +241,7 @@ TEST_SPECIALIZATION(__uint128_t);
TEST_SPECIALIZATION(LIBC_NAMESPACE::Int<128>);
+TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<96>);
TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<128>);
TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<192>);
TEST_SPECIALIZATION(LIBC_NAMESPACE::UInt<256>);
diff --git a/libc/test/src/__support/FPUtil/fpbits_test.cpp b/libc/test/src/__support/FPUtil/fpbits_test.cpp
index bcab0286480c35..edb04c24ae3876 100644
--- a/libc/test/src/__support/FPUtil/fpbits_test.cpp
+++ b/libc/test/src/__support/FPUtil/fpbits_test.cpp
@@ -8,12 +8,14 @@
#include "src/__support/FPUtil/FPBits.h"
#include "src/__support/FPUtil/fpbits_str.h"
+#include "src/__support/big_int.h"
#include "src/__support/integer_literals.h"
#include "src/__support/macros/properties/types.h"
#include "src/__support/sign.h" // Sign
#include "test/UnitTest/Test.h"
using LIBC_NAMESPACE::Sign;
+using LIBC_NAMESPACE::UInt;
using LIBC_NAMESPACE::fputil::FPBits;
using LIBC_NAMESPACE::fputil::FPType;
using LIBC_NAMESPACE::fputil::internal::FPRep;
@@ -21,6 +23,7 @@ using LIBC_NAMESPACE::fputil::internal::FPRep;
using LIBC_NAMESPACE::operator""_u16;
using LIBC_NAMESPACE::operator""_u32;
using LIBC_NAMESPACE::operator""_u64;
+using LIBC_NAMESPACE::operator""_u96;
using LIBC_NAMESPACE::operator""_u128;
TEST(LlvmLibcFPBitsTest, FPType_IEEE754_Binary16) {
@@ -124,6 +127,7 @@ TEST(LlvmLibcFPBitsTest, FPType_IEEE754_Binary128) {
TEST(LlvmLibcFPBitsTest, FPType_X86_Binary80) {
using Rep = FPRep<FPType::X86_Binary80>;
+#if __SIZEOF_LONG_DOUBLE__ == 16
EXPECT_EQ(
0b0'0000000000000000000000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::zero()));
@@ -151,11 +155,43 @@ TEST(LlvmLibcFPBitsTest, FPType_X86_Binary80) {
EXPECT_EQ(
0b0'1111111111111111100000000000000000000000000000000000000000000000000000000000000_u128,
UInt128(Rep::quiet_nan()));
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ EXPECT_EQ(
+ 0b0'0000000000000000000000000000000000000000000000000000000000000000000000000000000_u96,
+ UInt<96>(Rep::zero()));
+ EXPECT_EQ(
+ 0b0'0111111111111111000000000000000000000000000000000000000000000000000000000000000_u96,
+ UInt<96>(Rep::one()));
+ EXPECT_EQ(
+ 0b0'0000000000000000000000000000000000000000000000000000000000000000000000000000001_u96,
+ UInt<96>(Rep::min_subnormal()));
+ EXPECT_EQ(
+ 0b0'0000000000000000111111111111111111111111111111111111111111111111111111111111111_u96,
+ UInt<96>(Rep::max_subnormal()));
+ EXPECT_EQ(
+ 0b0'0000000000000011000000000000000000000000000000000000000000000000000000000000000_u96,
+ UInt<96>(Rep::min_normal()));
+ EXPECT_EQ(
+ 0b0'1111111111111101111111111111111111111111111111111111111111111111111111111111111_u96,
+ UInt<96>(Rep::max_normal()));
+ EXPECT_EQ(
+ 0b0'1111111111111111000000000000000000000000000000000000000000000000000000000000000_u96,
+ UInt<96>(Rep::inf()));
+ EXPECT_EQ(
+ 0b0'1111111111111111010000000000000000000000000000000000000000000000000000000000000_u96,
+ UInt<96>(Rep::signaling_nan()));
+ EXPECT_EQ(
+ 0b0'1111111111111111100000000000000000000000000000000000000000000000000000000000000_u96,
+ UInt<96>(Rep::quiet_nan()));
+#else
+#error "unhandled long double type"
+#endif
}
TEST(LlvmLibcFPBitsTest, FPType_X86_Binary80_IsNan) {
using Rep = FPRep<FPType::X86_Binary80>;
+#if __SIZEOF_LONG_DOUBLE__ == 16
EXPECT_TRUE( // NAN : Pseudo-Infinity
Rep(0b0'111111111111111'0000000000000000000000000000000000000000000000000000000000000000_u128)
.is_nan());
@@ -192,6 +228,46 @@ TEST(LlvmLibcFPBitsTest, FPType_X86_Binary80_IsNan) {
EXPECT_FALSE( // Normalized
Rep(0b0'111111111111110'1000000000000000000000000000000000000000000000000000000000000000_u128)
.is_nan());
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ EXPECT_TRUE( // NAN : Pseudo-Infinity
+ Rep(0b0'111111111111111'0000000000000000000000000000000000000000000000000000000000000000_u96)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Pseudo Not a Number
+ Rep(0b0'111111111111111'0000000000000000000000000000000000000000000000000000000000000001_u96)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Pseudo Not a Number
+ Rep(0b0'111111111111111'0100000000000000000000000000000000000000000000000000000000000000_u96)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Signalling Not a Number
+ Rep(0b0'111111111111111'1000000000000000000000000000000000000000000000000000000000000001_u96)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Floating-point Indefinite
+ Rep(0b0'111111111111111'1100000000000000000000000000000000000000000000000000000000000000_u96)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Quiet Not a Number
+ Rep(0b0'111111111111111'1100000000000000000000000000000000000000000000000000000000000001_u96)
+ .is_nan());
+ EXPECT_TRUE( // NAN : Unnormal
+ Rep(0b0'111111111111110'0000000000000000000000000000000000000000000000000000000000000000_u96)
+ .is_nan());
+ EXPECT_FALSE( // Zero
+ Rep(0b0'000000000000000'0000000000000000000000000000000000000000000000000000000000000000_u96)
+ .is_nan());
+ EXPECT_FALSE( // Subnormal
+ Rep(0b0'000000000000000'0000000000000000000000000000000000000000000000000000000000000001_u96)
+ .is_nan());
+ EXPECT_FALSE( // Pseudo Denormal
+ Rep(0b0'000000000000000'1000000000000000000000000000000000000000000000000000000000000001_u96)
+ .is_nan());
+ EXPECT_FALSE( // Infinity
+ Rep(0b0'111111111111111'1000000000000000000000000000000000000000000000000000000000000000_u96)
+ .is_nan());
+ EXPECT_FALSE( // Normalized
+ Rep(0b0'111111111111110'1000000000000000000000000000000000000000000000000000000000000000_u96)
+ .is_nan());
+#else
+#error "unhandled long double type"
+#endif
}
enum class FP {
@@ -430,6 +506,7 @@ TEST(LlvmLibcFPBitsTest, DoubleType) {
#ifdef LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80
TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
using LongDoubleBits = FPBits<long double>;
+ using Rep = FPRep<FPType::X86_Binary80>;
EXPECT_STREQ(LIBC_NAMESPACE::str(LongDoubleBits::inf(Sign::POS)).c_str(),
"(+Infinity)");
@@ -441,62 +518,117 @@ TEST(LlvmLibcFPBitsTest, X86LongDoubleType) {
LongDoubleBits zero(0.0l);
EXPECT_TRUE(zero.is_pos());
EXPECT_EQ(zero.get_biased_exponent(), 0_u16);
- EXPECT_EQ(zero.get_mantissa(), 0_u128);
- EXPECT_EQ(zero.uintval(), 0_u128);
+ EXPECT_EQ(zero.get_mantissa(), LongDoubleBits::StorageType(Rep::zero()));
+ EXPECT_EQ(zero.uintval(), LongDoubleBits::StorageType(Rep::zero()));
+#if __SIZEOF_LONG_DOUBLE__ == 16
EXPECT_STREQ(
LIBC_NAMESPACE::str(zero).c_str(),
"0x00000000000000000000000000000000 = "
"(S: 0, E: 0x0000, I: 0, M: 0x00000000000000000000000000000000)");
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ EXPECT_STREQ(LIBC_NAMESPACE::str(zero).c_str(),
+ "0x000000000000000000000000 = "
+ "(S: 0, E: 0x0000, I: 0, M: 0x000000000000000000000000)");
+#else
+#error "unhandled long double type"
+#endif
LongDoubleBits negzero(-0.0l);
EXPECT_TRUE(negzero.is_neg());
EXPECT_EQ(negzero.get_biased_exponent(), 0_u16);
- EXPECT_EQ(negzero.get_mantissa(), 0_u128);
+ EXPECT_EQ(negzero.get_mantissa(), LongDoubleBits::StorageType(Rep::zero()));
+#if __SIZEOF_LONG_DOUBLE__ == 16
EXPECT_EQ(negzero.uintval(), 0x8000'00000000'00000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(negzero).c_str(),
"0x00000000000080000000000000000000 = "
"(S: 1, E: 0x0000, I: 0, M: 0x00000000000000000000000000000000)");
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ EXPECT_EQ(negzero.uintval(), 0x8000'00000000'00000000_u96);
+ EXPECT_STREQ(LIBC_NAMESPACE::str(negzero).c_str(),
+ "0x000080000000000000000000 = "
+ "(S: 1, E: 0x0000, I: 0, M: 0x000000000000000000000000)");
+#else
+#error "unhandled long double type"
+#endif
LongDoubleBits one(1.0l);
EXPECT_TRUE(one.is_pos());
EXPECT_EQ(one.get_biased_exponent(), 0x3FFF_u16);
- EXPECT_EQ(one.get_mantissa(), 0_u128);
+ EXPECT_EQ(one.get_mantissa(), LongDoubleBits::StorageType(Rep::zero()));
+#if __SIZEOF_LONG_DOUBLE__ == 16
EXPECT_EQ(one.uintval(), 0x3FFF'80000000'00000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(one).c_str(),
"0x0000000000003FFF8000000000000000 = "
"(S: 0, E: 0x3FFF, I: 1, M: 0x00000000000000000000000000000000)");
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ EXPECT_EQ(one.uintval(), 0x3FFF'80000000'00000000_u96);
+ EXPECT_STREQ(LIBC_NAMESPACE::str(one).c_str(),
+ "0x00003FFF8000000000000000 = "
+ "(S: 0, E: 0x3FFF, I: 1, M: 0x000000000000000000000000)");
+#else
+#error "unhandled long double type"
+#endif
LongDoubleBits negone(-1.0l);
EXPECT_TRUE(negone.is_neg());
EXPECT_EQ(negone.get_biased_exponent(), 0x3FFF_u16);
- EXPECT_EQ(negone.get_mantissa(), 0_u128);
+ EXPECT_EQ(negone.get_mantissa(), LongDoubleBits::StorageType(Rep::zero()));
+#if __SIZEOF_LONG_DOUBLE__ == 16
EXPECT_EQ(negone.uintval(), 0xBFFF'80000000'00000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(negone).c_str(),
"0x000000000000BFFF8000000000000000 = "
"(S: 1, E: 0x3FFF, I: 1, M: 0x00000000000000000000000000000000)");
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ EXPECT_EQ(negone.uintval(), 0xBFFF'80000000'00000000_u96);
+ EXPECT_STREQ(LIBC_NAMESPACE::str(negone).c_str(),
+ "0x0000BFFF8000000000000000 = "
+ "(S: 1, E: 0x3FFF, I: 1, M: 0x000000000000000000000000)");
+#else
+#error "unhandled long double type"
+#endif
LongDoubleBits num(1.125l);
EXPECT_TRUE(num.is_pos());
EXPECT_EQ(num.get_biased_exponent(), 0x3FFF_u16);
+#if __SIZEOF_LONG_DOUBLE__ == 16
EXPECT_EQ(num.get_mantissa(), 0x10000000'00000000_u128);
EXPECT_EQ(num.uintval(), 0x3FFF'90000000'00000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(num).c_str(),
"0x0000000000003FFF9000000000000000 = "
"(S: 0, E: 0x3FFF, I: 1, M: 0x00000000000000001000000000000000)");
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ EXPECT_EQ(num.get_mantissa(), 0x10000000'00000000_u96);
+ EXPECT_EQ(num.uintval(), 0x3FFF'90000000'00000000_u96);
+ EXPECT_STREQ(LIBC_NAMESPACE::str(num).c_str(),
+ "0x00003FFF9000000000000000 = "
+ "(S: 0, E: 0x3FFF, I: 1, M: 0x000000001000000000000000)");
+#else
+#error "unhandled long double type"
+#endif
LongDoubleBits negnum(-1.125l);
EXPECT_TRUE(negnum.is_neg());
EXPECT_EQ(negnum.get_biased_exponent(), 0x3FFF_u16);
+#if __SIZEOF_LONG_DOUBLE__ == 16
EXPECT_EQ(negnum.get_mantissa(), 0x10000000'00000000_u128);
EXPECT_EQ(negnum.uintval(), 0xBFFF'90000000'00000000_u128);
EXPECT_STREQ(
LIBC_NAMESPACE::str(negnum).c_str(),
"0x000000000000BFFF9000000000000000 = "
"(S: 1, E: 0x3FFF, I: 1, M: 0x00000000000000001000000000000000)");
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ EXPECT_EQ(negnum.get_mantissa(), 0x10000000'00000000_u96);
+ EXPECT_EQ(negnum.uintval(), 0xBFFF'90000000'00000000_u96);
+ EXPECT_STREQ(LIBC_NAMESPACE::str(negnum).c_str(),
+ "0x0000BFFF9000000000000000 = "
+ "(S: 1, E: 0x3FFF, I: 1, M: 0x000000001000000000000000)");
+#else
+#error "unhandled long double type"
+#endif
LongDoubleBits quiet_nan = LongDoubleBits::quiet_nan();
EXPECT_EQ(quiet_nan.is_quiet_nan(), true);
diff --git a/libc/test/src/__support/str_to_long_double_test.cpp b/libc/test/src/__support/str_to_long_double_test.cpp
index 9efa457aac9577..fa7d600f9bff4e 100644
--- a/libc/test/src/__support/str_to_long_double_test.cpp
+++ b/libc/test/src/__support/str_to_long_double_test.cpp
@@ -30,12 +30,23 @@ TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80Simple) {
}
TEST_F(LlvmLibcStrToLongDblTest, EiselLemireFloat80LongerMantissa) {
+#if __SIZEOF_LONG_DOUBLE__ == 16
eisel_lemire_test(0x12345678'12345678'12345678'12345678_u128, 0,
0x91a2b3c091a2b3c1, 16507);
eisel_lemire_test(0x12345678'12345678'12345678'12345678_u128, 300,
0xd97757de56adb65c, 17503);
eisel_lemire_test(0x12345678'12345678'12345678'12345678_u128, -300,
0xc30feb9a7618457d, 15510);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ eisel_lemire_test(0x12345678'12345678'12345678_u96, 0, 0x91a2b3c091a2b3c1,
+ 16475);
+ eisel_lemire_test(0x12345678'12345678'12345678_u96, 300, 0xd97757de56adb65c,
+ 17471);
+ eisel_lemire_test(0x12345678'12345678'12345678_u96, -300, 0xc30feb9a7618457d,
+ 15478);
+#else
+#error "unhandled long double type"
+#endif
}
// These tests check numbers at the edge of the DETAILED_POWERS_OF_TEN table.
diff --git a/libc/test/src/stdlib/strtold_test.cpp b/libc/test/src/stdlib/strtold_test.cpp
index 2c9f542930bf86..b209c85b88e369 100644
--- a/libc/test/src/stdlib/strtold_test.cpp
+++ b/libc/test/src/stdlib/strtold_test.cpp
@@ -75,8 +75,9 @@ class LlvmLibcStrToLDTest : public LIBC_NAMESPACE::testing::Test {
// +-- 15 Exponent Bits
char *str_end = nullptr;
- LIBC_NAMESPACE::fputil::FPBits<long double> expected_fp =
- LIBC_NAMESPACE::fputil::FPBits<long double>(expectedRawData);
+ using FPBits = LIBC_NAMESPACE::fputil::FPBits<long double>;
+ FPBits expected_fp =
+ FPBits(static_cast<FPBits::StorageType>(expectedRawData));
const int expected_errno = expectedErrno;
LIBC_NAMESPACE::libc_errno = 0;
>From be223620e9c8466ca88e4b4f3cf06ce92cfe329f Mon Sep 17 00:00:00 2001
From: Nick Desaulniers <ndesaulniers at google.com>
Date: Wed, 6 Nov 2024 10:44:54 -0800
Subject: [PATCH 2/5] test case
---
libc/test/src/__support/big_int_test.cpp | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/libc/test/src/__support/big_int_test.cpp b/libc/test/src/__support/big_int_test.cpp
index 471ca72a8f6e0c..02dd9ff70f942a 100644
--- a/libc/test/src/__support/big_int_test.cpp
+++ b/libc/test/src/__support/big_int_test.cpp
@@ -1067,4 +1067,12 @@ TEST(LlvmLibcUIntClassTest, SignedOtherWordTypeCastTests) {
ASSERT_TRUE(bigger_back_plus_a + bigger_back_minus_a == zero_96);
}
+TEST(LlvmLibcUIntClassTest, MixedSignednessOtherWordTypeCastTests) {
+ using LL_UInt96 = BigInt<96, false, uint32_t>;
+ LL_UInt96 x = -123;
+ // ensure that -123 gets extended, even though the input type is signed while
+ // the BigInt is unsigned.
+ ASSERT_EQ(int64_t(x), -123LL);
+}
+
} // namespace LIBC_NAMESPACE_DECL
>From 474aad73d1213340663ceb631ba2c78ef774b9ca Mon Sep 17 00:00:00 2001
From: Nick Desaulniers <ndesaulniers at google.com>
Date: Wed, 6 Nov 2024 10:45:11 -0800
Subject: [PATCH 3/5] todo for android
---
libc/src/__support/FPUtil/FPBits.h | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 2994febff2f8a5..2b030b51c3a8b3 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -127,10 +127,17 @@ template <> struct FPLayout<FPType::IEEE754_Binary128> {
};
template <> struct FPLayout<FPType::X86_Binary80> {
+// x86_64
#if __SIZEOF_LONG_DOUBLE__ == 16
using StorageType = UInt128;
-#else
+// i386-linux-gnu
+#elif __SIZEOF_LONG_DOUBLE__ == 12
using StorageType = UInt<__SIZEOF_LONG_DOUBLE__ * CHAR_BIT>;
+#else
+# TODO: https://github.com/llvm/llvm-project/issues/115184
+# Android i386 uses `long double == double` i.e. `sizeof(long double) == 8`
+# https://developer.android.com/ndk/guides/abis#x86
+#error "unexpected size of long double"
#endif
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;
LIBC_INLINE_VAR static constexpr int EXP_LEN = 15;
>From 17b92eb9e8cf91f42d80723b20af9842c151d5e6 Mon Sep 17 00:00:00 2001
From: Nick Desaulniers <ndesaulniers at google.com>
Date: Wed, 6 Nov 2024 12:18:19 -0800
Subject: [PATCH 4/5] moar math.h
---
libc/config/linux/i386/entrypoints.txt | 267 +++++++++++++++++++-
libc/test/src/math/smoke/CanonicalizeTest.h | 77 ++++++
2 files changed, 343 insertions(+), 1 deletion(-)
diff --git a/libc/config/linux/i386/entrypoints.txt b/libc/config/linux/i386/entrypoints.txt
index 3a1952aeaa4e9a..062b042ec78261 100644
--- a/libc/config/linux/i386/entrypoints.txt
+++ b/libc/config/linux/i386/entrypoints.txt
@@ -52,7 +52,272 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.stdlib.strtoull
)
-set(TARGET_LIBM_ENTRYPOINTS "")
+set(TARGET_LIBM_ENTRYPOINTS
+ # fenv.h entrypoints
+ libc.src.fenv.feclearexcept
+ libc.src.fenv.fedisableexcept
+ libc.src.fenv.feenableexcept
+ libc.src.fenv.fegetenv
+ libc.src.fenv.fegetexcept
+ libc.src.fenv.fegetexceptflag
+ libc.src.fenv.fegetround
+ libc.src.fenv.feholdexcept
+ libc.src.fenv.feraiseexcept
+ libc.src.fenv.fesetenv
+ libc.src.fenv.fesetexcept
+ libc.src.fenv.fesetexceptflag
+ libc.src.fenv.fesetround
+ libc.src.fenv.fetestexcept
+ libc.src.fenv.fetestexceptflag
+ libc.src.fenv.feupdateenv
+
+ # math.h entrypoints
+ libc.src.math.acosf
+ libc.src.math.acoshf
+ libc.src.math.asinf
+ libc.src.math.asinhf
+ libc.src.math.atan2
+ libc.src.math.atan2f
+ libc.src.math.atanf
+ libc.src.math.atanhf
+ libc.src.math.canonicalize
+ libc.src.math.canonicalizef
+ libc.src.math.canonicalizel
+ libc.src.math.cbrt
+ libc.src.math.cbrtf
+ libc.src.math.ceil
+ libc.src.math.ceilf
+ libc.src.math.ceill
+ libc.src.math.copysign
+ libc.src.math.copysignf
+ libc.src.math.copysignl
+ libc.src.math.cos
+ libc.src.math.cosf
+ libc.src.math.coshf
+ libc.src.math.cospif
+ libc.src.math.dfmal
+ libc.src.math.dmull
+ libc.src.math.dsqrtl
+ libc.src.math.daddl
+ # libc.src.math.ddivl
+ libc.src.math.dsubl
+ libc.src.math.erff
+ libc.src.math.exp
+ libc.src.math.exp10
+ libc.src.math.exp10f
+ libc.src.math.exp2
+ libc.src.math.exp2f
+ libc.src.math.exp2m1f
+ libc.src.math.expf
+ libc.src.math.expm1
+ libc.src.math.expm1f
+ libc.src.math.fabs
+ libc.src.math.fabsf
+ libc.src.math.fabsl
+ libc.src.math.fadd
+ libc.src.math.faddl
+ libc.src.math.fadd
+ libc.src.math.fdim
+ libc.src.math.fdimf
+ libc.src.math.fdiml
+ libc.src.math.fdiv
+ # libc.src.math.fdivl
+ libc.src.math.ffma
+ libc.src.math.ffmal
+ libc.src.math.floor
+ libc.src.math.floorf
+ libc.src.math.floorl
+ libc.src.math.fma
+ libc.src.math.fmaf
+ libc.src.math.fmax
+ libc.src.math.fmaxf
+ libc.src.math.fmaximum
+ libc.src.math.fmaximum_mag
+ libc.src.math.fmaximum_mag_num
+ libc.src.math.fmaximum_mag_numf
+ libc.src.math.fmaximum_mag_numl
+ libc.src.math.fmaximum_magf
+ libc.src.math.fmaximum_magl
+ libc.src.math.fmaximum_num
+ libc.src.math.fmaximum_numf
+ libc.src.math.fmaximum_numl
+ libc.src.math.fmaximumf
+ libc.src.math.fmaximuml
+ libc.src.math.fmaxl
+ libc.src.math.fmin
+ libc.src.math.fminf
+ libc.src.math.fminimum
+ libc.src.math.fminimum_mag
+ libc.src.math.fminimum_mag_num
+ libc.src.math.fminimum_mag_numf
+ libc.src.math.fminimum_mag_numl
+ libc.src.math.fminimum_magf
+ libc.src.math.fminimum_magl
+ libc.src.math.fminimum_num
+ libc.src.math.fminimum_numf
+ libc.src.math.fminimum_numl
+ libc.src.math.fminimumf
+ libc.src.math.fminimuml
+ libc.src.math.fminl
+ libc.src.math.fmod
+ libc.src.math.fmodf
+ libc.src.math.fmodl
+ libc.src.math.fmul
+ libc.src.math.fmull
+ libc.src.math.frexp
+ libc.src.math.frexpf
+ libc.src.math.frexpl
+ libc.src.math.fromfp
+ libc.src.math.fromfpf
+ libc.src.math.fromfpl
+ libc.src.math.fromfpx
+ libc.src.math.fromfpxf
+ libc.src.math.fromfpxl
+ libc.src.math.fsqrt
+ libc.src.math.fsqrtl
+ libc.src.math.fsub
+ libc.src.math.fsubl
+ libc.src.math.getpayload
+ libc.src.math.getpayloadf
+ libc.src.math.getpayloadl
+ libc.src.math.hypot
+ libc.src.math.hypotf
+ libc.src.math.ilogb
+ libc.src.math.ilogbf
+ libc.src.math.ilogbl
+ libc.src.math.iscanonical
+ libc.src.math.iscanonicalf
+ libc.src.math.iscanonicall
+ libc.src.math.isnan
+ libc.src.math.isnanf
+ libc.src.math.isnanl
+ libc.src.math.issignaling
+ libc.src.math.issignalingf
+ libc.src.math.issignalingl
+ libc.src.math.ldexp
+ libc.src.math.ldexpf
+ libc.src.math.ldexpl
+ libc.src.math.llogb
+ libc.src.math.llogbf
+ libc.src.math.llogbl
+ libc.src.math.llrint
+ libc.src.math.llrintf
+ libc.src.math.llrintl
+ libc.src.math.llround
+ libc.src.math.llroundf
+ libc.src.math.llroundl
+ libc.src.math.log
+ libc.src.math.log10
+ libc.src.math.log10f
+ libc.src.math.log1p
+ libc.src.math.log1pf
+ libc.src.math.log2
+ libc.src.math.log2f
+ libc.src.math.logb
+ libc.src.math.logbf
+ libc.src.math.logbl
+ libc.src.math.logf
+ libc.src.math.lrint
+ libc.src.math.lrintf
+ libc.src.math.lrintl
+ libc.src.math.lround
+ libc.src.math.llroundf
+ libc.src.math.llroundl
+ libc.src.math.log
+ libc.src.math.log10
+ libc.src.math.log10f
+ libc.src.math.log1p
+ libc.src.math.log1pf
+ libc.src.math.log2
+ libc.src.math.log2f
+ libc.src.math.logb
+ libc.src.math.logbf
+ libc.src.math.logbl
+ libc.src.math.logf
+ libc.src.math.lrint
+ libc.src.math.lrintf
+ libc.src.math.lrintl
+ libc.src.math.lround
+ libc.src.math.lroundf
+ libc.src.math.lroundl
+ libc.src.math.modf
+ libc.src.math.modff
+ libc.src.math.modfl
+ libc.src.math.nan
+ libc.src.math.nanf
+ libc.src.math.nanl
+ libc.src.math.nearbyint
+ libc.src.math.nearbyintf
+ libc.src.math.nearbyintl
+ libc.src.math.nextafter
+ libc.src.math.nextafterf
+ libc.src.math.nextafterl
+ libc.src.math.nextdown
+ libc.src.math.nextdownf
+ libc.src.math.nextdownl
+ libc.src.math.nexttoward
+ libc.src.math.nexttowardf
+ libc.src.math.nexttowardl
+ libc.src.math.nextup
+ libc.src.math.nextupf
+ libc.src.math.nextupl
+ libc.src.math.pow
+ libc.src.math.powf
+ libc.src.math.remainder
+ libc.src.math.remainderf
+ libc.src.math.remainderl
+ libc.src.math.remquo
+ libc.src.math.remquof
+ libc.src.math.remquol
+ libc.src.math.rint
+ libc.src.math.rintf
+ libc.src.math.rintl
+ libc.src.math.round
+ libc.src.math.roundeven
+ libc.src.math.roundevenf
+ libc.src.math.roundevenl
+ libc.src.math.roundf
+ libc.src.math.roundl
+ libc.src.math.scalbln
+ libc.src.math.scalblnf
+ libc.src.math.scalblnl
+ libc.src.math.scalbn
+ libc.src.math.scalbnf
+ libc.src.math.scalbnl
+ libc.src.math.setpayload
+ libc.src.math.setpayloadf
+ libc.src.math.setpayloadl
+ libc.src.math.setpayloadsig
+ libc.src.math.setpayloadsigf
+ libc.src.math.setpayloadsigl
+ libc.src.math.sin
+ libc.src.math.sincos
+ libc.src.math.sincosf
+ libc.src.math.sinf
+ libc.src.math.sinhf
+ libc.src.math.sinpif
+ libc.src.math.sqrt
+ libc.src.math.sqrtf
+ libc.src.math.sqrtl
+ libc.src.math.tan
+ libc.src.math.tanf
+ libc.src.math.tanhf
+ libc.src.math.totalorder
+ libc.src.math.totalorderf
+ libc.src.math.totalorderl
+ libc.src.math.totalordermag
+ libc.src.math.totalordermagf
+ libc.src.math.totalordermagl
+ libc.src.math.trunc
+ libc.src.math.truncf
+ libc.src.math.truncl
+ libc.src.math.ufromfp
+ libc.src.math.ufromfpf
+ libc.src.math.ufromfpl
+ libc.src.math.ufromfpx
+ libc.src.math.ufromfpxf
+ libc.src.math.ufromfpxl
+)
set(TARGET_LLVMLIBC_ENTRYPOINTS
${TARGET_LIBC_ENTRYPOINTS}
diff --git a/libc/test/src/math/smoke/CanonicalizeTest.h b/libc/test/src/math/smoke/CanonicalizeTest.h
index 3baf60c3140ff4..f22a282b1843b6 100644
--- a/libc/test/src/math/smoke/CanonicalizeTest.h
+++ b/libc/test/src/math/smoke/CanonicalizeTest.h
@@ -18,6 +18,10 @@
#include "hdr/math_macros.h"
+#if __SIZEOF_LONG_DOUBLE__ != 16 && __SIZEOF_LONG_DOUBLE__ != 12
+#error "unhandled long double type"
+#endif
+
#define TEST_SPECIAL(x, y, expected, expected_exception) \
EXPECT_EQ(expected, f(&x, &y)); \
EXPECT_FP_EXCEPTION(expected_exception); \
@@ -25,6 +29,7 @@
#define TEST_REGULAR(x, y, expected) TEST_SPECIAL(x, y, expected, 0)
+using LIBC_NAMESPACE::operator""_u96;
using LIBC_NAMESPACE::operator""_u128;
template <typename T>
@@ -61,7 +66,11 @@ class CanonicalizeTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
// Exponent | Significand | Meaning
// | Bits 63-62 | Bits 61-0 |
// All Ones | 00 | Zero | Pseudo Infinity, Value = SNaN
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test1(0x00000000'00007FFF'00000000'00000000_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test1(0x00007FFF'00000000'00000000_u96);
+#endif
const T test1_val = test1.get_val();
TEST_SPECIAL(cx, test1_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
@@ -69,22 +78,38 @@ class CanonicalizeTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
// Exponent | Significand | Meaning
// | Bits 63-62 | Bits 61-0 |
// All Ones | 00 | Non-Zero | Pseudo NaN, Value = SNaN
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test2_1(0x00000000'00007FFF'00000000'00000001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test2_1(0x00007FFF'00000000'00000001_u96);
+#endif
const T test2_1_val = test2_1.get_val();
TEST_SPECIAL(cx, test2_1_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test2_2(0x00000000'00007FFF'00000042'70000001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test2_2(0x00007FFF'00000042'70000001_u96);
+#endif
const T test2_2_val = test2_2.get_val();
TEST_SPECIAL(cx, test2_2_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test2_3(0x00000000'00007FFF'00000000'08261001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test2_3(0x00007FFF'00000000'08261001_u96);
+#endif
const T test2_3_val = test2_3.get_val();
TEST_SPECIAL(cx, test2_3_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test2_4(0x00000000'00007FFF'00007800'08261001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test2_4(0x00007FFF'00007800'08261001_u96);
+#endif
const T test2_4_val = test2_4.get_val();
TEST_SPECIAL(cx, test2_4_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
@@ -92,22 +117,38 @@ class CanonicalizeTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
// Exponent | Significand | Meaning
// | Bits 63-62 | Bits 61-0 |
// All Ones | 01 | Anything | Pseudo NaN, Value = SNaN
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test3_1(0x00000000'00007FFF'40000000'00000000_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test3_1(0x00007FFF'40000000'00000000_u96);
+#endif
const T test3_1_val = test3_1.get_val();
TEST_SPECIAL(cx, test3_1_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test3_2(0x00000000'00007FFF'40000042'70000001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test3_2(0x00007FFF'40000042'70000001_u96);
+#endif
const T test3_2_val = test3_2.get_val();
TEST_SPECIAL(cx, test3_2_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test3_3(0x00000000'00007FFF'40000000'08261001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test3_3(0x00007FFF'40000000'08261001_u96);
+#endif
const T test3_3_val = test3_3.get_val();
TEST_SPECIAL(cx, test3_3_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test3_4(0x00000000'00007FFF'40007800'08261001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test3_4(0x00007FFF'40007800'08261001_u96);
+#endif
const T test3_4_val = test3_4.get_val();
TEST_SPECIAL(cx, test3_4_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
@@ -116,19 +157,31 @@ class CanonicalizeTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
// | Bit 63 | Bits 62-0 |
// All zeroes | One | Anything | Pseudo Denormal, Value =
// | | | (−1)**s × m × 2**−16382
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test4_1(0x00000000'00000000'80000000'00000000_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test4_1(0x00000000'80000000'00000000_u96);
+#endif
const T test4_1_val = test4_1.get_val();
TEST_SPECIAL(cx, test4_1_val, 0, 0);
EXPECT_FP_EQ(
cx, FPBits::make_value(test4_1.get_explicit_mantissa(), 0).get_val());
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test4_2(0x00000000'00000000'80000042'70000001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test4_2(0x00000000'80000042'70000001_u96);
+#endif
const T test4_2_val = test4_2.get_val();
TEST_SPECIAL(cx, test4_2_val, 0, 0);
EXPECT_FP_EQ(
cx, FPBits::make_value(test4_2.get_explicit_mantissa(), 0).get_val());
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test4_3(0x00000000'00000000'80000000'08261001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test4_3(0x00000000'80000000'08261001_u96);
+#endif
const T test4_3_val = test4_3.get_val();
TEST_SPECIAL(cx, test4_3_val, 0, 0);
EXPECT_FP_EQ(
@@ -138,32 +191,56 @@ class CanonicalizeTest : public LIBC_NAMESPACE::testing::FEnvSafeTest {
// | Bit 63 | Bits 62-0 |
// All Other | Zero | Anything | Unnormal, Value = SNaN
// Values | | |
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test5_1(0x00000000'00000040'00000000'00000001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test5_1(0x00000040'00000000'00000001_u96);
+#endif
const T test5_1_val = test5_1.get_val();
TEST_SPECIAL(cx, test5_1_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test5_2(0x00000000'00000230'00000042'70000001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test5_2(0x00000230'00000042'70000001_u96);
+#endif
const T test5_2_val = test5_2.get_val();
TEST_SPECIAL(cx, test5_2_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test5_3(0x00000000'00000560'00000000'08261001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test5_3(0x00000560'00000000'08261001_u96);
+#endif
const T test5_3_val = test5_3.get_val();
TEST_SPECIAL(cx, test5_3_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test5_4(0x00000000'00000780'00000028'16000000_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test5_4(0x00000780'00000028'16000000_u96);
+#endif
const T test5_4_val = test5_4.get_val();
TEST_SPECIAL(cx, test5_4_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test5_5(0x00000000'00000900'00000042'70000001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test5_5(0x00000900'00000042'70000001_u96);
+#endif
const T test5_5_val = test5_5.get_val();
TEST_SPECIAL(cx, test5_5_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
+#if __SIZEOF_LONG_DOUBLE__ == 16
FPBits test5_6(0x00000000'00000AB0'00000000'08261001_u128);
+#elif __SIZEOF_LONG_DOUBLE__ == 12
+ FPBits test5_6(0x00000AB0'00000000'08261001_u96);
+#endif
const T test5_6_val = test5_6.get_val();
TEST_SPECIAL(cx, test5_6_val, 1, FE_INVALID);
EXPECT_FP_EQ(cx, aNaN);
>From 189238088152296da2b913085fdb21cc17736ca7 Mon Sep 17 00:00:00 2001
From: Nick Desaulniers <ndesaulniers at google.com>
Date: Wed, 6 Nov 2024 16:01:59 -0800
Subject: [PATCH 5/5] reformat
---
libc/src/__support/FPUtil/FPBits.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 2b030b51c3a8b3..45fe3485314ac2 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -134,9 +134,9 @@ template <> struct FPLayout<FPType::X86_Binary80> {
#elif __SIZEOF_LONG_DOUBLE__ == 12
using StorageType = UInt<__SIZEOF_LONG_DOUBLE__ * CHAR_BIT>;
#else
-# TODO: https://github.com/llvm/llvm-project/issues/115184
-# Android i386 uses `long double == double` i.e. `sizeof(long double) == 8`
-# https://developer.android.com/ndk/guides/abis#x86
+// TODO: https://github.com/llvm/llvm-project/issues/115184
+// Android i386 uses `long double == double` i.e. `sizeof(long double) == 8`
+// https:developer.android.com/ndk/guides/abis#x86
#error "unexpected size of long double"
#endif
LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1;
More information about the libc-commits
mailing list