AK: Ensure unions with bitfield structs actually have correct sizes

The fun pattern of `union { struct { u32 a : 1; u64 b : 7; }; u8 x; }`
produces complete garbage on windows, this commit fixes the two
instances of those that exist in AK.
This commit also makes sure that the generated unions have the correct
size (whereas FloatExtractor<f32> previously did not!) by adding some
nice static_asserts.
This commit is contained in:
Ali Mohammad Pur 2023-11-01 01:59:31 +03:30 committed by Ali Mohammad Pur
parent 4676b288a2
commit 7976e1852c
Notes: sideshowbarker 2024-07-16 20:05:14 +09:00
2 changed files with 24 additions and 14 deletions

View file

@ -13,7 +13,7 @@ VALIDATE_IS_X86();
namespace AK {
enum class RoundingMode : u8 {
enum class RoundingMode : u16 {
NEAREST = 0b00,
DOWN = 0b01,
UP = 0b10,

View file

@ -22,16 +22,16 @@ union FloatExtractor<f128> {
static constexpr int exponent_bias = 16383;
static constexpr int exponent_bits = 15;
static constexpr unsigned exponent_max = 32767;
struct {
struct [[gnu::packed]] {
unsigned __int128 mantissa : 112;
unsigned exponent : 15;
unsigned sign : 1;
unsigned __int128 exponent : 15;
unsigned __int128 sign : 1;
};
f128 d;
};
// Validate that f128 and the FloatExtractor union are 128 bits.
static_assert(sizeof(f128) == 16);
static_assert(sizeof(FloatExtractor<f128>) == 16);
static_assert(AssertSize<f128, 16>());
static_assert(AssertSize<FloatExtractor<f128>, sizeof(f128)>());
#endif
#ifdef AK_HAS_FLOAT_80
@ -42,13 +42,14 @@ union FloatExtractor<f80> {
static constexpr int exponent_bias = 16383;
static constexpr int exponent_bits = 15;
static constexpr unsigned exponent_max = 32767;
struct {
struct [[gnu::packed]] {
unsigned long long mantissa;
unsigned exponent : 15;
unsigned sign : 1;
unsigned long long exponent : 15;
unsigned long long sign : 1;
};
f80 d;
};
static_assert(AssertSize<FloatExtractor<f80>, sizeof(f80)>());
#endif
template<>
@ -58,13 +59,21 @@ union FloatExtractor<f64> {
static constexpr int exponent_bias = 1023;
static constexpr int exponent_bits = 11;
static constexpr unsigned exponent_max = 2047;
struct {
struct [[gnu::packed]] {
// FIXME: These types have to all be the same, otherwise this struct
// goes from being a bitfield describing the layout of an f64
// into being a multibyte mess on windows.
// Technically, '-mno-ms-bitfields' is supposed to disable this
// 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 exponent : 11;
unsigned sign : 1;
unsigned long long exponent : 11;
unsigned long long sign : 1;
};
f64 d;
};
static_assert(AssertSize<FloatExtractor<f64>, sizeof(f64)>());
template<>
union FloatExtractor<f32> {
@ -73,13 +82,14 @@ union FloatExtractor<f32> {
static constexpr int exponent_bias = 127;
static constexpr int exponent_bits = 8;
static constexpr unsigned exponent_max = 255;
struct {
unsigned long long mantissa : 23;
struct [[gnu::packed]] {
unsigned mantissa : 23;
unsigned exponent : 8;
unsigned sign : 1;
};
f32 d;
};
static_assert(AssertSize<FloatExtractor<f32>, sizeof(f32)>());
template<size_t S, size_t E, size_t M>
requires(S <= 1 && E >= 1 && M >= 1 && (S + E + M) <= 64) class FloatingPointBits final {