Skip to content

Commit c09e690

Browse files
authored
[libc][NFC] Remove FloatProperties (#76508)
Access is now done through `FPBits` exclusively. This patch also renames a few internal structs and uses `T` instead of `FP` as a template parameter.
1 parent b7d5b0d commit c09e690

File tree

26 files changed

+180
-209
lines changed

26 files changed

+180
-209
lines changed

libc/fuzzing/stdlib/strtofloat_fuzz.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,17 @@
2222

2323
#include "utils/MPFRWrapper/mpfr_inc.h"
2424

25-
using LIBC_NAMESPACE::fputil::FloatProperties;
25+
using LIBC_NAMESPACE::fputil::FPBits;
2626

2727
// This function calculates the effective precision for a given float type and
2828
// exponent. Subnormals have a lower effective precision since they don't
2929
// necessarily use all of the bits of the mantissa.
3030
template <typename F> inline constexpr int effective_precision(int exponent) {
31-
const int full_precision = FloatProperties<F>::MANTISSA_PRECISION;
31+
const int full_precision = FPBits<F>::MANTISSA_PRECISION;
3232

3333
// This is intended to be 0 when the exponent is the lowest normal and
3434
// increase as the exponent's magnitude increases.
35-
const int bits_below_normal =
36-
(-exponent) - (FloatProperties<F>::EXP_BIAS - 1);
35+
const int bits_below_normal = (-exponent) - (FPBits<F>::EXP_BIAS - 1);
3736

3837
// The precision should be the normal, full precision, minus the bits lost
3938
// by this being a subnormal, minus one for the implicit leading one.

libc/src/__support/FPUtil/FPBits.h

Lines changed: 66 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -39,64 +39,66 @@ enum class FPEncoding {
3939
X86_ExtendedPrecision,
4040
};
4141

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 {};
4346

44-
template <> struct FPBaseProperties<FPType::IEEE754_Binary16> {
47+
template <> struct FPLayout<FPType::IEEE754_Binary16> {
4548
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;
4850
LIBC_INLINE_VAR static constexpr int EXP_LEN = 5;
51+
LIBC_INLINE_VAR static constexpr int SIG_LEN = 10;
4952
LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
5053
};
5154

52-
template <> struct FPBaseProperties<FPType::IEEE754_Binary32> {
55+
template <> struct FPLayout<FPType::IEEE754_Binary32> {
5356
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;
5658
LIBC_INLINE_VAR static constexpr int EXP_LEN = 8;
59+
LIBC_INLINE_VAR static constexpr int SIG_LEN = 23;
5760
LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
5861
};
5962

60-
template <> struct FPBaseProperties<FPType::IEEE754_Binary64> {
63+
template <> struct FPLayout<FPType::IEEE754_Binary64> {
6164
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;
6466
LIBC_INLINE_VAR static constexpr int EXP_LEN = 11;
67+
LIBC_INLINE_VAR static constexpr int SIG_LEN = 52;
6568
LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
6669
};
6770

68-
template <> struct FPBaseProperties<FPType::IEEE754_Binary128> {
71+
template <> struct FPLayout<FPType::IEEE754_Binary128> {
6972
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;
7274
LIBC_INLINE_VAR static constexpr int EXP_LEN = 15;
75+
LIBC_INLINE_VAR static constexpr int SIG_LEN = 112;
7376
LIBC_INLINE_VAR static constexpr auto ENCODING = FPEncoding::IEEE754;
7477
};
7578

76-
template <> struct FPBaseProperties<FPType::X86_Binary80> {
79+
template <> struct FPLayout<FPType::X86_Binary80> {
7780
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;
8082
LIBC_INLINE_VAR static constexpr int EXP_LEN = 15;
83+
LIBC_INLINE_VAR static constexpr int SIG_LEN = 64;
8184
LIBC_INLINE_VAR static constexpr auto ENCODING =
8285
FPEncoding::X86_ExtendedPrecision;
8386
};
8487

8588
} // namespace internal
8689

90+
// FPBaseMasksAndShifts derives useful constants from the FPLayout.
8791
template <FPType fp_type>
88-
struct FPProperties : public internal::FPBaseProperties<fp_type> {
92+
struct FPBaseMasksAndShifts : public internal::FPLayout<fp_type> {
8993
private:
90-
using UP = internal::FPBaseProperties<fp_type>;
94+
using UP = internal::FPLayout<fp_type>;
9195

9296
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;
100102

101103
// An unsigned integer that is wide enough to contain all of the floating
102104
// point bits.
@@ -173,45 +175,12 @@ struct FPProperties : public internal::FPBaseProperties<fp_type> {
173175
: bit_at(SIG_LEN - 2); // 0b0100...
174176
};
175177

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-
209178
namespace internal {
210179

211180
// This is a temporary class to unify common methods and properties between
212181
// 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>;
215184
using typename UP::StorageType;
216185
using UP::TOTAL_LEN;
217186

@@ -227,15 +196,17 @@ template <FPType fp_type> struct FPBitsCommon : private FPProperties<fp_type> {
227196
using UP::FP_MASK;
228197
using UP::FRACTION_LEN;
229198
using UP::FRACTION_MASK;
199+
using UP::MANTISSA_PRECISION;
230200
using UP::SIGN_MASK;
201+
using UP::STORAGE_LEN;
231202

232203
// Reinterpreting bits as an integer value and interpreting the bits of an
233204
// integer value as a floating point value is used in tests. So, a convenient
234205
// type is provided for such reinterpretations.
235206
StorageType bits;
236207

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) {}
239210

240211
LIBC_INLINE constexpr void set_mantissa(StorageType mantVal) {
241212
mantVal &= FRACTION_MASK;
@@ -297,6 +268,37 @@ template <FPType fp_type> struct FPBitsCommon : private FPProperties<fp_type> {
297268

298269
} // namespace internal
299270

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+
300302
// A generic class to represent single precision, double precision, and quad
301303
// precision IEEE 754 floating point formats.
302304
// 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> {
305307
// floating numbers. On x86 platforms however, the 'long double' type maps to
306308
// an x87 floating point format. This format is an IEEE 754 extension format.
307309
// 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>()> {
310311
static_assert(cpp::is_floating_point_v<T>,
311312
"FPBits instantiated with invalid type.");
312-
using UP = internal::FPBitsCommon<get_fp_type<T>()>;
313+
using UP = internal::FPRep<get_fp_type<T>()>;
313314
using StorageType = typename UP::StorageType;
314315
using UP::bits;
315316

libc/src/__support/FPUtil/ManipulationFunctions.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,13 @@ LIBC_INLINE T nextafter(T from, U to) {
174174
} else {
175175
int_val = FPBits<T>::MIN_SUBNORMAL;
176176
if (to_bits.get_sign())
177-
int_val |= FloatProperties<T>::SIGN_MASK;
177+
int_val |= FPBits<T>::SIGN_MASK;
178178
}
179179

180-
StorageType exponent_bits = int_val & FloatProperties<T>::EXP_MASK;
180+
StorageType exponent_bits = int_val & FPBits<T>::EXP_MASK;
181181
if (exponent_bits == StorageType(0))
182182
raise_except_if_required(FE_UNDERFLOW | FE_INEXACT);
183-
else if (exponent_bits == FloatProperties<T>::EXP_MASK)
183+
else if (exponent_bits == FPBits<T>::EXP_MASK)
184184
raise_except_if_required(FE_OVERFLOW | FE_INEXACT);
185185

186186
return cpp::bit_cast<T>(int_val);

libc/src/__support/FPUtil/dyadic_float.h

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@ template <size_t Bits> struct DyadicFloat {
4141

4242
template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
4343
DyadicFloat(T x) {
44-
static_assert(FloatProperties<T>::FRACTION_LEN < Bits);
44+
static_assert(FPBits<T>::FRACTION_LEN < Bits);
4545
FPBits<T> x_bits(x);
4646
sign = x_bits.get_sign();
47-
exponent = x_bits.get_exponent() - FloatProperties<T>::FRACTION_LEN;
47+
exponent = x_bits.get_exponent() - FPBits<T>::FRACTION_LEN;
4848
mantissa = MantissaType(x_bits.get_explicit_mantissa());
4949
normalize();
5050
}
@@ -83,21 +83,20 @@ template <size_t Bits> struct DyadicFloat {
8383
// Output is rounded correctly with respect to the current rounding mode.
8484
// TODO(lntue): Add support for underflow.
8585
// TODO(lntue): Test or add specialization for x86 long double.
86-
template <typename T, typename = cpp::enable_if_t<
87-
cpp::is_floating_point_v<T> &&
88-
(FloatProperties<T>::FRACTION_LEN < Bits),
89-
void>>
86+
template <typename T,
87+
typename = cpp::enable_if_t<cpp::is_floating_point_v<T> &&
88+
(FPBits<T>::FRACTION_LEN < Bits),
89+
void>>
9090
explicit operator T() const {
9191
// TODO(lntue): Do we need to treat signed zeros properly?
9292
if (mantissa.is_zero())
9393
return 0.0;
9494

9595
// Assume that it is normalized, and output is also normal.
96-
constexpr uint32_t PRECISION = FloatProperties<T>::MANTISSA_PRECISION;
96+
constexpr uint32_t PRECISION = FPBits<T>::MANTISSA_PRECISION;
9797
using output_bits_t = typename FPBits<T>::StorageType;
9898

99-
int exp_hi =
100-
exponent + static_cast<int>((Bits - 1) + FloatProperties<T>::EXP_BIAS);
99+
int exp_hi = exponent + static_cast<int>((Bits - 1) + FPBits<T>::EXP_BIAS);
101100

102101
bool denorm = false;
103102
uint32_t shift = Bits - PRECISION;
@@ -106,7 +105,7 @@ template <size_t Bits> struct DyadicFloat {
106105
denorm = true;
107106
shift = (Bits - PRECISION) + static_cast<uint32_t>(1 - exp_hi);
108107

109-
exp_hi = FloatProperties<T>::EXP_BIAS;
108+
exp_hi = FPBits<T>::EXP_BIAS;
110109
}
111110

112111
int exp_lo = exp_hi - static_cast<int>(PRECISION) - 1;
@@ -115,7 +114,7 @@ template <size_t Bits> struct DyadicFloat {
115114

116115
T d_hi = FPBits<T>::create_value(sign, exp_hi,
117116
static_cast<output_bits_t>(m_hi) &
118-
FloatProperties<T>::FRACTION_MASK)
117+
FPBits<T>::FRACTION_MASK)
119118
.get_val();
120119

121120
const MantissaType round_mask = MantissaType(1) << (shift - 1);
@@ -129,15 +128,13 @@ template <size_t Bits> struct DyadicFloat {
129128
if (LIBC_UNLIKELY(exp_lo <= 0)) {
130129
// d_lo is denormal, but the output is normal.
131130
int scale_up_exponent = 2 * PRECISION;
132-
T scale_up_factor = FPBits<T>::create_value(sign,
133-
FloatProperties<T>::EXP_BIAS +
134-
scale_up_exponent,
135-
output_bits_t(0))
136-
.get_val();
131+
T scale_up_factor =
132+
FPBits<T>::create_value(sign, FPBits<T>::EXP_BIAS + scale_up_exponent,
133+
output_bits_t(0))
134+
.get_val();
137135
T scale_down_factor =
138-
FPBits<T>::create_value(
139-
sign, FloatProperties<T>::EXP_BIAS - scale_up_exponent,
140-
output_bits_t(0))
136+
FPBits<T>::create_value(sign, FPBits<T>::EXP_BIAS - scale_up_exponent,
137+
output_bits_t(0))
141138
.get_val();
142139

143140
d_lo = FPBits<T>::create_value(sign, exp_lo + scale_up_exponent,
@@ -156,7 +153,7 @@ template <size_t Bits> struct DyadicFloat {
156153
if (LIBC_UNLIKELY(denorm)) {
157154
// Output is denormal, simply clear the exponent field.
158155
output_bits_t clear_exp = output_bits_t(exp_hi)
159-
<< FloatProperties<T>::FRACTION_LEN;
156+
<< FPBits<T>::FRACTION_LEN;
160157
output_bits_t r_bits = FPBits<T>(r).uintval() - clear_exp;
161158
return FPBits<T>(r_bits).get_val();
162159
}

libc/src/__support/FPUtil/generic/FMA.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ LIBC_INLINE bool shift_mantissa(int shift_length, UInt128 &mant) {
9494

9595
template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
9696
using FPBits = fputil::FPBits<double>;
97-
using FloatProp = fputil::FloatProperties<double>;
9897

9998
if (LIBC_UNLIKELY(x == 0 || y == 0 || z == 0)) {
10099
return x * y + z;
@@ -267,10 +266,10 @@ template <> LIBC_INLINE double fma<double>(double x, double y, double z) {
267266
}
268267

269268
// Remove hidden bit and append the exponent field and sign bit.
270-
result = (result & FloatProp::FRACTION_MASK) |
271-
(static_cast<uint64_t>(r_exp) << FloatProp::FRACTION_LEN);
269+
result = (result & FPBits::FRACTION_MASK) |
270+
(static_cast<uint64_t>(r_exp) << FPBits::FRACTION_LEN);
272271
if (prod_sign) {
273-
result |= FloatProp::SIGN_MASK;
272+
result |= FPBits::SIGN_MASK;
274273
}
275274

276275
// Rounding.

libc/src/__support/FPUtil/x86_64/LongDoubleBits.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,8 @@ namespace LIBC_NAMESPACE {
2727
namespace fputil {
2828

2929
template <>
30-
struct FPBits<long double>
31-
: public internal::FPBitsCommon<FPType::X86_Binary80> {
32-
using UP = internal::FPBitsCommon<FPType::X86_Binary80>;
30+
struct FPBits<long double> : public internal::FPRep<FPType::X86_Binary80> {
31+
using UP = internal::FPRep<FPType::X86_Binary80>;
3332
using StorageType = typename UP::StorageType;
3433
using UP::bits;
3534

0 commit comments

Comments
 (0)