//===-- Abstract class for bit manipulation of float 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_FP_BITS_H #define LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H #include "utils/CPP/TypeTraits.h" #include namespace __llvm_libc { namespace fputil { template struct MantissaWidth {}; template <> struct MantissaWidth { static constexpr unsigned value = 23; }; template <> struct MantissaWidth { static constexpr unsigned value = 52; }; template struct ExponentWidth {}; template <> struct ExponentWidth { static constexpr unsigned value = 8; }; template <> struct ExponentWidth { static constexpr unsigned value = 11; }; template <> struct ExponentWidth { static constexpr unsigned value = 15; }; template struct FPUIntType {}; template <> struct FPUIntType { using Type = uint32_t; }; template <> struct FPUIntType { using Type = uint64_t; }; #if !(defined(__x86_64__) || defined(__i386__)) // TODO: This has to be extended for visual studio where long double and // double are equivalent. template <> struct MantissaWidth { static constexpr unsigned value = 112; }; template <> struct FPUIntType { using Type = __uint128_t; }; #endif // A generic class to represent single precision, double precision, and quad // precision IEEE 754 floating point formats. // On most platforms, the 'float' type corresponds to single precision floating // point numbers, the 'double' type corresponds to double precision floating // point numers, and the 'long double' type corresponds to the quad precision // floating numbers. On x86 platforms however, the 'long double' type maps to // an x87 floating point format. This format is an IEEE 754 extension format. // It is handled as an explicit specialization of this class. template struct __attribute__((packed)) FPBits { static_assert(cpp::IsFloatingPointType::Value, "FPBits instantiated with invalid type."); // Reinterpreting bits as an integer value and interpreting the bits of an // integer value as a floating point value is used in tests. So, a convenient // type is provided for such reinterpretations. using UIntType = typename FPUIntType::Type; UIntType mantissa : MantissaWidth::value; uint16_t exponent : ExponentWidth::value; uint8_t sign : 1; static constexpr int exponentBias = (1 << (ExponentWidth::value - 1)) - 1; static constexpr int maxExponent = (1 << ExponentWidth::value) - 1; static constexpr UIntType minSubnormal = UIntType(1); static constexpr UIntType maxSubnormal = (UIntType(1) << MantissaWidth::value) - 1; static constexpr UIntType minNormal = (UIntType(1) << MantissaWidth::value); static constexpr UIntType maxNormal = ((UIntType(maxExponent) - 1) << MantissaWidth::value) | maxSubnormal; // We don't want accidental type promotions/conversions so we require exact // type match. template ::Value, int> = 0> explicit FPBits(XType x) { *this = *reinterpret_cast *>(&x); } operator T() { return *reinterpret_cast(this); } int getExponent() const { return int(exponent) - exponentBias; } bool isZero() const { return mantissa == 0 && exponent == 0; } bool isInf() const { return mantissa == 0 && exponent == maxExponent; } bool isNaN() const { return exponent == maxExponent && mantissa != 0; } bool isInfOrNaN() const { return exponent == maxExponent; } // Methods below this are used by tests. // The to and from integer bits converters are only used in tests. Hence, // the potential software implementations of UIntType will not slow real // code. 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 { return *reinterpret_cast(this); } static FPBits zero() { return FPBits(T(0.0)); } static FPBits negZero() { FPBits bits(T(0.0)); bits.sign = 1; return bits; } static FPBits inf() { FPBits bits(T(0.0)); bits.exponent = maxExponent; return bits; } static FPBits negInf() { FPBits bits(T(0.0)); bits.exponent = maxExponent; bits.sign = 1; return bits; } static T buildNaN(UIntType v) { FPBits bits(T(0.0)); bits.exponent = maxExponent; bits.mantissa = v; return bits; } }; } // namespace fputil } // namespace __llvm_libc #if defined(__x86_64__) || defined(__i386__) #include "utils/FPUtil/LongDoubleBitsX86.h" #endif #endif // LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H