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 <> struct MantissaWidth<long double> { 20 static constexpr unsigned value = 63; 21 }; 22 23 template <unsigned Width> struct Padding; 24 25 // i386 padding. 26 template <> struct Padding<4> { static constexpr unsigned value = 16; }; 27 28 // x86_64 padding. 29 template <> struct Padding<8> { static constexpr unsigned value = 48; }; 30 31 template <> struct __attribute__((packed)) FPBits<long double> { 32 using UIntType = __uint128_t; 33 34 static constexpr int exponentBias = 0x3FFF; 35 static constexpr int maxExponent = 0x7FFF; 36 static constexpr UIntType minSubnormal = UIntType(1); 37 // Subnormal numbers include the implicit bit in x86 long double formats. 38 static constexpr UIntType maxSubnormal = 39 (UIntType(1) << (MantissaWidth<long double>::value + 1)) - 1; 40 static constexpr UIntType minNormal = 41 (UIntType(3) << MantissaWidth<long double>::value); 42 static constexpr UIntType maxNormal = 43 ((UIntType(maxExponent) - 1) << (MantissaWidth<long double>::value + 1)) | 44 (UIntType(1) << MantissaWidth<long double>::value) | maxSubnormal; 45 46 UIntType mantissa : MantissaWidth<long double>::value; 47 uint8_t implicitBit : 1; 48 uint16_t exponent : ExponentWidth<long double>::value; 49 uint8_t sign : 1; 50 uint64_t padding : Padding<sizeof(uintptr_t)>::value; 51 52 template <typename XType, 53 cpp::EnableIfType<cpp::IsSame<long double, XType>::Value, int> = 0> 54 explicit FPBits<long double>(XType x) { 55 *this = *reinterpret_cast<FPBits<long double> *>(&x); 56 } 57 58 operator long double() { return *reinterpret_cast<long double *>(this); } 59 60 int getExponent() const { 61 if (exponent == 0) 62 return int(1) - exponentBias; 63 return int(exponent) - exponentBias; 64 } 65 66 bool isZero() const { 67 return exponent == 0 && mantissa == 0 && implicitBit == 0; 68 } 69 70 bool isInf() const { 71 return exponent == maxExponent && mantissa == 0 && implicitBit == 1; 72 } 73 74 bool isNaN() const { 75 if (exponent == maxExponent) { 76 return (implicitBit == 0) || mantissa != 0; 77 } else if (exponent != 0) { 78 return implicitBit == 0; 79 } 80 return false; 81 } 82 83 bool isInfOrNaN() const { 84 return (exponent == maxExponent) || (exponent != 0 && implicitBit == 0); 85 } 86 87 // Methods below this are used by tests. 88 89 template <typename XType, 90 cpp::EnableIfType<cpp::IsSame<UIntType, XType>::Value, int> = 0> 91 explicit FPBits<long double>(XType x) { 92 // The last 4 bytes of v are ignored in case of i386. 93 *this = *reinterpret_cast<FPBits<long double> *>(&x); 94 } 95 96 UIntType bitsAsUInt() const { 97 // We cannot just return the bits as is as it will lead to reading 98 // out of bounds in case of i386. So, we first copy the wider value 99 // before returning the value. This makes the last 4 bytes are always 100 // zero in case i386. 101 UIntType result = UIntType(0); 102 *reinterpret_cast<FPBits<long double> *>(&result) = *this; 103 104 // Even though we zero out |result| before copying the long double value, 105 // there can be garbage bits in the padding. So, we zero the padding bits 106 // in |result|. 107 static constexpr UIntType mask = 108 (UIntType(1) << (sizeof(long double) * 8 - 109 Padding<sizeof(uintptr_t)>::value)) - 110 1; 111 return result & mask; 112 } 113 114 static FPBits<long double> zero() { return FPBits<long double>(0.0l); } 115 116 static FPBits<long double> negZero() { 117 FPBits<long double> bits(0.0l); 118 bits.sign = 1; 119 return bits; 120 } 121 122 static FPBits<long double> inf() { 123 FPBits<long double> bits(0.0l); 124 bits.exponent = maxExponent; 125 bits.implicitBit = 1; 126 return bits; 127 } 128 129 static FPBits<long double> negInf() { 130 FPBits<long double> bits(0.0l); 131 bits.exponent = maxExponent; 132 bits.implicitBit = 1; 133 bits.sign = 1; 134 return bits; 135 } 136 137 static long double buildNaN(UIntType v) { 138 FPBits<long double> bits(0.0l); 139 bits.exponent = maxExponent; 140 bits.implicitBit = 1; 141 bits.mantissa = v; 142 return bits; 143 } 144 }; 145 146 static_assert( 147 sizeof(FPBits<long double>) == sizeof(long double), 148 "Internal long double representation does not match the machine format."); 149 150 } // namespace fputil 151 } // namespace __llvm_libc 152 153 #endif // LLVM_LIBC_UTILS_FPUTIL_LONG_DOUBLE_BITS_X86_H 154