diff --git a/libc/src/__support/FPUtil/FloatProperties.h b/libc/src/__support/FPUtil/FloatProperties.h index 59e261e1047f1..4288cd719a1d8 100644 --- a/libc/src/__support/FPUtil/FloatProperties.h +++ b/libc/src/__support/FPUtil/FloatProperties.h @@ -10,7 +10,7 @@ #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FLOATPROPERTIES_H #include "src/__support/UInt128.h" -#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR #include "src/__support/macros/properties/float.h" // LIBC_COMPILER_HAS_FLOAT128 #include @@ -27,22 +27,98 @@ enum class FPType { X86_Binary80, }; -template struct FPProperties {}; -template <> struct FPProperties { - typedef uint32_t BitsType; +// For now 'FPEncoding', 'FPBaseProperties' and 'FPCommonProperties' are +// implementation details. +namespace internal { + +// The type of encoding for supported floating point types. +enum class FPEncoding { + IEEE754, + X86_ExtendedPrecision, +}; + +template struct FPBaseProperties {}; + +template <> struct FPBaseProperties { + 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; +}; + +template <> struct FPBaseProperties { + 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; +}; + +template <> struct FPBaseProperties { + 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; +}; + +template <> struct FPBaseProperties { + 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; +}; + +template <> struct FPBaseProperties { + 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; +}; + +// Derives more properties from 'FPBaseProperties' above. +// This class serves as a halfway point between 'FPBaseProperties' and +// 'FPProperties' below. +template +struct FPCommonProperties : private FPBaseProperties { + using UP = FPBaseProperties; + using BitsType = typename UP::UIntType; + + 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; + + // 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); +}; + +} // namespace internal - static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8; +template struct FPProperties {}; - static constexpr uint32_t MANTISSA_WIDTH = 23; +// ---------------- +// Work In Progress +// ---------------- +// The 'FPProperties' template specializations below are being slowly replaced +// with properties from 'FPCommonProperties' above. Once specializations are +// empty, 'FPProperties' declaration can be fully replace with +// 'FPCommonProperties' implementation. + +template <> +struct FPProperties + : public internal::FPCommonProperties { // 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."); @@ -53,20 +129,14 @@ template <> struct FPProperties { static constexpr BitsType QUIET_NAN_MASK = 0x00400000U; }; -template <> struct FPProperties { - typedef uint64_t BitsType; - - static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8; - - static constexpr uint32_t MANTISSA_WIDTH = 52; +template <> +struct FPProperties + : public internal::FPCommonProperties { 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; - 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."); @@ -79,27 +149,20 @@ template <> struct FPProperties { // Properties for numbers represented in 80 bits long double on non-Windows x86 // platforms. -template <> struct FPProperties { - typedef UInt128 BitsType; - - static constexpr uint32_t BIT_WIDTH = (sizeof(BitsType) * 8) - 48; +template <> +struct FPProperties + : public internal::FPCommonProperties { static constexpr BitsType FULL_WIDTH_MASK = ((BitsType(1) << BIT_WIDTH) - 1); - 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; - // 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); - 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; - static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK | EXPLICIT_BIT_MASK | EXPONENT_MASK; static_assert(EXP_MANT_MASK == (~SIGN_MASK & FULL_WIDTH_MASK), @@ -114,20 +177,14 @@ template <> struct FPProperties { // Properties for numbers represented in 128 bits long double on non x86 // platform. -template <> struct FPProperties { - typedef UInt128 BitsType; - - static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) << 3; - - static constexpr uint32_t MANTISSA_WIDTH = 112; +template <> +struct FPProperties + : public internal::FPCommonProperties { 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; 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 = 16383; - 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.");