[libc][i386] FPBit support for 96b long double (#115084) `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 Co-authored-by: Michael Jones <michaelrj@google.com> GitOrigin-RevId: 7302c8dbe71b7c03b73a35a21fa4b415fa1f4505
diff --git a/src/__support/FPUtil/FPBits.h b/src/__support/FPUtil/FPBits.h index 6da8909..90b6e40 100644 --- a/src/__support/FPUtil/FPBits.h +++ b/src/__support/FPUtil/FPBits.h
@@ -127,7 +127,11 @@ }; template <> struct FPLayout<FPType::X86_Binary80> { +#if __SIZEOF_LONG_DOUBLE__ == 12 + using StorageType = UInt<__SIZEOF_LONG_DOUBLE__ * CHAR_BIT>; +#else using StorageType = UInt128; +#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/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h b/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h index 053348d..9492d52 100644 --- a/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h +++ b/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
@@ -21,7 +21,8 @@ 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/src/__support/big_int.h b/src/__support/big_int.h index bea0abc..a95ab4f 100644 --- a/src/__support/big_int.h +++ b/src/__support/big_int.h
@@ -469,7 +469,7 @@ !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 @@ // 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 @@ // 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/src/__support/float_to_string.h b/src/__support/float_to_string.h index e2e06cd..d5de6f3 100644 --- a/src/__support/float_to_string.h +++ b/src/__support/float_to_string.h
@@ -373,23 +373,12 @@ 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/src/__support/integer_literals.h b/src/__support/integer_literals.h index af3da1c..4c5c4c4 100644 --- a/src/__support/integer_literals.h +++ b/src/__support/integer_literals.h
@@ -165,6 +165,10 @@ } // 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/src/__support/str_to_float.h b/src/__support/str_to_float.h index a1f4eef..80ea334 100644 --- a/src/__support/str_to_float.h +++ b/src/__support/str_to_float.h
@@ -206,7 +206,7 @@ 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 @@ } // 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 @@ // 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 @@ } ExpandedFloat<long double> output; - output.mantissa = final_mantissa; + output.mantissa = static_cast<StorageType>(final_mantissa); output.exponent = exp2; return output; } @@ -558,7 +558,7 @@ 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/test/UnitTest/LibcTest.cpp b/test/UnitTest/LibcTest.cpp index ad5722f..afb1368 100644 --- a/test/UnitTest/LibcTest.cpp +++ b/test/UnitTest/LibcTest.cpp
@@ -44,7 +44,6 @@ 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(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/test/src/__support/FPUtil/fpbits_test.cpp b/test/src/__support/FPUtil/fpbits_test.cpp index bcab028..edb04c2 100644 --- a/test/src/__support/FPUtil/fpbits_test.cpp +++ b/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::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_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 @@ 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 @@ 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 @@ #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 @@ 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/test/src/__support/big_int_test.cpp b/test/src/__support/big_int_test.cpp index 471ca72..2666ed9 100644 --- a/test/src/__support/big_int_test.cpp +++ b/test/src/__support/big_int_test.cpp
@@ -1067,4 +1067,12 @@ 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), int64_t(-123)); +} + } // namespace LIBC_NAMESPACE_DECL
diff --git a/test/src/__support/str_to_long_double_test.cpp b/test/src/__support/str_to_long_double_test.cpp index 9efa457..fa7d600 100644 --- a/test/src/__support/str_to_long_double_test.cpp +++ b/test/src/__support/str_to_long_double_test.cpp
@@ -30,12 +30,23 @@ } 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/test/src/math/smoke/CanonicalizeTest.h b/test/src/math/smoke/CanonicalizeTest.h index 3baf60c..f22a282 100644 --- a/test/src/math/smoke/CanonicalizeTest.h +++ b/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 @@ // 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 @@ // 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 @@ // 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 @@ // | 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 @@ // | 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);
diff --git a/test/src/stdlib/strtold_test.cpp b/test/src/stdlib/strtold_test.cpp index 2c9f542..b209c85 100644 --- a/test/src/stdlib/strtold_test.cpp +++ b/test/src/stdlib/strtold_test.cpp
@@ -75,8 +75,9 @@ // +-- 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;