1 //===-- Bit representation of x86 long double numbers -----------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_LONGDOUBLEBITS_H
10 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_LONGDOUBLEBITS_H
12 #include "src/__support/CPP/bit.h"
13 #include "src/__support/UInt128.h"
14 #include "src/__support/common.h"
15 #include "src/__support/macros/attributes.h" // LIBC_INLINE
16 #include "src/__support/macros/properties/architectures.h"
18 #if !defined(LIBC_TARGET_ARCH_IS_X86)
19 #error "Invalid include"
22 #include "src/__support/FPUtil/FPBits.h"
26 namespace LIBC_NAMESPACE
{
29 template <> struct FPBits
<long double> {
30 using UIntType
= UInt128
;
32 static constexpr int EXPONENT_BIAS
= 0x3FFF;
33 static constexpr int MAX_EXPONENT
= 0x7FFF;
34 static constexpr UIntType MIN_SUBNORMAL
= UIntType(1);
35 // Subnormal numbers include the implicit bit in x86 long double formats.
36 static constexpr UIntType MAX_SUBNORMAL
=
37 (UIntType(1) << (MantissaWidth
<long double>::VALUE
)) - 1;
38 static constexpr UIntType MIN_NORMAL
=
39 (UIntType(3) << MantissaWidth
<long double>::VALUE
);
40 static constexpr UIntType MAX_NORMAL
=
41 (UIntType(MAX_EXPONENT
- 1) << (MantissaWidth
<long double>::VALUE
+ 1)) |
42 (UIntType(1) << MantissaWidth
<long double>::VALUE
) | MAX_SUBNORMAL
;
44 using FloatProp
= FloatProperties
<long double>;
48 LIBC_INLINE
constexpr void set_mantissa(UIntType mantVal
) {
49 mantVal
&= (FloatProp::MANTISSA_MASK
);
50 bits
&= ~(FloatProp::MANTISSA_MASK
);
54 LIBC_INLINE
constexpr UIntType
get_mantissa() const {
55 return bits
& FloatProp::MANTISSA_MASK
;
58 LIBC_INLINE
constexpr UIntType
get_explicit_mantissa() const {
59 // The x86 80 bit float represents the leading digit of the mantissa
60 // explicitly. This is the mask for that bit.
61 constexpr UIntType EXPLICIT_BIT_MASK
=
62 (UIntType(1) << FloatProp::MANTISSA_WIDTH
);
63 return bits
& (FloatProp::MANTISSA_MASK
| EXPLICIT_BIT_MASK
);
66 LIBC_INLINE
constexpr void set_biased_exponent(UIntType expVal
) {
68 (expVal
<< (FloatProp::BIT_WIDTH
- 1 - FloatProp::EXPONENT_WIDTH
)) &
69 FloatProp::EXPONENT_MASK
;
70 bits
&= ~(FloatProp::EXPONENT_MASK
);
74 LIBC_INLINE
constexpr uint16_t get_biased_exponent() const {
75 return uint16_t((bits
& FloatProp::EXPONENT_MASK
) >>
76 (FloatProp::BIT_WIDTH
- 1 - FloatProp::EXPONENT_WIDTH
));
79 LIBC_INLINE
constexpr void set_implicit_bit(bool implicitVal
) {
80 bits
&= ~(UIntType(1) << FloatProp::MANTISSA_WIDTH
);
81 bits
|= (UIntType(implicitVal
) << FloatProp::MANTISSA_WIDTH
);
84 LIBC_INLINE
constexpr bool get_implicit_bit() const {
85 return bool((bits
& (UIntType(1) << FloatProp::MANTISSA_WIDTH
)) >>
86 FloatProp::MANTISSA_WIDTH
);
89 LIBC_INLINE
constexpr void set_sign(bool signVal
) {
90 bits
&= ~(FloatProp::SIGN_MASK
);
91 UIntType sign1
= UIntType(signVal
) << (FloatProp::BIT_WIDTH
- 1);
95 LIBC_INLINE
constexpr bool get_sign() const {
96 return bool((bits
& FloatProp::SIGN_MASK
) >> (FloatProp::BIT_WIDTH
- 1));
99 LIBC_INLINE
constexpr FPBits() : bits(0) {}
101 template <typename XType
,
102 cpp::enable_if_t
<cpp::is_same_v
<long double, XType
>, int> = 0>
103 LIBC_INLINE
constexpr explicit FPBits(XType x
)
104 : bits(cpp::bit_cast
<UIntType
>(x
)) {
105 // bits starts uninitialized, and setting it to a long double only
106 // overwrites the first 80 bits. This clears those upper bits.
107 bits
= bits
& ((UIntType(1) << 80) - 1);
110 template <typename XType
,
111 cpp::enable_if_t
<cpp::is_same_v
<XType
, UIntType
>, int> = 0>
112 LIBC_INLINE
constexpr explicit FPBits(XType x
) : bits(x
) {}
114 LIBC_INLINE
constexpr operator long double() {
115 return cpp::bit_cast
<long double>(bits
);
118 LIBC_INLINE
constexpr UIntType
uintval() {
119 // We zero the padding bits as they can contain garbage.
120 return bits
& FloatProp::FP_MASK
;
123 LIBC_INLINE
constexpr long double get_val() const {
124 return cpp::bit_cast
<long double>(bits
);
127 LIBC_INLINE
constexpr int get_exponent() const {
128 return int(get_biased_exponent()) - EXPONENT_BIAS
;
131 // If the number is subnormal, the exponent is treated as if it were the
132 // minimum exponent for a normal number. This is to keep continuity between
133 // the normal and subnormal ranges, but it causes problems for functions where
134 // values are calculated from the exponent, since just subtracting the bias
135 // will give a slightly incorrect result. Additionally, zero has an exponent
136 // of zero, and that should actually be treated as zero.
137 LIBC_INLINE
constexpr int get_explicit_exponent() const {
138 const int biased_exp
= int(get_biased_exponent());
141 } else if (biased_exp
== 0) {
142 return 1 - EXPONENT_BIAS
;
144 return biased_exp
- EXPONENT_BIAS
;
148 LIBC_INLINE
constexpr bool is_zero() const {
149 return get_biased_exponent() == 0 && get_mantissa() == 0 &&
150 get_implicit_bit() == 0;
153 LIBC_INLINE
constexpr bool is_inf() const {
154 return get_biased_exponent() == MAX_EXPONENT
&& get_mantissa() == 0 &&
155 get_implicit_bit() == 1;
158 LIBC_INLINE
constexpr bool is_nan() const {
159 if (get_biased_exponent() == MAX_EXPONENT
) {
160 return (get_implicit_bit() == 0) || get_mantissa() != 0;
161 } else if (get_biased_exponent() != 0) {
162 return get_implicit_bit() == 0;
167 LIBC_INLINE
constexpr bool is_inf_or_nan() const {
168 return (get_biased_exponent() == MAX_EXPONENT
) ||
169 (get_biased_exponent() != 0 && get_implicit_bit() == 0);
172 // Methods below this are used by tests.
174 LIBC_INLINE
static constexpr long double zero() { return 0.0l; }
176 LIBC_INLINE
static constexpr long double neg_zero() { return -0.0l; }
178 LIBC_INLINE
static constexpr long double inf(bool sign
= false) {
179 FPBits
<long double> bits(0.0l);
180 bits
.set_biased_exponent(MAX_EXPONENT
);
181 bits
.set_implicit_bit(1);
185 return bits
.get_val();
188 LIBC_INLINE
static constexpr long double neg_inf() { return inf(true); }
190 LIBC_INLINE
static constexpr long double build_nan(UIntType v
) {
191 FPBits
<long double> bits(0.0l);
192 bits
.set_biased_exponent(MAX_EXPONENT
);
193 bits
.set_implicit_bit(1);
194 bits
.set_mantissa(v
);
198 LIBC_INLINE
static constexpr long double build_quiet_nan(UIntType v
) {
199 return build_nan(FloatProp::QUIET_NAN_MASK
| v
);
202 LIBC_INLINE
static constexpr long double min_normal() {
203 return FPBits(MIN_NORMAL
).get_val();
206 LIBC_INLINE
static constexpr long double max_normal() {
207 return FPBits(MAX_NORMAL
).get_val();
210 LIBC_INLINE
static constexpr long double min_denormal() {
211 return FPBits(MIN_SUBNORMAL
).get_val();
214 LIBC_INLINE
static constexpr long double max_denormal() {
215 return FPBits(MAX_SUBNORMAL
).get_val();
218 LIBC_INLINE
static constexpr FPBits
<long double>
219 create_value(bool sign
, UIntType biased_exp
, UIntType mantissa
) {
220 FPBits
<long double> result
;
221 result
.set_sign(sign
);
222 result
.set_biased_exponent(biased_exp
);
223 result
.set_mantissa(mantissa
);
229 sizeof(FPBits
<long double>) == sizeof(long double),
230 "Internal long double representation does not match the machine format.");
232 } // namespace fputil
233 } // namespace LIBC_NAMESPACE
235 #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_LONGDOUBLEBITS_H