[libc-commits] [libc] [libc][NFC] Simplify FloatProperties implementation (PR #74821)
via libc-commits
libc-commits at lists.llvm.org
Fri Dec 8 09:50:32 PST 2023
================
@@ -27,116 +27,173 @@ enum class FPType {
X86_Binary80,
};
-template <FPType> struct FPProperties {};
-template <> struct FPProperties<FPType::IEEE754_Binary32> {
- typedef uint32_t BitsType;
+// For now 'FPEncoding', 'FPBaseProperties' and 'FPCommonProperties' are
+// implementation details.
+namespace internal {
- static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;
-
- static constexpr uint32_t MANTISSA_WIDTH = 23;
- // The mantissa precision includes the implicit bit.
- static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1;
- static constexpr uint32_t EXPONENT_WIDTH = 8;
- static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1;
- static constexpr BitsType SIGN_MASK = BitsType(1)
- << (EXPONENT_WIDTH + MANTISSA_WIDTH);
- static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
- static constexpr uint32_t EXPONENT_BIAS = 127;
-
- static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK;
- static_assert(EXP_MANT_MASK == ~SIGN_MASK,
- "Exponent and mantissa masks are not as expected.");
-
- // If a number x is a NAN, then it is a quiet NAN if:
- // QuietNaNMask & bits(x) != 0
- // Else, it is a signalling NAN.
- static constexpr BitsType QUIET_NAN_MASK = 0x00400000U;
+// The type of encoding for supported floating point types.
+enum class FPEncoding {
+ IEEE754,
+ X86_ExtendedPrecision,
};
-template <> struct FPProperties<FPType::IEEE754_Binary64> {
- typedef uint64_t BitsType;
-
- static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;
-
- static constexpr uint32_t MANTISSA_WIDTH = 52;
- static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1;
- static constexpr uint32_t EXPONENT_WIDTH = 11;
- static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1;
- static constexpr BitsType SIGN_MASK = BitsType(1)
- << (EXPONENT_WIDTH + MANTISSA_WIDTH);
- static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
- static constexpr uint32_t EXPONENT_BIAS = 1023;
+template <FPType> struct FPBaseProperties {};
- static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK;
- static_assert(EXP_MANT_MASK == ~SIGN_MASK,
- "Exponent and mantissa masks are not as expected.");
+template <> struct FPBaseProperties<FPType::IEEE754_Binary16> {
+ using UIntType = uint16_t;
+ LIBC_INLINE_VAR static constexpr int TOTAL_BITS = 16;
+ LIBC_INLINE_VAR static constexpr int SIG_BITS = 10;
+ LIBC_INLINE_VAR static constexpr int EXP_BITS = 5;
+ LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
+};
- // If a number x is a NAN, then it is a quiet NAN if:
- // QuietNaNMask & bits(x) != 0
- // Else, it is a signalling NAN.
- static constexpr BitsType QUIET_NAN_MASK = 0x0008000000000000ULL;
+template <> struct FPBaseProperties<FPType::IEEE754_Binary32> {
+ using UIntType = uint32_t;
+ LIBC_INLINE_VAR static constexpr int TOTAL_BITS = 32;
+ LIBC_INLINE_VAR static constexpr int SIG_BITS = 23;
+ LIBC_INLINE_VAR static constexpr int EXP_BITS = 8;
+ LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
};
-// Properties for numbers represented in 80 bits long double on non-Windows x86
-// platforms.
-template <> struct FPProperties<FPType::X86_Binary80> {
- typedef UInt128 BitsType;
+template <> struct FPBaseProperties<FPType::IEEE754_Binary64> {
+ using UIntType = uint64_t;
+ LIBC_INLINE_VAR static constexpr int TOTAL_BITS = 64;
+ LIBC_INLINE_VAR static constexpr int SIG_BITS = 52;
+ LIBC_INLINE_VAR static constexpr int EXP_BITS = 11;
+ LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
+};
- static constexpr uint32_t BIT_WIDTH = (sizeof(BitsType) * 8) - 48;
- static constexpr BitsType FULL_WIDTH_MASK = ((BitsType(1) << BIT_WIDTH) - 1);
+template <> struct FPBaseProperties<FPType::IEEE754_Binary128> {
+ using UIntType = UInt128;
+ LIBC_INLINE_VAR static constexpr int TOTAL_BITS = 128;
+ LIBC_INLINE_VAR static constexpr int SIG_BITS = 112;
+ LIBC_INLINE_VAR static constexpr int EXP_BITS = 15;
+ LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
+};
- static constexpr uint32_t MANTISSA_WIDTH = 63;
- static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1;
- static constexpr uint32_t EXPONENT_WIDTH = 15;
- static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1;
+template <> struct FPBaseProperties<FPType::X86_Binary80> {
+ using UIntType = UInt128;
+ LIBC_INLINE_VAR static constexpr int TOTAL_BITS = 80;
+ LIBC_INLINE_VAR static constexpr int SIG_BITS = 64;
+ LIBC_INLINE_VAR static constexpr int EXP_BITS = 15;
+ LIBC_INLINE_VAR static constexpr auto ENCODING =
+ FPEncoding::X86_ExtendedPrecision;
+};
- // The x86 80 bit float represents the leading digit of the mantissa
- // explicitly. This is the mask for that bit.
- static constexpr BitsType EXPLICIT_BIT_MASK = (BitsType(1) << MANTISSA_WIDTH);
+// 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));
+}
- static constexpr BitsType SIGN_MASK =
- BitsType(1) << (EXPONENT_WIDTH + MANTISSA_WIDTH + 1);
- static constexpr BitsType EXPONENT_MASK =
- ((BitsType(1) << EXPONENT_WIDTH) - 1) << (MANTISSA_WIDTH + 1);
- static constexpr uint32_t EXPONENT_BIAS = 16383;
+// 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 UP::EXP_BITS;
+ using UP::SIG_BITS;
+ using UP::TOTAL_BITS;
+ using UIntType = typename UP::UIntType;
+
+ 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 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_ =
----------------
lntue wrote:
nit: it's a little odd to have extra `_` trailing with `SIGN_MASK`, but not with other `*_MASK`.
https://github.com/llvm/llvm-project/pull/74821
More information about the libc-commits
mailing list