From 3ee8097102b7632d3e7858d0a8ce92719d01e0ba Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 31 Oct 2024 13:52:03 -0700 Subject: [PATCH 1/8] [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 --- 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 6548c9b816c93..3a1952aeaa4e9 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 6da89091a8ced..2994febff2f8a 100644 --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -127,7 +127,11 @@ template <> struct FPLayout { }; template <> struct FPLayout { +#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 053348d4c975d..9492d52da0455 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::StorageType &mantissa) { const unsigned int shift = static_cast( cpp::countl_zero(static_cast(mantissa)) - (8 * sizeof(uint64_t) - 1 - FPBits::FRACTION_LEN)); diff --git a/libc/src/__support/big_int.h b/libc/src/__support/big_int.h index bea0abc84b213..a95ab4ff8e1ab 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>> 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 + LIBC_INLINE constexpr explicit + operator BigInt() const { + return BigInt(this); + } + template LIBC_INLINE constexpr explicit operator T() const { return to(); } @@ -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 {}; template <> struct WordTypeSelector<32> : cpp::type_identity {}; +template <> struct WordTypeSelector<96> : cpp::type_identity {}; + template using WordTypeSelectorT = typename WordTypeSelector::type; } // namespace internal diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h index e2e06cd0492a9..d5de6f38cb655 100644 --- a/libc/src/__support/float_to_string.h +++ b/libc/src/__support/float_to_string.h @@ -373,23 +373,12 @@ LIBC_INLINE UInt get_table_negative_df(int exponent, size_t i) { return result; } -LIBC_INLINE uint32_t fast_uint_mod_1e9(const UInt &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 mult_const( - {0x31680A88F8953031u, 0x89705F4136B4A597u, 0}); - const auto middle = (mult_const * val); - const uint64_t result = static_cast(middle[2]); - const uint64_t shifted = result >> 29; - return static_cast(static_cast(val) - - (EXP10_9 * shifted)); -} - LIBC_INLINE uint32_t mul_shift_mod_1e9(const FPBits::StorageType mantissa, const UInt &large, const int32_t shift_amount) { - UInt val(large); + // make sure the number of bits is always divisible by 64 + UInt val( + large); val = (val * mantissa) >> shift_amount; return static_cast( val.div_uint_half_times_pow_2(static_cast(EXP10_9), 0).value()); diff --git a/libc/src/__support/integer_literals.h b/libc/src/__support/integer_literals.h index af3da1c443d7b..4c5c4c4166681 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>(x); +} + LIBC_INLINE constexpr UInt128 operator""_u128(const char *x) { return internal::parse_with_prefix(x); } diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h index a1f4eef03fc3c..80ea334d15c03 100644 --- a/libc/src/__support/str_to_float.h +++ b/libc/src/__support/str_to_float.h @@ -206,7 +206,7 @@ eisel_lemire(ExpandedFloat init_num, using FPBits = typename fputil::FPBits; 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(ExpandedFloat init_num, } // Normalization - uint32_t clz = cpp::countl_zero(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(ExpandedFloat init_num, // Shifting to 65 bits for 80 bit floats and 113 bits for 128 bit floats uint32_t msb = static_cast(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(1 ^ msb); // same as !msb if (round == RoundDirection::Nearest) { @@ -315,7 +315,7 @@ eisel_lemire(ExpandedFloat init_num, } ExpandedFloat output; - output.mantissa = final_mantissa; + output.mantissa = static_cast(final_mantissa); output.exponent = exp2; return output; } @@ -558,7 +558,7 @@ clinger_fast_path(ExpandedFloat init_num, FPBits result; T float_mantissa; - if constexpr (cpp::is_same_v>) { + if constexpr (is_big_int_v || sizeof(T) > sizeof(uint64_t)) { float_mantissa = (static_cast(uint64_t(mantissa >> 64)) * static_cast(0x1.0p64)) + static_cast(uint64_t(mantissa)); diff --git a/libc/test/UnitTest/LibcTest.cpp b/libc/test/UnitTest/LibcTest.cpp index ad5722f99a436..afb1368f00905 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 && (sizeof(T) > sizeof(uint64_t))) || is_big_int_v, cpp::string> describeValue(T Value) { - static_assert(sizeof(T) % 8 == 0, "Unsupported size of UInt"); const IntegerToString 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 bcab0286480c3..edb04c24ae387 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; +#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; +#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; + using Rep = FPRep; 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 9efa457aac957..fa7d600f9bff4 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 2c9f542930bf8..b209c85b88e36 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 expected_fp = - LIBC_NAMESPACE::fputil::FPBits(expectedRawData); + using FPBits = LIBC_NAMESPACE::fputil::FPBits; + FPBits expected_fp = + FPBits(static_cast(expectedRawData)); const int expected_errno = expectedErrno; LIBC_NAMESPACE::libc_errno = 0; From c4cc557f9252a84b1fe501778643382b0e44d1d8 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Wed, 6 Nov 2024 10:44:54 -0800 Subject: [PATCH 2/8] 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 471ca72a8f6e0..02dd9ff70f942 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 4947d04b104c38a30dc9d25c6b0b41a3d8a1c312 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Wed, 6 Nov 2024 10:45:11 -0800 Subject: [PATCH 3/8] 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 2994febff2f8a..2b030b51c3a8b 100644 --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -127,10 +127,17 @@ template <> struct FPLayout { }; template <> struct FPLayout { +// 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 16df423f182b7d95172b9045814359b2d6a44c86 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Wed, 6 Nov 2024 12:18:19 -0800 Subject: [PATCH 4/8] 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 3a1952aeaa4e9..062b042ec7826 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 3baf60c3140ff..f22a282b1843b 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 @@ -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 26011ad6493b3e82f34048b837fc06a545091b0e Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Wed, 6 Nov 2024 16:01:59 -0800 Subject: [PATCH 5/8] 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 2b030b51c3a8b..081b7073cf1c0 100644 --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -134,9 +134,9 @@ template <> struct FPLayout { #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; From 3cec2cfc7fbb76b11500cda9a34fb23b03c3fad5 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 7 Nov 2024 08:40:40 -0800 Subject: [PATCH 6/8] remove entrypoints, they still depend on my other fenv_t patches --- libc/config/linux/i386/entrypoints.txt | 316 +------------------------ 1 file changed, 1 insertion(+), 315 deletions(-) diff --git a/libc/config/linux/i386/entrypoints.txt b/libc/config/linux/i386/entrypoints.txt index 062b042ec7826..6548c9b816c93 100644 --- a/libc/config/linux/i386/entrypoints.txt +++ b/libc/config/linux/i386/entrypoints.txt @@ -1,323 +1,9 @@ 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 - # 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_LIBM_ENTRYPOINTS "") set(TARGET_LLVMLIBC_ENTRYPOINTS ${TARGET_LIBC_ENTRYPOINTS} From 120eec37b4bef20460af221f44d906eba5230889 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 7 Nov 2024 08:41:48 -0800 Subject: [PATCH 7/8] fix up new test case for fp64 --- libc/test/src/__support/big_int_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libc/test/src/__support/big_int_test.cpp b/libc/test/src/__support/big_int_test.cpp index 02dd9ff70f942..2666ed978dad7 100644 --- a/libc/test/src/__support/big_int_test.cpp +++ b/libc/test/src/__support/big_int_test.cpp @@ -1072,7 +1072,7 @@ TEST(LlvmLibcUIntClassTest, MixedSignednessOtherWordTypeCastTests) { 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); + ASSERT_EQ(int64_t(x), int64_t(-123)); } } // namespace LIBC_NAMESPACE_DECL From ab6deee4f4e15b7163dcf72e032b3137ba6b170d Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Mon, 11 Nov 2024 14:52:09 -0800 Subject: [PATCH 8/8] only use __SIZEOF_LONG_DOUBLE__ when it's 12 --- libc/src/__support/FPUtil/FPBits.h | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h index 081b7073cf1c0..90b6e406e0f31 100644 --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -127,17 +127,10 @@ template <> struct FPLayout { }; template <> struct FPLayout { -// x86_64 -#if __SIZEOF_LONG_DOUBLE__ == 16 - using StorageType = UInt128; -// i386-linux-gnu -#elif __SIZEOF_LONG_DOUBLE__ == 12 +#if __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" + using StorageType = UInt128; #endif LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1; LIBC_INLINE_VAR static constexpr int EXP_LEN = 15;