AK: Use common ComponentType integer type for float bitfields

This allows us to easily use an appropriate integer type when performing
float bitfield operations.

This change also adds a comment about the technically-incorrect 80-bit
extended float mantissa field.
This commit is contained in:
kleines Filmröllchen 2024-01-08 00:00:35 +01:00 committed by Andrew Kaster
parent 997828c31a
commit 8443d0a74d

View file

@ -18,15 +18,16 @@ union FloatExtractor;
#ifdef AK_HAS_FLOAT_128
template<>
union FloatExtractor<f128> {
using ComponentType = unsigned __int128;
static constexpr int mantissa_bits = 112;
static constexpr unsigned __int128 mantissa_max = (((unsigned __int128)1) << 112) - 1;
static constexpr ComponentType mantissa_max = (((ComponentType)1) << 112) - 1;
static constexpr int exponent_bias = 16383;
static constexpr int exponent_bits = 15;
static constexpr unsigned exponent_max = 32767;
struct [[gnu::packed]] {
unsigned __int128 mantissa : 112;
unsigned __int128 exponent : 15;
unsigned __int128 sign : 1;
ComponentType mantissa : 112;
ComponentType exponent : 15;
ComponentType sign : 1;
};
f128 d;
};
@ -38,15 +39,21 @@ static_assert(AssertSize<FloatExtractor<f128>, sizeof(f128)>());
#ifdef AK_HAS_FLOAT_80
template<>
union FloatExtractor<f80> {
using ComponentType = unsigned long long;
static constexpr int mantissa_bits = 64;
static constexpr unsigned long long mantissa_max = ~0u;
static constexpr ComponentType mantissa_max = ~0ull;
static constexpr int exponent_bias = 16383;
static constexpr int exponent_bits = 15;
static constexpr unsigned exponent_max = 32767;
struct [[gnu::packed]] {
unsigned long long mantissa;
unsigned long long exponent : 15;
unsigned long long sign : 1;
// This is technically wrong: Extended floating point values really only have 63 bits of mantissa
// and an "integer bit" that behaves in various strange, unintuitive and non-IEEE-754 ways.
// However, since all bit-fiddling float code assumes IEEE floats, it cannot handle this properly.
// If we pretend that 80-bit floats are IEEE floats with 64-bit mantissas, almost everything works correctly
// and we just need a few special cases.
ComponentType mantissa : 64;
ComponentType exponent : 15;
ComponentType sign : 1;
};
f80 d;
};
@ -55,8 +62,9 @@ static_assert(AssertSize<FloatExtractor<f80>, sizeof(f80)>());
template<>
union FloatExtractor<f64> {
using ComponentType = unsigned long long;
static constexpr int mantissa_bits = 52;
static constexpr unsigned long long mantissa_max = (1ull << 52) - 1;
static constexpr ComponentType mantissa_max = (1ull << 52) - 1;
static constexpr int exponent_bias = 1023;
static constexpr int exponent_bits = 11;
static constexpr unsigned exponent_max = 2047;
@ -68,9 +76,9 @@ union FloatExtractor<f64> {
// very intuitive and portable behaviour on windows, but it doesn't
// work with the msvc ABI.
// See <https://github.com/llvm/llvm-project/issues/24757>
unsigned long long mantissa : 52;
unsigned long long exponent : 11;
unsigned long long sign : 1;
ComponentType mantissa : 52;
ComponentType exponent : 11;
ComponentType sign : 1;
};
f64 d;
};
@ -78,15 +86,16 @@ static_assert(AssertSize<FloatExtractor<f64>, sizeof(f64)>());
template<>
union FloatExtractor<f32> {
using ComponentType = unsigned;
static constexpr int mantissa_bits = 23;
static constexpr unsigned mantissa_max = (1 << 23) - 1;
static constexpr ComponentType mantissa_max = (1 << 23) - 1;
static constexpr int exponent_bias = 127;
static constexpr int exponent_bits = 8;
static constexpr unsigned exponent_max = 255;
static constexpr ComponentType exponent_max = 255;
struct [[gnu::packed]] {
unsigned mantissa : 23;
unsigned exponent : 8;
unsigned sign : 1;
ComponentType mantissa : 23;
ComponentType exponent : 8;
ComponentType sign : 1;
};
f32 d;
};