-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc][i386] FPBit support for 96b long double #115084
Conversation
@llvm/pr-subscribers-libc Author: Nick Desaulniers (nickdesaulniers) Changes
Fixes for supporting printf family of conversions for Fixes: #110894 Patch is 22.41 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/115084.diff 11 Files Affected:
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);
+ E...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
In attempting to add some math.h entrypoints, I'm hitting other compilation failures related to FPBits. Let me see if I can get those sorted, and add them to this PR. |
libc/src/__support/FPUtil/FPBits.h
Outdated
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` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should add extra android i386 condition to https://github.com/llvm/llvm-project/blob/main/libc/src/__support/macros/properties/types.h#L24, but does it mean that LDBL_MANT_DIG
for Android i386 doesn't match with double?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For android, #define __LDBL_MANT_DIG__ 53
: https://godbolt.org/z/M61Edn5c4, which falls into the first existing case.
I'm hitting an issue with 2 math tests failing at runtime (libc.src.math.ddivl, libc.src.math.fdivl). I'm not sure yet if it's a bug in this PR, or another I'm working on for saving/restoring the fpenv_t. Will diagnose more tomorrow. |
1892380
to
13f359a
Compare
`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: llvm#110894 Link: llvm#93709 Link: https://developer.android.com/ndk/guides/abis Co-authored-by: Michael Jones <michaelrj@google.com>
ae3f621
to
120eec3
Compare
force push seemed to have cleared the issue. Ready for rereview |
libc/src/__support/FPUtil/FPBits.h
Outdated
// 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that thinking more about it, I would like to dictate using UInt128
for 80-bit floating point whenever __SIZEOF_LONG_DOUBLE__ != 12
. So that when we emulate 80-bit floating points on targets other than i386, we will always use 128-bit. For Android, Windows, and MacOS where long double is double, it will be taken care of by LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE
, and so this specialization is not used for FPBits<long double>
(can you double check this?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in:
diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h
index 2994febff2f8..98e7eef90d43 100644
--- a/libc/src/__support/FPUtil/FPBits.h
+++ b/libc/src/__support/FPUtil/FPBits.h
@@ -127,7 +127,7 @@ template <> struct FPLayout<FPType::IEEE754_Binary128> {
};
template <> struct FPLayout<FPType::X86_Binary80> {
-#if __SIZEOF_LONG_DOUBLE__ == 16
+#if __SIZEOF_LONG_DOUBLE__ == 16 || __SIZEOF_LONG_DOUBLE__ == 8
using StorageType = UInt128;
#else
using StorageType = UInt<__SIZEOF_LONG_DOUBLE__ * CHAR_BIT>;
I can build android (-DLIBC_TARGET_TRIPLE=i386-linux-android
) fine with that change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as:
#if __SIZEOF_LONG_DOUBLE__ == 12
using StorageType = UInt<__SIZEOF_LONG_DOUBLE__ * CHAR_BIT>;
#else
using StorageType = UInt128;
#endif
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done in ab6deee PTAL
After llvm#115084 the 80 bit long double tests error if sizeof(long double) isn't 96 or 128 bits. This caused failures in long double is double systems (since long double is 64 bits) so I've disabled the 80 bit long double tests on systems that don't use them.
After #115084 the 80 bit long double tests error if sizeof(long double) isn't 96 or 128 bits. This caused failures in long double is double systems (since long double is 64 bits) so I've disabled the 80 bit long double tests on systems that don't use them.
long double
is haunted on most architectures, but it is especially so oni386-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
oni386-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@google.com