| //===-- 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 "PlatformDefs.h" |
| |
| #include "utils/CPP/TypeTraits.h" |
| |
| #include "FloatProperties.h" |
| #include <stdint.h> |
| |
| namespace __llvm_libc { |
| namespace fputil { |
| |
| template <typename T> struct MantissaWidth { |
| static constexpr unsigned value = FloatProperties<T>::mantissaWidth; |
| }; |
| |
| template <typename T> struct ExponentWidth { |
| static constexpr unsigned value = FloatProperties<T>::exponentWidth; |
| }; |
| |
| // 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 <typename T> union FPBits { |
| static_assert(cpp::IsFloatingPointType<T>::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 FloatProp = FloatProperties<T>; |
| // TODO: Change UintType name to BitsType for consistency. |
| using UIntType = typename FloatProp::BitsType; |
| |
| UIntType bits; |
| |
| void setMantissa(UIntType mantVal) { |
| mantVal &= (FloatProp::mantissaMask); |
| bits &= ~(FloatProp::mantissaMask); |
| bits |= mantVal; |
| } |
| |
| UIntType getMantissa() const { return bits & FloatProp::mantissaMask; } |
| |
| void setUnbiasedExponent(UIntType expVal) { |
| expVal = (expVal << (FloatProp::mantissaWidth)) & FloatProp::exponentMask; |
| bits &= ~(FloatProp::exponentMask); |
| bits |= expVal; |
| } |
| |
| uint16_t getUnbiasedExponent() const { |
| return uint16_t((bits & FloatProp::exponentMask) >> |
| (FloatProp::mantissaWidth)); |
| } |
| |
| void setSign(bool signVal) { |
| bits &= ~(FloatProp::signMask); |
| UIntType sign = UIntType(signVal) << (FloatProp::bitWidth - 1); |
| bits |= sign; |
| } |
| |
| bool getSign() const { |
| return ((bits & FloatProp::signMask) >> (FloatProp::bitWidth - 1)); |
| } |
| T val; |
| |
| static_assert(sizeof(T) == sizeof(UIntType), |
| "Data type and integral representation have different sizes."); |
| |
| static constexpr int exponentBias = (1 << (ExponentWidth<T>::value - 1)) - 1; |
| static constexpr int maxExponent = (1 << ExponentWidth<T>::value) - 1; |
| |
| static constexpr UIntType minSubnormal = UIntType(1); |
| static constexpr UIntType maxSubnormal = |
| (UIntType(1) << MantissaWidth<T>::value) - 1; |
| static constexpr UIntType minNormal = |
| (UIntType(1) << MantissaWidth<T>::value); |
| static constexpr UIntType maxNormal = |
| ((UIntType(maxExponent) - 1) << MantissaWidth<T>::value) | maxSubnormal; |
| |
| // We don't want accidental type promotions/conversions so we require exact |
| // type match. |
| template <typename XType, |
| cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0> |
| explicit FPBits(XType x) : val(x) {} |
| |
| template <typename XType, |
| cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0> |
| explicit FPBits(XType x) : bits(x) {} |
| |
| FPBits() : bits(0) {} |
| |
| explicit operator T() { return val; } |
| |
| UIntType uintval() const { return bits; } |
| |
| int getExponent() const { return int(getUnbiasedExponent()) - exponentBias; } |
| |
| bool isZero() const { |
| return getMantissa() == 0 && getUnbiasedExponent() == 0; |
| } |
| |
| bool isInf() const { |
| return getMantissa() == 0 && getUnbiasedExponent() == maxExponent; |
| } |
| |
| bool isNaN() const { |
| return getUnbiasedExponent() == maxExponent && getMantissa() != 0; |
| } |
| |
| bool isInfOrNaN() const { return getUnbiasedExponent() == maxExponent; } |
| |
| static FPBits<T> zero() { return FPBits(); } |
| |
| static FPBits<T> negZero() { |
| return FPBits(UIntType(1) << (sizeof(UIntType) * 8 - 1)); |
| } |
| |
| static FPBits<T> inf() { |
| FPBits<T> bits; |
| bits.setUnbiasedExponent(maxExponent); |
| return bits; |
| } |
| |
| static FPBits<T> negInf() { |
| FPBits<T> bits = inf(); |
| bits.setSign(1); |
| return bits; |
| } |
| |
| static T buildNaN(UIntType v) { |
| FPBits<T> bits = inf(); |
| bits.setMantissa(v); |
| return T(bits); |
| } |
| }; |
| |
| } // namespace fputil |
| } // namespace __llvm_libc |
| |
| #ifdef SPECIAL_X86_LONG_DOUBLE |
| #include "utils/FPUtil/LongDoubleBitsX86.h" |
| #endif |
| |
| #endif // LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H |