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 "PlatformDefs.h" 13 14 #include "utils/CPP/TypeTraits.h" 15 16 #include "FloatProperties.h" 17 #include <stdint.h> 18 19 namespace __llvm_libc { 20 namespace fputil { 21 22 template <typename T> struct MantissaWidth { 23 static constexpr unsigned value = FloatProperties<T>::mantissaWidth; 24 }; 25 26 template <typename T> struct ExponentWidth { 27 static constexpr unsigned value = FloatProperties<T>::exponentWidth; 28 }; 29 30 // A generic class to represent single precision, double precision, and quad 31 // precision IEEE 754 floating point formats. 32 // On most platforms, the 'float' type corresponds to single precision floating 33 // point numbers, the 'double' type corresponds to double precision floating 34 // point numers, and the 'long double' type corresponds to the quad precision 35 // floating numbers. On x86 platforms however, the 'long double' type maps to 36 // an x87 floating point format. This format is an IEEE 754 extension format. 37 // It is handled as an explicit specialization of this class. 38 template <typename T> union FPBits { 39 static_assert(cpp::IsFloatingPointType<T>::Value, 40 "FPBits instantiated with invalid type."); 41 42 // Reinterpreting bits as an integer value and interpreting the bits of an 43 // integer value as a floating point value is used in tests. So, a convenient 44 // type is provided for such reinterpretations. 45 using FloatProp = FloatProperties<T>; 46 // TODO: Change UintType name to BitsType for consistency. 47 using UIntType = typename FloatProp::BitsType; 48 49 UIntType bits; 50 setMantissa(UIntType mantVal)51 void setMantissa(UIntType mantVal) { 52 mantVal &= (FloatProp::mantissaMask); 53 bits &= ~(FloatProp::mantissaMask); 54 bits |= mantVal; 55 } 56 getMantissa()57 UIntType getMantissa() const { return bits & FloatProp::mantissaMask; } 58 setUnbiasedExponent(UIntType expVal)59 void setUnbiasedExponent(UIntType expVal) { 60 expVal = (expVal << (FloatProp::mantissaWidth)) & FloatProp::exponentMask; 61 bits &= ~(FloatProp::exponentMask); 62 bits |= expVal; 63 } 64 getUnbiasedExponent()65 uint16_t getUnbiasedExponent() const { 66 return uint16_t((bits & FloatProp::exponentMask) >> 67 (FloatProp::mantissaWidth)); 68 } 69 setSign(bool signVal)70 void setSign(bool signVal) { 71 bits &= ~(FloatProp::signMask); 72 UIntType sign = UIntType(signVal) << (FloatProp::bitWidth - 1); 73 bits |= sign; 74 } 75 getSign()76 bool getSign() const { 77 return ((bits & FloatProp::signMask) >> (FloatProp::bitWidth - 1)); 78 } 79 T val; 80 81 static_assert(sizeof(T) == sizeof(UIntType), 82 "Data type and integral representation have different sizes."); 83 84 static constexpr int exponentBias = (1 << (ExponentWidth<T>::value - 1)) - 1; 85 static constexpr int maxExponent = (1 << ExponentWidth<T>::value) - 1; 86 87 static constexpr UIntType minSubnormal = UIntType(1); 88 static constexpr UIntType maxSubnormal = 89 (UIntType(1) << MantissaWidth<T>::value) - 1; 90 static constexpr UIntType minNormal = 91 (UIntType(1) << MantissaWidth<T>::value); 92 static constexpr UIntType maxNormal = 93 ((UIntType(maxExponent) - 1) << MantissaWidth<T>::value) | maxSubnormal; 94 95 // We don't want accidental type promotions/conversions so we require exact 96 // type match. 97 template <typename XType, 98 cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0> FPBits(XType x)99 explicit FPBits(XType x) : val(x) {} 100 101 template <typename XType, 102 cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0> FPBits(XType x)103 explicit FPBits(XType x) : bits(x) {} 104 FPBits()105 FPBits() : bits(0) {} 106 T()107 explicit operator T() { return val; } 108 uintval()109 UIntType uintval() const { return bits; } 110 getExponent()111 int getExponent() const { return int(getUnbiasedExponent()) - exponentBias; } 112 isZero()113 bool isZero() const { 114 return getMantissa() == 0 && getUnbiasedExponent() == 0; 115 } 116 isInf()117 bool isInf() const { 118 return getMantissa() == 0 && getUnbiasedExponent() == maxExponent; 119 } 120 isNaN()121 bool isNaN() const { 122 return getUnbiasedExponent() == maxExponent && getMantissa() != 0; 123 } 124 isInfOrNaN()125 bool isInfOrNaN() const { return getUnbiasedExponent() == maxExponent; } 126 zero()127 static FPBits<T> zero() { return FPBits(); } 128 negZero()129 static FPBits<T> negZero() { 130 return FPBits(UIntType(1) << (sizeof(UIntType) * 8 - 1)); 131 } 132 inf()133 static FPBits<T> inf() { 134 FPBits<T> bits; 135 bits.setUnbiasedExponent(maxExponent); 136 return bits; 137 } 138 negInf()139 static FPBits<T> negInf() { 140 FPBits<T> bits = inf(); 141 bits.setSign(1); 142 return bits; 143 } 144 buildNaN(UIntType v)145 static T buildNaN(UIntType v) { 146 FPBits<T> bits = inf(); 147 bits.setMantissa(v); 148 return T(bits); 149 } 150 }; 151 152 } // namespace fputil 153 } // namespace __llvm_libc 154 155 #ifdef SPECIAL_X86_LONG_DOUBLE 156 #include "utils/FPUtil/LongDoubleBitsX86.h" 157 #endif 158 159 #endif // LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H 160