[libc] [llvm] [libc][NFC] Refactor FPBits and remove LongDoubleBits specialization (PR #78192)

Nick Desaulniers via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 16 10:35:00 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:

32b arm build bot failure here:
```
In file included from /llvm/ndesaulniers/llvm-project/libc/src/fenv/fegetround.cpp:10:
In file included from /llvm/ndesaulniers/llvm-project/libc/src/__support/FPUtil/FEnvImpl.h:33:
In file included from /llvm/ndesaulniers/llvm-project/libc/src/__support/FPUtil/arm/FEnvImpl.h:12:
/llvm/ndesaulniers/llvm-project/libc/src/__support/FPUtil/FPBits.h:550:12: error: no viable conversion from returned value of type 'BigInt<128U, false>' to function return type 'bool'
    return bits & EXPLICIT_BIT_MASK;
           ^~~~~~~~~~~~~~~~~~~~~~~~
/llvm/ndesaulniers/llvm-project/libc/src/__support/UInt.h:106:56: note: explicit conversion function is not a candidate
  template <typename T> LIBC_INLINE constexpr explicit operator T() const {
                                                       ^
/llvm/ndesaulniers/llvm-project/libc/src/__support/UInt.h:135:34: note: explicit conversion function is not a candidate
  LIBC_INLINE constexpr explicit operator bool() const { return !is_zero(); }
                                 ^
```

https://github.com/llvm/llvm-project/pull/78192


More information about the llvm-commits mailing list