Skip to content

Revert "[reland][libc][NFC] Refactor FPBits and remove LongDoubleBits specialization" #78457

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

Merged
merged 1 commit into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
487 changes: 95 additions & 392 deletions libc/src/__support/FPUtil/FPBits.h

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ LIBC_INLINE long double sqrt(long double x) {
out.set_implicit_bit(1);
out.set_mantissa((y & (ONE - 1)));

return out.get_val();
return out;
}
}
#endif // LIBC_LONG_DOUBLE_IS_X86_FLOAT80
Expand Down
179 changes: 179 additions & 0 deletions libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//===-- Bit representation of x86 long double numbers -----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_LONGDOUBLEBITS_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_LONGDOUBLEBITS_H

#include "src/__support/CPP/bit.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/properties/architectures.h"

#if !defined(LIBC_TARGET_ARCH_IS_X86)
#error "Invalid include"
#endif

#include "src/__support/FPUtil/FPBits.h"

#include <stdint.h>

namespace LIBC_NAMESPACE {
namespace fputil {

template <>
struct FPBits<long double> : public internal::FPRep<FPType::X86_Binary80> {
using UP = internal::FPRep<FPType::X86_Binary80>;
using StorageType = typename UP::StorageType;

private:
using UP::bits;
using UP::EXP_SIG_MASK;
using UP::QUIET_NAN_MASK;

public:
// Constants.
static constexpr int MAX_BIASED_EXPONENT = (1 << EXP_LEN) - 1;
// The x86 80 bit float represents the leading digit of the mantissa
// explicitly. This is the mask for that bit.
static constexpr StorageType EXPLICIT_BIT_MASK = StorageType(1)
<< FRACTION_LEN;
// The X80 significand is made of an explicit bit and the fractional part.
static_assert((EXPLICIT_BIT_MASK & FRACTION_MASK) == 0,
"the explicit bit and the fractional part should not overlap");
static_assert((EXPLICIT_BIT_MASK | FRACTION_MASK) == SIG_MASK,
"the explicit bit and the fractional part should cover the "
"whole significand");
static constexpr StorageType MIN_SUBNORMAL = StorageType(1);
// Subnormal numbers include the implicit bit in x86 long double formats.
static constexpr StorageType MAX_SUBNORMAL = FRACTION_MASK;
static constexpr StorageType MIN_NORMAL =
(StorageType(1) << SIG_LEN) | EXPLICIT_BIT_MASK;
static constexpr StorageType MAX_NORMAL =
(StorageType(MAX_BIASED_EXPONENT - 1) << SIG_LEN) | SIG_MASK;

// Constructors.
LIBC_INLINE constexpr FPBits() = default;

template <typename XType> LIBC_INLINE constexpr explicit FPBits(XType x) {
using Unqual = typename cpp::remove_cv_t<XType>;
if constexpr (cpp::is_same_v<Unqual, long double>) {
bits = cpp::bit_cast<StorageType>(x);
} else if constexpr (cpp::is_same_v<Unqual, StorageType>) {
bits = x;
} else {
// We don't want accidental type promotions/conversions, so we require
// exact type match.
static_assert(cpp::always_false<XType>);
}
}

// Floating-point conversions.
LIBC_INLINE constexpr long double get_val() const {
return cpp::bit_cast<long double>(bits);
}

LIBC_INLINE constexpr operator long double() const {
return cpp::bit_cast<long double>(bits);
}

LIBC_INLINE constexpr StorageType get_explicit_mantissa() const {
return bits & SIG_MASK;
}

LIBC_INLINE constexpr bool get_implicit_bit() const {
return bits & EXPLICIT_BIT_MASK;
}

LIBC_INLINE constexpr void set_implicit_bit(bool implicitVal) {
if (get_implicit_bit() != implicitVal)
bits ^= EXPLICIT_BIT_MASK;
}

LIBC_INLINE constexpr bool is_inf() const {
return get_biased_exponent() == MAX_BIASED_EXPONENT &&
get_mantissa() == 0 && get_implicit_bit() == 1;
}

LIBC_INLINE constexpr bool is_nan() const {
if (get_biased_exponent() == MAX_BIASED_EXPONENT) {
return (get_implicit_bit() == 0) || get_mantissa() != 0;
} else if (get_biased_exponent() != 0) {
return get_implicit_bit() == 0;
}
return false;
}

LIBC_INLINE constexpr bool is_inf_or_nan() const {
return (get_biased_exponent() == MAX_BIASED_EXPONENT) ||
(get_biased_exponent() != 0 && get_implicit_bit() == 0);
}

LIBC_INLINE constexpr bool is_quiet_nan() const {
return (bits & EXP_SIG_MASK) >= (EXP_MASK | QUIET_NAN_MASK);
}

// Methods below this are used by tests.

LIBC_INLINE static constexpr long double zero(bool sign = false) {
StorageType rep = (sign ? SIGN_MASK : StorageType(0)) // sign
| 0 // exponent
| 0 // explicit bit
| 0; // mantissa
return FPBits(rep).get_val();
}

LIBC_INLINE static constexpr long double neg_zero() { return zero(true); }

LIBC_INLINE static constexpr long double inf(bool sign = false) {
StorageType rep = (sign ? SIGN_MASK : StorageType(0)) // sign
| EXP_MASK // exponent
| EXPLICIT_BIT_MASK // explicit bit
| 0; // mantissa
return FPBits(rep).get_val();
}

LIBC_INLINE static constexpr long double neg_inf() { return inf(true); }

LIBC_INLINE static constexpr long double min_normal() {
return FPBits(MIN_NORMAL).get_val();
}

LIBC_INLINE static constexpr long double max_normal() {
return FPBits(MAX_NORMAL).get_val();
}

LIBC_INLINE static constexpr long double min_denormal() {
return FPBits(MIN_SUBNORMAL).get_val();
}

LIBC_INLINE static constexpr long double max_denormal() {
return FPBits(MAX_SUBNORMAL).get_val();
}

LIBC_INLINE static constexpr long double build_nan(StorageType v) {
StorageType rep = 0 // sign
| EXP_MASK // exponent
| EXPLICIT_BIT_MASK // explicit bit
| (v & FRACTION_MASK); // mantissa
return FPBits(rep).get_val();
}

LIBC_INLINE static constexpr long double build_quiet_nan(StorageType v) {
return build_nan(QUIET_NAN_MASK | v);
}
};

static_assert(
sizeof(FPBits<long double>) == sizeof(long double),
"Internal long double representation does not match the machine format.");

} // namespace fputil
} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_LONGDOUBLEBITS_H
8 changes: 4 additions & 4 deletions libc/src/__support/FPUtil/x86_64/NextAfterLongDouble.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
from_bits.set_biased_exponent(from_bits.get_biased_exponent() + 1);
if (from_bits.is_inf())
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
return from_bits.get_val();
return from_bits;
} else {
++int_val;
}
Expand All @@ -75,7 +75,7 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
// from == 0 is handled separately so decrementing the exponent will not
// lead to underflow.
from_bits.set_biased_exponent(from_bits.get_biased_exponent() - 1);
return from_bits.get_val();
return from_bits;
} else {
--int_val;
}
Expand All @@ -94,7 +94,7 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
// from == 0 is handled separately so decrementing the exponent will not
// lead to underflow.
from_bits.set_biased_exponent(from_bits.get_biased_exponent() - 1);
return from_bits.get_val();
return from_bits;
} else {
--int_val;
}
Expand All @@ -109,7 +109,7 @@ LIBC_INLINE long double nextafter(long double from, long double to) {
from_bits.set_biased_exponent(from_bits.get_biased_exponent() + 1);
if (from_bits.is_inf())
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
return from_bits.get_val();
return from_bits;
} else {
++int_val;
}
Expand Down
2 changes: 1 addition & 1 deletion libc/src/__support/UInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ template <size_t Bits, bool Signed> struct BigInt {
return d.borrow;
}

LIBC_INLINE constexpr BigInt<Bits, Signed>
LIBC_INLINE BigInt<Bits, Signed>
operator-(const BigInt<Bits, Signed> &other) const {
BigInt<Bits, Signed> result;
DiffBorrow<uint64_t> d{0, 0};
Expand Down
Loading