[libc-commits] [llvm] [libc] [libc][NFC] Refactor FPBits and remove LongDoubleBits specialization (PR #78192)
Nick Desaulniers via libc-commits
libc-commits at lists.llvm.org
Tue Jan 16 10:45:18 PST 2024
================
@@ -241,6 +347,213 @@ template <FPType fp_type> struct FPRep : public FPRepBase<fp_type> {
using UP::FRACTION_LEN;
using UP::FRACTION_MASK;
using UP::MANTISSA_PRECISION;
+
+protected:
+ using typename UP::BiasedExponent;
+ using typename UP::Exponent;
+ using typename UP::Significand;
+ using UP::biased;
+ using UP::encode;
+ using UP::exp_bits;
+ using UP::exp_sig_bits;
+ using UP::sig_bits;
+
+public:
+ LIBC_INLINE constexpr bool is_nan() const {
+ return exp_sig_bits() >
+ encode(BiasedExponent::BITS_ALL_ONES, Significand::ZERO);
+ }
+ LIBC_INLINE constexpr bool is_quiet_nan() const {
+ return exp_sig_bits() >=
+ encode(BiasedExponent::BITS_ALL_ONES, Significand::MSB);
+ }
+ LIBC_INLINE constexpr bool is_signaling_nan() const {
+ return is_nan() && !is_quiet_nan();
+ }
+ LIBC_INLINE constexpr bool is_inf() const {
+ return exp_sig_bits() ==
+ encode(BiasedExponent::BITS_ALL_ONES, Significand::ZERO);
+ }
+ LIBC_INLINE constexpr bool is_zero() const {
+ return exp_sig_bits() ==
+ encode(BiasedExponent::BITS_ALL_ZEROES, Significand::ZERO);
+ }
+ LIBC_INLINE constexpr bool is_finite() const {
+ return exp_bits() != encode(BiasedExponent::BITS_ALL_ONES);
+ }
+ LIBC_INLINE
+ constexpr bool is_subnormal() const {
+ return exp_bits() == encode(BiasedExponent::BITS_ALL_ZEROES);
+ }
+ LIBC_INLINE constexpr bool is_normal() const {
+ return is_finite() && !is_subnormal();
+ }
+
+ LIBC_INLINE static constexpr StorageType zero(bool sign = false) {
+ return encode(sign, BiasedExponent::BITS_ALL_ZEROES, Significand::ZERO);
+ }
+ LIBC_INLINE static constexpr StorageType one(bool sign = false) {
+ return encode(sign, biased(Exponent::ZERO), Significand::ZERO);
+ }
+ LIBC_INLINE static constexpr StorageType min_subnormal(bool sign = false) {
+ return encode(sign, BiasedExponent::BITS_ALL_ZEROES, Significand::LSB);
+ }
+ LIBC_INLINE static constexpr StorageType max_subnormal(bool sign = false) {
+ return encode(sign, BiasedExponent::BITS_ALL_ZEROES,
+ Significand::BITS_ALL_ONES);
+ }
+ LIBC_INLINE static constexpr StorageType min_normal(bool sign = false) {
+ return encode(sign, biased(Exponent::MIN), Significand::ZERO);
+ }
+ LIBC_INLINE static constexpr StorageType max_normal(bool sign = false) {
+ return encode(sign, biased(Exponent::MAX), Significand::BITS_ALL_ONES);
+ }
+ LIBC_INLINE static constexpr StorageType inf(bool sign = false) {
+ return encode(sign, BiasedExponent::BITS_ALL_ONES, Significand::ZERO);
+ }
+ LIBC_INLINE static constexpr StorageType build_nan(bool sign = false,
+ StorageType v = 0) {
+ return encode(sign, BiasedExponent::BITS_ALL_ONES,
+ (v ? Significand{v} : (Significand::MSB >> 1)));
+ }
+ LIBC_INLINE static constexpr StorageType build_quiet_nan(bool sign = false,
+ StorageType v = 0) {
+ return encode(sign, BiasedExponent::BITS_ALL_ONES,
+ Significand::MSB | Significand{v});
+ }
+
+ // The function return mantissa with the implicit bit set iff the current
+ // value is a valid normal number.
+ LIBC_INLINE constexpr StorageType get_explicit_mantissa() {
+ if (is_subnormal())
+ return sig_bits();
+ return (StorageType(1) << UP::SIG_LEN) | sig_bits();
+ }
+};
+
+// Specialization for the X86 Extended Precision type.
+template <>
+struct FPRep<FPType::X86_Binary80> : public FPRepBase<FPType::X86_Binary80> {
+ using UP = FPRepBase<FPType::X86_Binary80>;
+ using typename UP::StorageType;
+ using UP::FRACTION_LEN;
+ using UP::FRACTION_MASK;
+ using UP::MANTISSA_PRECISION;
+
+protected:
+ using typename UP::BiasedExponent;
+ using typename UP::Significand;
+ using UP::encode;
+
+public:
+ // 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");
+
+ LIBC_INLINE constexpr bool is_nan() const {
+ // Most encoding forms from the table found in
+ // https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format
+ // are interpreted as NaN.
+ // More precisely :
+ // - Pseudo-Infinity
+ // - Pseudo Not a Number
+ // - Signalling Not a Number
+ // - Floating-point Indefinite
+ // - Quiet Not a Number
+ // - Unnormal
+ // This can be reduced to the following logic:
+ if (exp_bits() == encode(BiasedExponent::BITS_ALL_ONES))
+ return !is_inf();
+ if (exp_bits() != encode(BiasedExponent::BITS_ALL_ZEROES))
+ return (sig_bits() & encode(Significand::MSB)) == 0;
+ return false;
+ }
+ LIBC_INLINE constexpr bool is_quiet_nan() const {
+ return exp_sig_bits() >= encode(BiasedExponent::BITS_ALL_ONES,
+ Significand::MSB | (Significand::MSB >> 1));
+ }
+ LIBC_INLINE constexpr bool is_signaling_nan() const {
+ return is_nan() && !is_quiet_nan();
+ }
+ LIBC_INLINE constexpr bool is_inf() const {
+ return exp_sig_bits() ==
+ encode(BiasedExponent::BITS_ALL_ONES, Significand::MSB);
+ }
+ LIBC_INLINE constexpr bool is_zero() const {
+ return exp_sig_bits() ==
+ encode(BiasedExponent::BITS_ALL_ZEROES, Significand::ZERO);
+ }
+ LIBC_INLINE constexpr bool is_finite() const {
+ return !is_inf() && !is_nan();
+ }
+ LIBC_INLINE
+ constexpr bool is_subnormal() const {
+ return exp_sig_bits() >
+ encode(BiasedExponent::BITS_ALL_ZEROES, Significand::ZERO);
+ }
+ LIBC_INLINE constexpr bool is_normal() const {
+ const auto exp = exp_bits();
+ if (exp == encode(BiasedExponent::BITS_ALL_ZEROES) ||
+ exp == encode(BiasedExponent::BITS_ALL_ONES))
+ return false;
+ return get_implicit_bit();
+ }
+
+ LIBC_INLINE static constexpr StorageType zero(bool sign = false) {
+ return encode(sign, BiasedExponent::BITS_ALL_ZEROES, Significand::ZERO);
+ }
+ LIBC_INLINE static constexpr StorageType one(bool sign = false) {
+ return encode(sign, biased(Exponent::ZERO), Significand::MSB);
+ }
+ LIBC_INLINE static constexpr StorageType min_subnormal(bool sign = false) {
+ return encode(sign, BiasedExponent::BITS_ALL_ZEROES, Significand::LSB);
+ }
+ LIBC_INLINE static constexpr StorageType max_subnormal(bool sign = false) {
+ return encode(sign, BiasedExponent::BITS_ALL_ZEROES,
+ Significand::BITS_ALL_ONES ^ Significand::MSB);
+ }
+ LIBC_INLINE static constexpr StorageType min_normal(bool sign = false) {
+ return encode(sign, biased(Exponent::MIN), Significand::MSB);
+ }
+ LIBC_INLINE static constexpr StorageType max_normal(bool sign = false) {
+ return encode(sign, biased(Exponent::MAX), Significand::BITS_ALL_ONES);
+ }
+ LIBC_INLINE static constexpr StorageType inf(bool sign = false) {
+ return encode(sign, BiasedExponent::BITS_ALL_ONES, Significand::MSB);
+ }
+ LIBC_INLINE static constexpr StorageType build_nan(bool sign = false,
+ StorageType v = 0) {
+ return encode(sign, BiasedExponent::BITS_ALL_ONES,
+ Significand::MSB |
+ (v ? Significand{v} : (Significand::MSB >> 2)));
+ }
+ LIBC_INLINE static constexpr StorageType build_quiet_nan(bool sign = false,
+ StorageType v = 0) {
+ return encode(sign, BiasedExponent::BITS_ALL_ONES,
+ Significand::MSB | (Significand::MSB >> 1) | Significand{v});
+ }
+
+ LIBC_INLINE constexpr StorageType get_explicit_mantissa() const {
+ return sig_bits();
+ }
+
+ // The following functions are specific to FPRep<FPType::X86_Binary80>.
+ // TODO: Remove if possible.
+ LIBC_INLINE constexpr bool get_implicit_bit() const {
+ return bits & EXPLICIT_BIT_MASK;
----------------
nickdesaulniers wrote:
adding a `static_cast<bool>()` to the expression helps. It looks like BigInt's `operator bool` is marked explicit, so it can only be used for explicit casts and not implicit casts IIUC).
https://github.com/llvm/llvm-project/pull/78192
More information about the libc-commits
mailing list