[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>
This commit is contained in:
Nick Desaulniers
2024-11-12 08:19:47 -08:00
committed by GitHub
parent 0d2ef7af19
commit 7302c8dbe7
12 changed files with 266 additions and 31 deletions

View File

@@ -127,7 +127,11 @@ template <> struct FPLayout<FPType::IEEE754_Binary128> {
};
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;

View File

@@ -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));

View File

@@ -469,7 +469,7 @@ public:
!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 @@ public:
// 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

View File

@@ -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());

View File

@@ -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);
}

View File

@@ -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));

View File

@@ -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>);

View File

@@ -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);

View File

@@ -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), int64_t(-123));
}
} // namespace LIBC_NAMESPACE_DECL

View File

@@ -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.

View File

@@ -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 @@ public:
// 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 @@ public:
// 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 @@ public:
// 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 @@ public:
// | 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 @@ public:
// | 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);

View File

@@ -75,8 +75,9 @@ public:
// +-- 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;