Skip to content

Commit c599b8e

Browse files
authored
[libc][NFC] Decouple FP properties from C++ types (#73517)
We simplify the floating point properties by splitting concerns: - We define all distinct floating point formats in the `FPType` enum. - We map them to properties via the `FPProperties` trait. - We map from C++ type to `FPType` in the `getFPType` function so logic is easier to understand and extend.
1 parent 63a6e51 commit c599b8e

File tree

2 files changed

+48
-85
lines changed

2 files changed

+48
-85
lines changed

libc/src/__support/FPUtil/FloatProperties.h

Lines changed: 45 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,18 @@
1717
namespace LIBC_NAMESPACE {
1818
namespace fputil {
1919

20-
template <typename T> struct FloatProperties {};
20+
// The supported floating point types.
21+
enum class FPType {
22+
IEEE754_Binary16,
23+
IEEE754_Binary32,
24+
IEEE754_Binary64,
25+
IEEE754_Binary128,
26+
X86_Binary80,
27+
};
2128

22-
template <> struct FloatProperties<float> {
29+
template <FPType> struct FPProperties {};
30+
template <> struct FPProperties<FPType::IEEE754_Binary32> {
2331
typedef uint32_t BitsType;
24-
static_assert(sizeof(BitsType) == sizeof(float),
25-
"Unexpected size of 'float' type.");
2632

2733
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;
2834

@@ -46,10 +52,8 @@ template <> struct FloatProperties<float> {
4652
static constexpr BitsType QUIET_NAN_MASK = 0x00400000U;
4753
};
4854

49-
template <> struct FloatProperties<double> {
55+
template <> struct FPProperties<FPType::IEEE754_Binary64> {
5056
typedef uint64_t BitsType;
51-
static_assert(sizeof(BitsType) == sizeof(double),
52-
"Unexpected size of 'double' type.");
5357

5458
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;
5559

@@ -72,47 +76,10 @@ template <> struct FloatProperties<double> {
7276
static constexpr BitsType QUIET_NAN_MASK = 0x0008000000000000ULL;
7377
};
7478

75-
#if defined(LONG_DOUBLE_IS_DOUBLE)
76-
// Properties for numbers represented in 64 bits long double on Windows
77-
// platform.
78-
template <> struct FloatProperties<long double> {
79-
typedef uint64_t BitsType;
80-
static_assert(sizeof(BitsType) == sizeof(double),
81-
"Unexpected size of 'double' type.");
82-
83-
static constexpr uint32_t BIT_WIDTH = FloatProperties<double>::BIT_WIDTH;
84-
85-
static constexpr uint32_t MANTISSA_WIDTH =
86-
FloatProperties<double>::MANTISSA_WIDTH;
87-
static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1;
88-
static constexpr uint32_t EXPONENT_WIDTH =
89-
FloatProperties<double>::EXPONENT_WIDTH;
90-
static constexpr BitsType MANTISSA_MASK =
91-
FloatProperties<double>::MANTISSA_MASK;
92-
static constexpr BitsType SIGN_MASK = FloatProperties<double>::SIGN_MASK;
93-
static constexpr BitsType EXPONENT_MASK =
94-
FloatProperties<double>::EXPONENT_MASK;
95-
static constexpr uint32_t EXPONENT_BIAS =
96-
FloatProperties<double>::EXPONENT_BIAS;
97-
98-
static constexpr BitsType EXP_MANT_MASK =
99-
FloatProperties<double>::EXP_MANT_MASK;
100-
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
101-
"Exponent and mantissa masks are not as expected.");
102-
103-
// If a number x is a NAN, then it is a quiet NAN if:
104-
// QuietNaNMask & bits(x) != 0
105-
// Else, it is a signalling NAN.
106-
static constexpr BitsType QUIET_NAN_MASK =
107-
FloatProperties<double>::QUIET_NAN_MASK;
108-
};
109-
#elif defined(SPECIAL_X86_LONG_DOUBLE)
11079
// Properties for numbers represented in 80 bits long double on non-Windows x86
11180
// platforms.
112-
template <> struct FloatProperties<long double> {
81+
template <> struct FPProperties<FPType::X86_Binary80> {
11382
typedef UInt128 BitsType;
114-
static_assert(sizeof(BitsType) == sizeof(long double),
115-
"Unexpected size of 'long double' type.");
11683

11784
static constexpr uint32_t BIT_WIDTH = (sizeof(BitsType) * 8) - 48;
11885
static constexpr BitsType FULL_WIDTH_MASK = ((BitsType(1) << BIT_WIDTH) - 1);
@@ -143,13 +110,11 @@ template <> struct FloatProperties<long double> {
143110
static constexpr BitsType QUIET_NAN_MASK = BitsType(1)
144111
<< (MANTISSA_WIDTH - 1);
145112
};
146-
#else
113+
147114
// Properties for numbers represented in 128 bits long double on non x86
148115
// platform.
149-
template <> struct FloatProperties<long double> {
116+
template <> struct FPProperties<FPType::IEEE754_Binary128> {
150117
typedef UInt128 BitsType;
151-
static_assert(sizeof(BitsType) == sizeof(long double),
152-
"Unexpected size of 'long double' type.");
153118

154119
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) << 3;
155120

@@ -172,39 +137,39 @@ template <> struct FloatProperties<long double> {
172137
static constexpr BitsType QUIET_NAN_MASK = BitsType(1)
173138
<< (MANTISSA_WIDTH - 1);
174139
};
175-
#endif
176140

177-
#if (defined(LIBC_COMPILER_HAS_FLOAT128) && \
178-
!defined(LIBC_FLOAT128_IS_LONG_DOUBLE))
179-
// Properties for numbers represented in 128 bits long double on non x86
180-
// platform.
181-
template <> struct FloatProperties<float128> {
182-
typedef UInt128 BitsType;
183-
static_assert(sizeof(BitsType) == sizeof(float128),
184-
"Unexpected size of 'float128' type.");
185-
186-
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) << 3;
187-
188-
static constexpr uint32_t MANTISSA_WIDTH = 112;
189-
static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1;
190-
static constexpr uint32_t EXPONENT_WIDTH = 15;
191-
static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1;
192-
static constexpr BitsType SIGN_MASK = BitsType(1)
193-
<< (EXPONENT_WIDTH + MANTISSA_WIDTH);
194-
static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
195-
static constexpr uint32_t EXPONENT_BIAS = 16383;
196-
197-
static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK | EXPONENT_MASK;
198-
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
199-
"Exponent and mantissa masks are not as expected.");
141+
//-----------------------------------------------------------------------------
142+
template <typename FP> static constexpr FPType get_fp_type() {
143+
if constexpr (cpp::is_same_v<FP, float> && __FLT_MANT_DIG__ == 24)
144+
return FPType::IEEE754_Binary32;
145+
else if constexpr (cpp::is_same_v<FP, double> && __DBL_MANT_DIG__ == 53)
146+
return FPType::IEEE754_Binary64;
147+
else if constexpr (cpp::is_same_v<FP, long double>) {
148+
if constexpr (__LDBL_MANT_DIG__ == 53)
149+
return FPType::IEEE754_Binary64;
150+
else if constexpr (__LDBL_MANT_DIG__ == 64)
151+
return FPType::X86_Binary80;
152+
else if constexpr (__LDBL_MANT_DIG__ == 113)
153+
return FPType::IEEE754_Binary128;
154+
}
155+
#if defined(LIBC_COMPILER_HAS_C23_FLOAT16)
156+
else if constexpr (cpp::is_same_v<FP, _Float16>)
157+
return FPType::IEEE754_Binary16;
158+
#endif
159+
#if defined(LIBC_COMPILER_HAS_C23_FLOAT128)
160+
else if constexpr (cpp::is_same_v<FP, _Float128>)
161+
return FPType::IEEE754_Binary128;
162+
#endif
163+
#if defined(LIBC_COMPILER_HAS_FLOAT128_EXTENSION)
164+
else if constexpr (cpp::is_same_v<FP, __float128>)
165+
return FPType::IEEE754_Binary128;
166+
#endif
167+
else
168+
static_assert(cpp::always_false<FP>, "Unsupported type");
169+
}
200170

201-
// If a number x is a NAN, then it is a quiet NAN if:
202-
// QuietNaNMask & bits(x) != 0
203-
// Else, it is a signalling NAN.
204-
static constexpr BitsType QUIET_NAN_MASK = BitsType(1)
205-
<< (MANTISSA_WIDTH - 1);
206-
};
207-
#endif // LIBC_COMPILER_HAS_FLOAT128
171+
template <typename FP>
172+
struct FloatProperties : public FPProperties<get_fp_type<FP>()> {};
208173

209174
} // namespace fputil
210175
} // namespace LIBC_NAMESPACE

libc/src/__support/FPUtil/dyadic_float.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,11 @@ template <size_t Bits> struct DyadicFloat {
3838
int exponent = 0;
3939
MantissaType mantissa = MantissaType(0);
4040

41-
DyadicFloat() = default;
41+
constexpr DyadicFloat() = default;
4242

43-
template <typename T,
44-
cpp::enable_if_t<cpp::is_floating_point_v<T> &&
45-
(FloatProperties<T>::MANTISSA_WIDTH < Bits),
46-
int> = 0>
43+
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
4744
DyadicFloat(T x) {
45+
static_assert(FloatProperties<T>::MANTISSA_WIDTH < Bits);
4846
FPBits<T> x_bits(x);
4947
sign = x_bits.get_sign();
5048
exponent = x_bits.get_exponent() - FloatProperties<T>::MANTISSA_WIDTH;

0 commit comments

Comments
 (0)