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