1 //===-- Bit representation of x86 long double 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_LONG_DOUBLE_BITS_X86_H 10 #define LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H 11 12 #include "FPBits.h" 13 14 #include <stdint.h> 15 16 namespace __llvm_libc { 17 namespace fputil { 18 19 template <unsigned Width> struct Padding; 20 21 // i386 padding. 22 template <> struct Padding<4> { static constexpr unsigned value = 16; }; 23 24 // x86_64 padding. 25 template <> struct Padding<8> { static constexpr unsigned value = 48; }; 26 27 template <> union FPBits<long double> { 28 using UIntType = __uint128_t; 29 30 static constexpr int exponentBias = 0x3FFF; 31 static constexpr int maxExponent = 0x7FFF; 32 static constexpr UIntType minSubnormal = UIntType(1); 33 // Subnormal numbers include the implicit bit in x86 long double formats. 34 static constexpr UIntType maxSubnormal = 35 (UIntType(1) << (MantissaWidth<long double>::value)) - 1; 36 static constexpr UIntType minNormal = 37 (UIntType(3) << MantissaWidth<long double>::value); 38 static constexpr UIntType maxNormal = 39 ((UIntType(maxExponent) - 1) << (MantissaWidth<long double>::value + 1)) | 40 (UIntType(1) << MantissaWidth<long double>::value) | maxSubnormal; 41 42 using FloatProp = FloatProperties<long double>; 43 44 UIntType bits; 45 46 void setMantissa(UIntType mantVal) { 47 mantVal &= (FloatProp::mantissaMask); 48 bits &= ~(FloatProp::mantissaMask); 49 bits |= mantVal; 50 } 51 52 UIntType getMantissa() const { return bits & FloatProp::mantissaMask; } 53 54 void setUnbiasedExponent(UIntType expVal) { 55 expVal = (expVal << (FloatProp::bitWidth - 1 - FloatProp::exponentWidth)) & 56 FloatProp::exponentMask; 57 bits &= ~(FloatProp::exponentMask); 58 bits |= expVal; 59 } 60 61 uint16_t getUnbiasedExponent() const { 62 return uint16_t((bits & FloatProp::exponentMask) >> 63 (FloatProp::bitWidth - 1 - FloatProp::exponentWidth)); 64 } 65 66 void setImplicitBit(bool implicitVal) { 67 bits &= ~(UIntType(1) << FloatProp::mantissaWidth); 68 bits |= (UIntType(implicitVal) << FloatProp::mantissaWidth); 69 } 70 71 bool getImplicitBit() const { 72 return ((bits & (UIntType(1) << FloatProp::mantissaWidth)) >> 73 FloatProp::mantissaWidth); 74 } 75 76 void setSign(bool signVal) { 77 bits &= ~(FloatProp::signMask); 78 UIntType sign1 = UIntType(signVal) << (FloatProp::bitWidth - 1); 79 bits |= sign1; 80 } 81 82 bool getSign() const { 83 return ((bits & FloatProp::signMask) >> (FloatProp::bitWidth - 1)); 84 } 85 86 long double val; 87 88 FPBits() : bits(0) {} 89 90 template <typename XType, 91 cpp::EnableIfType<cpp::IsSame<long double, XType>::Value, int> = 0> 92 explicit FPBits(XType x) : val(x) {} 93 94 template <typename XType, 95 cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0> 96 explicit FPBits(XType x) : bits(x) {} 97 98 operator long double() { return val; } 99 100 UIntType uintval() { 101 // We zero the padding bits as they can contain garbage. 102 static constexpr UIntType mask = 103 (UIntType(1) << (sizeof(long double) * 8 - 104 Padding<sizeof(uintptr_t)>::value)) - 105 1; 106 return bits & mask; 107 } 108 109 int getExponent() const { 110 if (getUnbiasedExponent() == 0) 111 return int(1) - exponentBias; 112 return int(getUnbiasedExponent()) - exponentBias; 113 } 114 115 bool isZero() const { 116 return getUnbiasedExponent() == 0 && getMantissa() == 0 && 117 getImplicitBit() == 0; 118 } 119 120 bool isInf() const { 121 return getUnbiasedExponent() == maxExponent && getMantissa() == 0 && 122 getImplicitBit() == 1; 123 } 124 125 bool isNaN() const { 126 if (getUnbiasedExponent() == maxExponent) { 127 return (getImplicitBit() == 0) || getMantissa() != 0; 128 } else if (getUnbiasedExponent() != 0) { 129 return getImplicitBit() == 0; 130 } 131 return false; 132 } 133 134 bool isInfOrNaN() const { 135 return (getUnbiasedExponent() == maxExponent) || 136 (getUnbiasedExponent() != 0 && getImplicitBit() == 0); 137 } 138 139 // Methods below this are used by tests. 140 141 static FPBits<long double> zero() { return FPBits<long double>(0.0l); } 142 143 static FPBits<long double> negZero() { 144 FPBits<long double> bits(0.0l); 145 bits.setSign(1); 146 return bits; 147 } 148 149 static FPBits<long double> inf() { 150 FPBits<long double> bits(0.0l); 151 bits.setUnbiasedExponent(maxExponent); 152 bits.setImplicitBit(1); 153 return bits; 154 } 155 156 static FPBits<long double> negInf() { 157 FPBits<long double> bits(0.0l); 158 bits.setUnbiasedExponent(maxExponent); 159 bits.setImplicitBit(1); 160 bits.setSign(1); 161 return bits; 162 } 163 164 static long double buildNaN(UIntType v) { 165 FPBits<long double> bits(0.0l); 166 bits.setUnbiasedExponent(maxExponent); 167 bits.setImplicitBit(1); 168 bits.setMantissa(v); 169 return bits; 170 } 171 }; 172 173 static_assert( 174 sizeof(FPBits<long double>) == sizeof(long double), 175 "Internal long double representation does not match the machine format."); 176 177 } // namespace fputil 178 } // namespace __llvm_libc 179 180 #endif // LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H 181