//===-- Properties of floating point 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_SRC_SUPPORT_FPUTIL_FLOAT_PROPERTIES_H #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT_PROPERTIES_H #include "PlatformDefs.h" #include "src/__support/UInt128.h" #include namespace __llvm_libc { namespace fputil { template struct FloatProperties {}; template <> struct FloatProperties { typedef uint32_t BitsType; static_assert(sizeof(BitsType) == sizeof(float), "Unexpected size of 'float' type."); static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8; static constexpr uint32_t MANTISSA_WIDTH = 23; static constexpr uint32_t EXPONENT_WIDTH = 8; static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1; static constexpr BitsType SIGN_MASK = BitsType(1) << (EXPONENT_WIDTH + MANTISSA_WIDTH); static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK); static constexpr uint32_t EXPONENT_BIAS = 127; static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK; static_assert(EXP_MANT_MASK == ~SIGN_MASK, "Exponent and mantissa masks are not as expected."); // If a number x is a NAN, then it is a quiet NAN if: // QuietNaNMask & bits(x) != 0 // Else, it is a signalling NAN. static constexpr BitsType QUIET_NAN_MASK = 0x00400000U; }; template <> struct FloatProperties { typedef uint64_t BitsType; static_assert(sizeof(BitsType) == sizeof(double), "Unexpected size of 'double' type."); static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8; static constexpr uint32_t MANTISSA_WIDTH = 52; static constexpr uint32_t EXPONENT_WIDTH = 11; static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1; static constexpr BitsType SIGN_MASK = BitsType(1) << (EXPONENT_WIDTH + MANTISSA_WIDTH); static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK); static constexpr uint32_t EXPONENT_BIAS = 1023; static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK; static_assert(EXP_MANT_MASK == ~SIGN_MASK, "Exponent and mantissa masks are not as expected."); // If a number x is a NAN, then it is a quiet NAN if: // QuietNaNMask & bits(x) != 0 // Else, it is a signalling NAN. static constexpr BitsType QUIET_NAN_MASK = 0x0008000000000000ULL; }; #if defined(LONG_DOUBLE_IS_DOUBLE) // Properties for numbers represented in 64 bits long double on Windows // platform. template <> struct FloatProperties { typedef uint64_t BitsType; static_assert(sizeof(BitsType) == sizeof(double), "Unexpected size of 'double' type."); static constexpr uint32_t BIT_WIDTH = FloatProperties::BIT_WIDTH; static constexpr uint32_t MANTISSA_WIDTH = FloatProperties::MANTISSA_WIDTH; static constexpr uint32_t EXPONENT_WIDTH = FloatProperties::EXPONENT_WIDTH; static constexpr BitsType MANTISSA_MASK = FloatProperties::MANTISSA_MASK; static constexpr BitsType SIGN_MASK = FloatProperties::SIGN_MASK; static constexpr BitsType EXPONENT_MASK = FloatProperties::EXPONENT_MASK; static constexpr uint32_t EXPONENT_BIAS = FloatProperties::EXPONENT_BIAS; static constexpr BitsType EXP_MANT_MASK = FloatProperties::EXP_MANT_MASK; static_assert(EXP_MANT_MASK == ~SIGN_MASK, "Exponent and mantissa masks are not as expected."); // If a number x is a NAN, then it is a quiet NAN if: // QuietNaNMask & bits(x) != 0 // Else, it is a signalling NAN. static constexpr BitsType QUIET_NAN_MASK = FloatProperties::QUIET_NAN_MASK; }; #elif defined(SPECIAL_X86_LONG_DOUBLE) // Properties for numbers represented in 80 bits long double on non-Windows x86 // platforms. template <> struct FloatProperties { typedef UInt128 BitsType; static_assert(sizeof(BitsType) == sizeof(long double), "Unexpected size of 'long double' type."); static constexpr uint32_t BIT_WIDTH = (sizeof(BitsType) * 8) - 48; static constexpr BitsType FULL_WIDTH_MASK = ((BitsType(1) << BIT_WIDTH) - 1); static constexpr uint32_t MANTISSA_WIDTH = 63; static constexpr uint32_t EXPONENT_WIDTH = 15; static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1; // The x86 80 bit float represents the leading digit of the mantissa // explicitly. This is the mask for that bit. static constexpr BitsType EXPLICIT_BIT_MASK = (BitsType(1) << MANTISSA_WIDTH); static constexpr BitsType SIGN_MASK = BitsType(1) << (EXPONENT_WIDTH + MANTISSA_WIDTH + 1); static constexpr BitsType EXPONENT_MASK = ((BitsType(1) << EXPONENT_WIDTH) - 1) << (MANTISSA_WIDTH + 1); static constexpr uint32_t EXPONENT_BIAS = 16383; static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK | EXPLICIT_BIT_MASK | EXPONENT_MASK; static_assert(EXP_MANT_MASK == (~SIGN_MASK & FULL_WIDTH_MASK), "Exponent and mantissa masks are not as expected."); // If a number x is a NAN, then it is a quiet NAN if: // QuietNaNMask & bits(x) != 0 // Else, it is a signalling NAN. static constexpr BitsType QUIET_NAN_MASK = BitsType(1) << (MANTISSA_WIDTH - 1); }; #else // Properties for numbers represented in 128 bits long double on non x86 // platform. template <> struct FloatProperties { typedef UInt128 BitsType; static_assert(sizeof(BitsType) == sizeof(long double), "Unexpected size of 'long double' type."); static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) << 3; static constexpr uint32_t MANTISSA_WIDTH = 112; static constexpr uint32_t EXPONENT_WIDTH = 15; static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1; static constexpr BitsType SIGN_MASK = BitsType(1) << (EXPONENT_WIDTH + MANTISSA_WIDTH); static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK); static constexpr uint32_t EXPONENT_BIAS = 16383; static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK | EXPONENT_MASK; static_assert(EXP_MANT_MASK == ~SIGN_MASK, "Exponent and mantissa masks are not as expected."); // If a number x is a NAN, then it is a quiet NAN if: // QuietNaNMask & bits(x) != 0 // Else, it is a signalling NAN. static constexpr BitsType QUIET_NAN_MASK = BitsType(1) << (MANTISSA_WIDTH - 1); }; #endif // Define the float type corresponding to the BitsType. template struct FloatType; template <> struct FloatType { static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected size of 'float' type."); typedef float Type; }; template <> struct FloatType { static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected size of 'double' type."); typedef double Type; }; template using FloatTypeT = typename FloatType::Type; } // namespace fputil } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT_PROPERTIES_H