Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions libc/src/__support/FPUtil/FPBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,18 @@ 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
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
Copy link
Contributor

@lntue lntue Nov 11, 2024

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?).

Copy link
Member Author

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.

Copy link
Contributor

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in ab6deee PTAL

#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;
LIBC_INLINE_VAR static constexpr int SIG_LEN = 64;
Expand Down
3 changes: 2 additions & 1 deletion libc/src/__support/FPUtil/generic/sqrt_80_bit_long_double.h
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
10 changes: 9 additions & 1 deletion libc/src/__support/big_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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>();
}
Expand Down Expand Up @@ -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
Expand Down
17 changes: 3 additions & 14 deletions libc/src/__support/float_to_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
4 changes: 4 additions & 0 deletions libc/src/__support/integer_literals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
14 changes: 7 additions & 7 deletions libc/src/__support/str_to_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 =
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion libc/test/UnitTest/LibcTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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>);
Expand Down
Loading
Loading