//===-- Bit representation of x86 long double numbers -----------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H #define LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H #include "FPBits.h" #include namespace __llvm_libc { namespace fputil { template <> struct MantissaWidth { static constexpr unsigned value = 63; }; template struct Padding; // i386 padding. template <> struct Padding<4> { static constexpr unsigned value = 16; }; // x86_64 padding. template <> struct Padding<8> { static constexpr unsigned value = 48; }; template <> struct __attribute__((packed)) FPBits { using UIntType = __uint128_t; static constexpr int exponentBias = 0x3FFF; static constexpr int maxExponent = 0x7FFF; static constexpr UIntType minSubnormal = UIntType(1); // Subnormal numbers include the implicit bit in x86 long double formats. static constexpr UIntType maxSubnormal = (UIntType(1) << (MantissaWidth::value + 1)) - 1; static constexpr UIntType minNormal = (UIntType(3) << MantissaWidth::value); static constexpr UIntType maxNormal = ((UIntType(maxExponent) - 1) << (MantissaWidth::value + 1)) | (UIntType(1) << MantissaWidth::value) | maxSubnormal; UIntType mantissa : MantissaWidth::value; uint8_t implicitBit : 1; uint16_t exponent : ExponentWidth::value; uint8_t sign : 1; uint64_t padding : Padding::value; template ::Value, int> = 0> explicit FPBits(XType x) { *this = *reinterpret_cast *>(&x); } operator long double() { return *reinterpret_cast(this); } int getExponent() const { if (exponent == 0) return int(1) - exponentBias; return int(exponent) - exponentBias; } bool isZero() const { return exponent == 0 && mantissa == 0 && implicitBit == 0; } bool isInf() const { return exponent == maxExponent && mantissa == 0 && implicitBit == 1; } bool isNaN() const { if (exponent == maxExponent) { return (implicitBit == 0) || mantissa != 0; } else if (exponent != 0) { return implicitBit == 0; } return false; } bool isInfOrNaN() const { return (exponent == maxExponent) || (exponent != 0 && implicitBit == 0); } // Methods below this are used by tests. template ::Value, int> = 0> explicit FPBits(XType x) { // The last 4 bytes of v are ignored in case of i386. *this = *reinterpret_cast *>(&x); } UIntType bitsAsUInt() const { // We cannot just return the bits as is as it will lead to reading // out of bounds in case of i386. So, we first copy the wider value // before returning the value. This makes the last 4 bytes are always // zero in case i386. UIntType result = UIntType(0); *reinterpret_cast *>(&result) = *this; // Even though we zero out |result| before copying the long double value, // there can be garbage bits in the padding. So, we zero the padding bits // in |result|. static constexpr UIntType mask = (UIntType(1) << (sizeof(long double) * 8 - Padding::value)) - 1; return result & mask; } static FPBits zero() { return FPBits(0.0l); } static FPBits negZero() { FPBits bits(0.0l); bits.sign = 1; return bits; } static FPBits inf() { FPBits bits(0.0l); bits.exponent = maxExponent; bits.implicitBit = 1; return bits; } static FPBits negInf() { FPBits bits(0.0l); bits.exponent = maxExponent; bits.implicitBit = 1; bits.sign = 1; return bits; } static long double buildNaN(UIntType v) { FPBits bits(0.0l); bits.exponent = maxExponent; bits.implicitBit = 1; bits.mantissa = v; return bits; } }; static_assert( sizeof(FPBits) == sizeof(long double), "Internal long double representation does not match the machine format."); } // namespace fputil } // namespace __llvm_libc #endif // LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H