[libc-commits] [libc] [libc][NFC] Simplify FloatProperties implementation #2 (PR #74821)

via libc-commits libc-commits at lists.llvm.org
Fri Dec 8 06:46:21 PST 2023


================
@@ -80,27 +80,96 @@ template <> struct FPBaseProperties<FPType::X86_Binary80> {
       FPEncoding::X86_ExtendedPrecision;
 };
 
+// TODO: Move this utility elsewhere.
+template <typename T, size_t count> static constexpr T mask_trailing_ones() {
+  static_assert(cpp::is_unsigned_v<T>);
+  constexpr unsigned t_bits = CHAR_BIT * sizeof(T);
+  static_assert(count <= t_bits && "Invalid bit index");
+  return count == 0 ? 0 : (T(-1) >> (t_bits - count));
+}
+
 // Derives more properties from 'FPBaseProperties' above.
 // This class serves as a halfway point between 'FPBaseProperties' and
 // 'FPProperties' below.
 template <FPType fp_type>
 struct FPCommonProperties : private FPBaseProperties<fp_type> {
+private:
   using UP = FPBaseProperties<fp_type>;
-  using BitsType = typename UP::UIntType;
+  using UP::EXP_BITS;
+  using UP::SIG_BITS;
+  using UP::TOTAL_BITS;
+  using UIntType = typename UP::UIntType;
+
+  LIBC_INLINE_VAR static constexpr bool HAS_EXPLICIT_SIG_BIT =
+      UP::ENCODING == FPEncoding::X86_ExtendedPrecision;
+  LIBC_INLINE_VAR static constexpr int EXPLICIT_SIG_BITS =
+      HAS_EXPLICIT_SIG_BIT ? 1 : 0;
 
-  LIBC_INLINE_VAR static constexpr uint32_t BIT_WIDTH = UP::TOTAL_BITS;
-  LIBC_INLINE_VAR static constexpr uint32_t MANTISSA_WIDTH = UP::SIG_BITS;
-  LIBC_INLINE_VAR static constexpr uint32_t EXPONENT_WIDTH = UP::EXP_BITS;
+  LIBC_INLINE_VAR static constexpr int STORAGE_BITS =
+      sizeof(UIntType) * CHAR_BIT;
+  static_assert(STORAGE_BITS >= TOTAL_BITS);
+
+  // The number of bits to represent sign.
+  // For documentation purpose, always 1.
+  LIBC_INLINE_VAR static constexpr int SIGN_BITS = 1;
+  static_assert(SIGN_BITS + EXP_BITS + SIG_BITS == TOTAL_BITS);
 
   // The exponent bias. Always positive.
-  LIBC_INLINE_VAR static constexpr uint32_t EXPONENT_BIAS =
-      (1U << (UP::EXP_BITS - 1U)) - 1U;
-  static_assert(EXPONENT_BIAS > 0);
+  LIBC_INLINE_VAR static constexpr int32_t EXP_BIAS =
+      (1U << (EXP_BITS - 1U)) - 1U;
+  static_assert(EXP_BIAS > 0);
+
+  // Shifts
+  LIBC_INLINE_VAR static constexpr int SIG_MASK_SHIFT = 0;
+  LIBC_INLINE_VAR static constexpr int EXP_MASK_SHIFT = SIG_BITS;
+  LIBC_INLINE_VAR static constexpr int SIGN_MASK_SHIFT = SIG_BITS + EXP_BITS;
+
+  // Masks
+  LIBC_INLINE_VAR static constexpr UIntType SIG_MASK =
+      mask_trailing_ones<UIntType, SIG_BITS>() << SIG_MASK_SHIFT;
+  LIBC_INLINE_VAR static constexpr UIntType EXP_MASK =
+      mask_trailing_ones<UIntType, EXP_BITS>() << EXP_MASK_SHIFT;
+  LIBC_INLINE_VAR static constexpr UIntType SIGN_MASK_ =
+      mask_trailing_ones<UIntType, SIGN_BITS>() << SIGN_MASK_SHIFT;
+  LIBC_INLINE_VAR static constexpr UIntType FP_MASK =
+      mask_trailing_ones<UIntType, TOTAL_BITS>();
+  static_assert((SIG_MASK & EXP_MASK & SIGN_MASK_) == 0, "masks disjoint");
+  static_assert((SIG_MASK | EXP_MASK | SIGN_MASK_) == FP_MASK, "masks covers");
+
+  //
+  LIBC_INLINE_VAR static constexpr int FRACTION_BITS =
+      SIG_BITS - EXPLICIT_SIG_BITS;
+  LIBC_INLINE_VAR static constexpr UIntType QNAN_MASK = UIntType(1)
----------------
lntue wrote:

I think in order for `QNAN` and `SNAN` work for both IEEE 754 and X86_FLOAT80,  `QNAN_MASK` should be `(1 << SIGN_MASK_SHIFT) - (1 << (MANTISSA_WIDTH - 1))` and `SNAN_MASK = (1 << SIGN_MASK_SHIFT) - (1 << MANTISSA_WIDTH)`.  Then the detection is
```
is_quiet_nan(x) = ((bits(x) & QNAN_MASK) == QNAN_MASK)
is_signaling_nan = ((bits(x) & QNAN_MASK) == SNAN_MASK)
```


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


More information about the libc-commits mailing list