/* * Copyright (c) 2022, Jelle Raaijmakers * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include namespace AK { template union FloatExtractor; #ifdef AK_HAS_FLOAT_128 template<> union FloatExtractor { using ComponentType = unsigned __int128; static constexpr int mantissa_bits = 112; 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]] { # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ComponentType sign : 1; ComponentType exponent : 15; ComponentType mantissa : 112; # else ComponentType mantissa : 112; ComponentType exponent : 15; ComponentType sign : 1; # endif }; f128 d; }; // Validate that f128 and the FloatExtractor union are 128 bits. static_assert(AssertSize()); static_assert(AssertSize, sizeof(f128)>()); #endif #ifdef AK_HAS_FLOAT_80 template<> union FloatExtractor { using ComponentType = unsigned long long; static constexpr int mantissa_bits = 64; 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]] { // 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. # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ComponentType sign : 1; ComponentType exponent : 15; ComponentType mantissa : 64; # else ComponentType mantissa : 64; ComponentType exponent : 15; ComponentType sign : 1; # endif }; f80 d; }; static_assert(AssertSize, sizeof(f80)>()); #endif template<> union FloatExtractor { using ComponentType = unsigned long long; static constexpr int mantissa_bits = 52; 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; 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 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ComponentType sign : 1; ComponentType exponent : 11; ComponentType mantissa : 52; #else ComponentType mantissa : 52; ComponentType exponent : 11; ComponentType sign : 1; #endif }; f64 d; }; static_assert(AssertSize, sizeof(f64)>()); template<> union FloatExtractor { using ComponentType = unsigned; static constexpr int mantissa_bits = 23; static constexpr ComponentType mantissa_max = (1 << 23) - 1; static constexpr int exponent_bias = 127; static constexpr int exponent_bits = 8; static constexpr ComponentType exponent_max = 255; struct [[gnu::packed]] { #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ ComponentType sign : 1; ComponentType exponent : 8; ComponentType mantissa : 23; #else ComponentType mantissa : 23; ComponentType exponent : 8; ComponentType sign : 1; #endif }; f32 d; }; static_assert(AssertSize, sizeof(f32)>()); } #if USING_AK_GLOBALLY using AK::FloatExtractor; #endif