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