@@ -39,64 +39,66 @@ enum class FPEncoding {
39
39
X86_ExtendedPrecision,
40
40
};
41
41
42
- template <FPType> struct FPBaseProperties {};
42
+ // Defines the layout (sign, exponent, significand) of a floating point type in
43
+ // memory. It also defines its associated StorageType, i.e., the unsigned
44
+ // integer type used to manipulate its representation.
45
+ template <FPType> struct FPLayout {};
43
46
44
- template <> struct FPBaseProperties <FPType::IEEE754_Binary16> {
47
+ template <> struct FPLayout <FPType::IEEE754_Binary16> {
45
48
using StorageType = uint16_t ;
46
- LIBC_INLINE_VAR static constexpr int TOTAL_LEN = 16 ;
47
- LIBC_INLINE_VAR static constexpr int SIG_LEN = 10 ;
49
+ LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1 ;
48
50
LIBC_INLINE_VAR static constexpr int EXP_LEN = 5 ;
51
+ LIBC_INLINE_VAR static constexpr int SIG_LEN = 10 ;
49
52
LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
50
53
};
51
54
52
- template <> struct FPBaseProperties <FPType::IEEE754_Binary32> {
55
+ template <> struct FPLayout <FPType::IEEE754_Binary32> {
53
56
using StorageType = uint32_t ;
54
- LIBC_INLINE_VAR static constexpr int TOTAL_LEN = 32 ;
55
- LIBC_INLINE_VAR static constexpr int SIG_LEN = 23 ;
57
+ LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1 ;
56
58
LIBC_INLINE_VAR static constexpr int EXP_LEN = 8 ;
59
+ LIBC_INLINE_VAR static constexpr int SIG_LEN = 23 ;
57
60
LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
58
61
};
59
62
60
- template <> struct FPBaseProperties <FPType::IEEE754_Binary64> {
63
+ template <> struct FPLayout <FPType::IEEE754_Binary64> {
61
64
using StorageType = uint64_t ;
62
- LIBC_INLINE_VAR static constexpr int TOTAL_LEN = 64 ;
63
- LIBC_INLINE_VAR static constexpr int SIG_LEN = 52 ;
65
+ LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1 ;
64
66
LIBC_INLINE_VAR static constexpr int EXP_LEN = 11 ;
67
+ LIBC_INLINE_VAR static constexpr int SIG_LEN = 52 ;
65
68
LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
66
69
};
67
70
68
- template <> struct FPBaseProperties <FPType::IEEE754_Binary128> {
71
+ template <> struct FPLayout <FPType::IEEE754_Binary128> {
69
72
using StorageType = UInt128;
70
- LIBC_INLINE_VAR static constexpr int TOTAL_LEN = 128 ;
71
- LIBC_INLINE_VAR static constexpr int SIG_LEN = 112 ;
73
+ LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1 ;
72
74
LIBC_INLINE_VAR static constexpr int EXP_LEN = 15 ;
75
+ LIBC_INLINE_VAR static constexpr int SIG_LEN = 112 ;
73
76
LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
74
77
};
75
78
76
- template <> struct FPBaseProperties <FPType::X86_Binary80> {
79
+ template <> struct FPLayout <FPType::X86_Binary80> {
77
80
using StorageType = UInt128;
78
- LIBC_INLINE_VAR static constexpr int TOTAL_LEN = 80 ;
79
- LIBC_INLINE_VAR static constexpr int SIG_LEN = 64 ;
81
+ LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1 ;
80
82
LIBC_INLINE_VAR static constexpr int EXP_LEN = 15 ;
83
+ LIBC_INLINE_VAR static constexpr int SIG_LEN = 64 ;
81
84
LIBC_INLINE_VAR static constexpr auto ENCODING =
82
85
FPEncoding::X86_ExtendedPrecision;
83
86
};
84
87
85
88
} // namespace internal
86
89
90
+ // FPBaseMasksAndShifts derives useful constants from the FPLayout.
87
91
template <FPType fp_type>
88
- struct FPProperties : public internal ::FPBaseProperties <fp_type> {
92
+ struct FPBaseMasksAndShifts : public internal ::FPLayout <fp_type> {
89
93
private:
90
- using UP = internal::FPBaseProperties <fp_type>;
94
+ using UP = internal::FPLayout <fp_type>;
91
95
92
96
public:
93
- // The number of bits to represent sign. For documentation purpose, always 1.
94
- LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1 ;
95
- using UP::EXP_LEN; // The number of bits for the *exponent* part
96
- using UP::SIG_LEN; // The number of bits for the *significand* part
97
- using UP::TOTAL_LEN; // For convenience, the sum of `SIG_LEN`, `EXP_LEN`,
98
- // and `SIGN_LEN`.
99
- static_assert (SIGN_LEN + EXP_LEN + SIG_LEN == TOTAL_LEN);
97
+ using UP::EXP_LEN; // The number of bits for the *exponent* part
98
+ using UP::SIG_LEN; // The number of bits for the *significand* part
99
+ using UP::SIGN_LEN; // The number of bits for the *sign* part
100
+ // For convenience, the sum of `SIG_LEN`, `EXP_LEN`, and `SIGN_LEN`.
101
+ LIBC_INLINE_VAR static constexpr int TOTAL_LEN = SIGN_LEN + EXP_LEN + SIG_LEN;
100
102
101
103
// An unsigned integer that is wide enough to contain all of the floating
102
104
// point bits.
@@ -173,45 +175,12 @@ struct FPProperties : public internal::FPBaseProperties<fp_type> {
173
175
: bit_at(SIG_LEN - 2 ); // 0b0100...
174
176
};
175
177
176
- // -----------------------------------------------------------------------------
177
- template <typename FP> LIBC_INLINE static constexpr FPType get_fp_type () {
178
- if constexpr (cpp::is_same_v<FP, float > && __FLT_MANT_DIG__ == 24 )
179
- return FPType::IEEE754_Binary32;
180
- else if constexpr (cpp::is_same_v<FP, double > && __DBL_MANT_DIG__ == 53 )
181
- return FPType::IEEE754_Binary64;
182
- else if constexpr (cpp::is_same_v<FP, long double >) {
183
- if constexpr (__LDBL_MANT_DIG__ == 53 )
184
- return FPType::IEEE754_Binary64;
185
- else if constexpr (__LDBL_MANT_DIG__ == 64 )
186
- return FPType::X86_Binary80;
187
- else if constexpr (__LDBL_MANT_DIG__ == 113 )
188
- return FPType::IEEE754_Binary128;
189
- }
190
- #if defined(LIBC_COMPILER_HAS_C23_FLOAT16)
191
- else if constexpr (cpp::is_same_v<FP, _Float16>)
192
- return FPType::IEEE754_Binary16;
193
- #endif
194
- #if defined(LIBC_COMPILER_HAS_C23_FLOAT128)
195
- else if constexpr (cpp::is_same_v<FP, _Float128>)
196
- return FPType::IEEE754_Binary128;
197
- #endif
198
- #if defined(LIBC_COMPILER_HAS_FLOAT128_EXTENSION)
199
- else if constexpr (cpp::is_same_v<FP, __float128>)
200
- return FPType::IEEE754_Binary128;
201
- #endif
202
- else
203
- static_assert (cpp::always_false<FP>, " Unsupported type" );
204
- }
205
-
206
- template <typename FP>
207
- struct FloatProperties : public FPProperties <get_fp_type<FP>()> {};
208
-
209
178
namespace internal {
210
179
211
180
// This is a temporary class to unify common methods and properties between
212
181
// FPBits and FPBits<long double>.
213
- template <FPType fp_type> struct FPBitsCommon : private FPProperties <fp_type> {
214
- using UP = FPProperties <fp_type>;
182
+ template <FPType fp_type> struct FPRep : private FPBaseMasksAndShifts <fp_type> {
183
+ using UP = FPBaseMasksAndShifts <fp_type>;
215
184
using typename UP::StorageType;
216
185
using UP::TOTAL_LEN;
217
186
@@ -227,15 +196,17 @@ template <FPType fp_type> struct FPBitsCommon : private FPProperties<fp_type> {
227
196
using UP::FP_MASK;
228
197
using UP::FRACTION_LEN;
229
198
using UP::FRACTION_MASK;
199
+ using UP::MANTISSA_PRECISION;
230
200
using UP::SIGN_MASK;
201
+ using UP::STORAGE_LEN;
231
202
232
203
// Reinterpreting bits as an integer value and interpreting the bits of an
233
204
// integer value as a floating point value is used in tests. So, a convenient
234
205
// type is provided for such reinterpretations.
235
206
StorageType bits;
236
207
237
- LIBC_INLINE constexpr FPBitsCommon () : bits(0 ) {}
238
- LIBC_INLINE explicit constexpr FPBitsCommon (StorageType bits) : bits(bits) {}
208
+ LIBC_INLINE constexpr FPRep () : bits(0 ) {}
209
+ LIBC_INLINE explicit constexpr FPRep (StorageType bits) : bits(bits) {}
239
210
240
211
LIBC_INLINE constexpr void set_mantissa (StorageType mantVal) {
241
212
mantVal &= FRACTION_MASK;
@@ -297,6 +268,37 @@ template <FPType fp_type> struct FPBitsCommon : private FPProperties<fp_type> {
297
268
298
269
} // namespace internal
299
270
271
+ // Returns the FPType corresponding to C++ type T on the host.
272
+ template <typename T> LIBC_INLINE static constexpr FPType get_fp_type () {
273
+ using UnqualT = cpp::remove_cv_t <T>;
274
+ if constexpr (cpp::is_same_v<UnqualT, float > && __FLT_MANT_DIG__ == 24 )
275
+ return FPType::IEEE754_Binary32;
276
+ else if constexpr (cpp::is_same_v<UnqualT, double > && __DBL_MANT_DIG__ == 53 )
277
+ return FPType::IEEE754_Binary64;
278
+ else if constexpr (cpp::is_same_v<UnqualT, long double >) {
279
+ if constexpr (__LDBL_MANT_DIG__ == 53 )
280
+ return FPType::IEEE754_Binary64;
281
+ else if constexpr (__LDBL_MANT_DIG__ == 64 )
282
+ return FPType::X86_Binary80;
283
+ else if constexpr (__LDBL_MANT_DIG__ == 113 )
284
+ return FPType::IEEE754_Binary128;
285
+ }
286
+ #if defined(LIBC_COMPILER_HAS_C23_FLOAT16)
287
+ else if constexpr (cpp::is_same_v<UnqualT, _Float16>)
288
+ return FPType::IEEE754_Binary16;
289
+ #endif
290
+ #if defined(LIBC_COMPILER_HAS_C23_FLOAT128)
291
+ else if constexpr (cpp::is_same_v<UnqualT, _Float128>)
292
+ return FPType::IEEE754_Binary128;
293
+ #endif
294
+ #if defined(LIBC_COMPILER_HAS_FLOAT128_EXTENSION)
295
+ else if constexpr (cpp::is_same_v<UnqualT, __float128>)
296
+ return FPType::IEEE754_Binary128;
297
+ #endif
298
+ else
299
+ static_assert (cpp::always_false<UnqualT>, " Unsupported type" );
300
+ }
301
+
300
302
// A generic class to represent single precision, double precision, and quad
301
303
// precision IEEE 754 floating point formats.
302
304
// On most platforms, the 'float' type corresponds to single precision floating
@@ -305,11 +307,10 @@ template <FPType fp_type> struct FPBitsCommon : private FPProperties<fp_type> {
305
307
// floating numbers. On x86 platforms however, the 'long double' type maps to
306
308
// an x87 floating point format. This format is an IEEE 754 extension format.
307
309
// It is handled as an explicit specialization of this class.
308
- template <typename T>
309
- struct FPBits : public internal ::FPBitsCommon<get_fp_type<T>()> {
310
+ template <typename T> struct FPBits : public internal ::FPRep<get_fp_type<T>()> {
310
311
static_assert (cpp::is_floating_point_v<T>,
311
312
" FPBits instantiated with invalid type." );
312
- using UP = internal::FPBitsCommon <get_fp_type<T>()>;
313
+ using UP = internal::FPRep <get_fp_type<T>()>;
313
314
using StorageType = typename UP::StorageType;
314
315
using UP::bits;
315
316
0 commit comments