1 //===-- Abstract class for bit manipulation of float numbers. ---*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H 10 #define LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H 11 12 #include "utils/CPP/TypeTraits.h" 13 14 #include <stdint.h> 15 16 namespace __llvm_libc { 17 namespace fputil { 18 19 template <typename T> struct MantissaWidth {}; 20 template <> struct MantissaWidth<float> { 21 static constexpr unsigned value = 23; 22 }; 23 template <> struct MantissaWidth<double> { 24 static constexpr unsigned value = 52; 25 }; 26 27 template <typename T> struct ExponentWidth {}; 28 template <> struct ExponentWidth<float> { 29 static constexpr unsigned value = 8; 30 }; 31 template <> struct ExponentWidth<double> { 32 static constexpr unsigned value = 11; 33 }; 34 template <> struct ExponentWidth<long double> { 35 static constexpr unsigned value = 15; 36 }; 37 38 template <typename T> struct FPUIntType {}; 39 template <> struct FPUIntType<float> { using Type = uint32_t; }; 40 template <> struct FPUIntType<double> { using Type = uint64_t; }; 41 42 #if !(defined(__x86_64__) || defined(__i386__)) 43 // TODO: This has to be extended for visual studio where long double and 44 // double are equivalent. 45 template <> struct MantissaWidth<long double> { 46 static constexpr unsigned value = 112; 47 }; 48 49 template <> struct FPUIntType<long double> { using Type = __uint128_t; }; 50 #endif 51 52 // A generic class to represent single precision, double precision, and quad 53 // precision IEEE 754 floating point formats. 54 // On most platforms, the 'float' type corresponds to single precision floating 55 // point numbers, the 'double' type corresponds to double precision floating 56 // point numers, and the 'long double' type corresponds to the quad precision 57 // floating numbers. On x86 platforms however, the 'long double' type maps to 58 // an x87 floating point format. This format is an IEEE 754 extension format. 59 // It is handled as an explicit specialization of this class. 60 template <typename T> struct __attribute__((packed)) FPBits { 61 static_assert(cpp::IsFloatingPointType<T>::Value, 62 "FPBits instantiated with invalid type."); 63 64 // Reinterpreting bits as an integer value and interpreting the bits of an 65 // integer value as a floating point value is used in tests. So, a convenient 66 // type is provided for such reinterpretations. 67 using UIntType = typename FPUIntType<T>::Type; 68 69 UIntType mantissa : MantissaWidth<T>::value; 70 uint16_t exponent : ExponentWidth<T>::value; 71 uint8_t sign : 1; 72 73 static constexpr int exponentBias = (1 << (ExponentWidth<T>::value - 1)) - 1; 74 static constexpr int maxExponent = (1 << ExponentWidth<T>::value) - 1; 75 76 static constexpr UIntType minSubnormal = UIntType(1); 77 static constexpr UIntType maxSubnormal = 78 (UIntType(1) << MantissaWidth<T>::value) - 1; 79 static constexpr UIntType minNormal = 80 (UIntType(1) << MantissaWidth<T>::value); 81 static constexpr UIntType maxNormal = 82 ((UIntType(maxExponent) - 1) << MantissaWidth<T>::value) | maxSubnormal; 83 84 // We don't want accidental type promotions/conversions so we require exact 85 // type match. 86 template <typename XType, 87 cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0> 88 explicit FPBits(XType x) { 89 *this = *reinterpret_cast<FPBits<T> *>(&x); 90 } 91 92 operator T() { return *reinterpret_cast<T *>(this); } 93 94 int getExponent() const { return int(exponent) - exponentBias; } 95 96 bool isZero() const { return mantissa == 0 && exponent == 0; } 97 98 bool isInf() const { return mantissa == 0 && exponent == maxExponent; } 99 100 bool isNaN() const { return exponent == maxExponent && mantissa != 0; } 101 102 bool isInfOrNaN() const { return exponent == maxExponent; } 103 104 // Methods below this are used by tests. 105 // The to and from integer bits converters are only used in tests. Hence, 106 // the potential software implementations of UIntType will not slow real 107 // code. 108 109 template <typename XType, 110 cpp::EnableIfType<cpp::IsSame<UIntType, XType>::Value, int> = 0> 111 explicit FPBits<long double>(XType x) { 112 // The last 4 bytes of v are ignored in case of i386. 113 *this = *reinterpret_cast<FPBits<T> *>(&x); 114 } 115 116 UIntType bitsAsUInt() const { 117 return *reinterpret_cast<const UIntType *>(this); 118 } 119 120 static FPBits<T> zero() { return FPBits(T(0.0)); } 121 122 static FPBits<T> negZero() { 123 FPBits<T> bits(T(0.0)); 124 bits.sign = 1; 125 return bits; 126 } 127 128 static FPBits<T> inf() { 129 FPBits<T> bits(T(0.0)); 130 bits.exponent = maxExponent; 131 return bits; 132 } 133 134 static FPBits<T> negInf() { 135 FPBits<T> bits(T(0.0)); 136 bits.exponent = maxExponent; 137 bits.sign = 1; 138 return bits; 139 } 140 141 static T buildNaN(UIntType v) { 142 FPBits<T> bits(T(0.0)); 143 bits.exponent = maxExponent; 144 bits.mantissa = v; 145 return bits; 146 } 147 }; 148 149 } // namespace fputil 150 } // namespace __llvm_libc 151 152 #if defined(__x86_64__) || defined(__i386__) 153 #include "utils/FPUtil/LongDoubleBitsX86.h" 154 #endif 155 156 #endif // LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H 157