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_SRC_SUPPORT_FPUTIL_FP_BITS_H 10 #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_FP_BITS_H 11 12 #include "PlatformDefs.h" 13 14 #include "src/__support/CPP/Bit.h" 15 #include "src/__support/CPP/TypeTraits.h" 16 #include "src/__support/FPUtil/builtin_wrappers.h" 17 #include "src/__support/common.h" 18 19 #include "FloatProperties.h" 20 #include <stdint.h> 21 22 namespace __llvm_libc { 23 namespace fputil { 24 25 template <typename T> struct MantissaWidth { 26 static constexpr unsigned VALUE = FloatProperties<T>::MANTISSA_WIDTH; 27 }; 28 29 template <typename T> struct ExponentWidth { 30 static constexpr unsigned VALUE = FloatProperties<T>::EXPONENT_WIDTH; 31 }; 32 33 // A generic class to represent single precision, double precision, and quad 34 // precision IEEE 754 floating point formats. 35 // On most platforms, the 'float' type corresponds to single precision floating 36 // point numbers, the 'double' type corresponds to double precision floating 37 // point numers, and the 'long double' type corresponds to the quad precision 38 // floating numbers. On x86 platforms however, the 'long double' type maps to 39 // an x87 floating point format. This format is an IEEE 754 extension format. 40 // It is handled as an explicit specialization of this class. 41 template <typename T> struct FPBits { 42 static_assert(cpp::IsFloatingPointType<T>::Value, 43 "FPBits instantiated with invalid type."); 44 45 // Reinterpreting bits as an integer value and interpreting the bits of an 46 // integer value as a floating point value is used in tests. So, a convenient 47 // type is provided for such reinterpretations. 48 using FloatProp = FloatProperties<T>; 49 // TODO: Change UintType name to BitsType for consistency. 50 using UIntType = typename FloatProp::BitsType; 51 52 UIntType bits; 53 set_mantissaFPBits54 void set_mantissa(UIntType mantVal) { 55 mantVal &= (FloatProp::MANTISSA_MASK); 56 bits &= ~(FloatProp::MANTISSA_MASK); 57 bits |= mantVal; 58 } 59 get_mantissaFPBits60 UIntType get_mantissa() const { return bits & FloatProp::MANTISSA_MASK; } 61 set_unbiased_exponentFPBits62 void set_unbiased_exponent(UIntType expVal) { 63 expVal = (expVal << (FloatProp::MANTISSA_WIDTH)) & FloatProp::EXPONENT_MASK; 64 bits &= ~(FloatProp::EXPONENT_MASK); 65 bits |= expVal; 66 } 67 get_unbiased_exponentFPBits68 uint16_t get_unbiased_exponent() const { 69 return uint16_t((bits & FloatProp::EXPONENT_MASK) >> 70 (FloatProp::MANTISSA_WIDTH)); 71 } 72 73 // The function return mantissa with the implicit bit set iff the current 74 // value is a valid normal number. get_explicit_mantissaFPBits75 constexpr UIntType get_explicit_mantissa() { 76 return ((get_unbiased_exponent() > 0 && !is_inf_or_nan()) 77 ? (FloatProp::MANTISSA_MASK + 1) 78 : 0) | 79 (FloatProp::MANTISSA_MASK & bits); 80 } 81 set_signFPBits82 void set_sign(bool signVal) { 83 bits |= FloatProp::SIGN_MASK; 84 if (!signVal) 85 bits -= FloatProp::SIGN_MASK; 86 } 87 get_signFPBits88 bool get_sign() const { return (bits & FloatProp::SIGN_MASK) != 0; } 89 90 static_assert(sizeof(T) == sizeof(UIntType), 91 "Data type and integral representation have different sizes."); 92 93 static constexpr int EXPONENT_BIAS = (1 << (ExponentWidth<T>::VALUE - 1)) - 1; 94 static constexpr int MAX_EXPONENT = (1 << ExponentWidth<T>::VALUE) - 1; 95 96 static constexpr UIntType MIN_SUBNORMAL = UIntType(1); 97 static constexpr UIntType MAX_SUBNORMAL = 98 (UIntType(1) << MantissaWidth<T>::VALUE) - 1; 99 static constexpr UIntType MIN_NORMAL = 100 (UIntType(1) << MantissaWidth<T>::VALUE); 101 static constexpr UIntType MAX_NORMAL = 102 ((UIntType(MAX_EXPONENT) - 1) << MantissaWidth<T>::VALUE) | MAX_SUBNORMAL; 103 104 // We don't want accidental type promotions/conversions, so we require exact 105 // type match. 106 template <typename XType, 107 cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0> FPBitsFPBits108 constexpr explicit FPBits(XType x) 109 : bits(__llvm_libc::bit_cast<UIntType>(x)) {} 110 111 template <typename XType, 112 cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0> FPBitsFPBits113 constexpr explicit FPBits(XType x) : bits(x) {} 114 FPBitsFPBits115 FPBits() : bits(0) {} 116 get_valFPBits117 T get_val() const { return __llvm_libc::bit_cast<T>(bits); } 118 set_valFPBits119 void set_val(T value) { bits = __llvm_libc::bit_cast<UIntType>(value); } 120 TFPBits121 explicit operator T() const { return get_val(); } 122 uintvalFPBits123 UIntType uintval() const { return bits; } 124 get_exponentFPBits125 int get_exponent() const { 126 return int(get_unbiased_exponent()) - EXPONENT_BIAS; 127 } 128 is_zeroFPBits129 bool is_zero() const { 130 // Remove sign bit by shift 131 return (bits << 1) == 0; 132 } 133 is_infFPBits134 bool is_inf() const { 135 return (bits & FloatProp::EXP_MANT_MASK) == FloatProp::EXPONENT_MASK; 136 } 137 is_nanFPBits138 bool is_nan() const { 139 return (bits & FloatProp::EXP_MANT_MASK) > FloatProp::EXPONENT_MASK; 140 } 141 is_quiet_nanFPBits142 bool is_quiet_nan() const { 143 return (bits & FloatProp::EXP_MANT_MASK) == 144 (FloatProp::EXPONENT_MASK | FloatProp::QUIET_NAN_MASK); 145 } 146 is_inf_or_nanFPBits147 bool is_inf_or_nan() const { 148 return (bits & FloatProp::EXPONENT_MASK) == FloatProp::EXPONENT_MASK; 149 } 150 151 static constexpr FPBits<T> zero(bool sign = false) { 152 return FPBits(sign ? FloatProp::SIGN_MASK : UIntType(0)); 153 } 154 neg_zeroFPBits155 static constexpr FPBits<T> neg_zero() { return zero(true); } 156 infFPBits157 static constexpr FPBits<T> inf() { 158 FPBits<T> bits; 159 bits.set_unbiased_exponent(MAX_EXPONENT); 160 return bits; 161 } 162 neg_infFPBits163 static constexpr FPBits<T> neg_inf() { 164 FPBits<T> bits = inf(); 165 bits.set_sign(1); 166 return bits; 167 } 168 build_nanFPBits169 static constexpr T build_nan(UIntType v) { 170 FPBits<T> bits = inf(); 171 bits.set_mantissa(v); 172 return T(bits); 173 } 174 175 // The function convert integer number and unbiased exponent to proper float 176 // T type: 177 // Result = number * 2^(ep+1 - exponent_bias) 178 // Be careful! 179 // 1) "ep" is raw exponent value. 180 // 2) The function add to +1 to ep for seamless normalized to denormalized 181 // transition. 182 // 3) The function did not check exponent high limit. 183 // 4) "number" zero value is not processed correctly. 184 // 5) Number is unsigned, so the result can be only positive. make_valueFPBits185 inline static constexpr FPBits<T> make_value(UIntType number, int ep) { 186 FPBits<T> result; 187 // offset: +1 for sign, but -1 for implicit first bit 188 int lz = fputil::unsafe_clz(number) - FloatProp::EXPONENT_WIDTH; 189 number <<= lz; 190 ep -= lz; 191 192 if (likely(ep >= 0)) { 193 // Implicit number bit will be removed by mask 194 result.set_mantissa(number); 195 result.set_unbiased_exponent(ep + 1); 196 } else { 197 result.set_mantissa(number >> -ep); 198 } 199 return result; 200 } 201 }; 202 203 } // namespace fputil 204 } // namespace __llvm_libc 205 206 #ifdef SPECIAL_X86_LONG_DOUBLE 207 #include "x86_64/LongDoubleBits.h" 208 #endif 209 210 #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_FP_BITS_H 211