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_LONG_DOUBLE_BITS_H
10 #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_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/properties/architectures.h"
17 #if !defined(LIBC_TARGET_ARCH_IS_X86)
18 #error "Invalid include"
21 #include "src/__support/FPUtil/FPBits.h"
25 namespace __llvm_libc
{
28 template <unsigned Width
> struct Padding
;
31 template <> struct Padding
<4> {
32 static constexpr unsigned VALUE
= 16;
36 template <> struct Padding
<8> {
37 static constexpr unsigned VALUE
= 48;
40 template <> struct FPBits
<long double> {
41 using UIntType
= UInt128
;
43 static constexpr int EXPONENT_BIAS
= 0x3FFF;
44 static constexpr int MAX_EXPONENT
= 0x7FFF;
45 static constexpr UIntType MIN_SUBNORMAL
= UIntType(1);
46 // Subnormal numbers include the implicit bit in x86 long double formats.
47 static constexpr UIntType MAX_SUBNORMAL
=
48 (UIntType(1) << (MantissaWidth
<long double>::VALUE
)) - 1;
49 static constexpr UIntType MIN_NORMAL
=
50 (UIntType(3) << MantissaWidth
<long double>::VALUE
);
51 static constexpr UIntType MAX_NORMAL
=
52 (UIntType(MAX_EXPONENT
- 1) << (MantissaWidth
<long double>::VALUE
+ 1)) |
53 (UIntType(1) << MantissaWidth
<long double>::VALUE
) | MAX_SUBNORMAL
;
55 using FloatProp
= FloatProperties
<long double>;
59 LIBC_INLINE
void set_mantissa(UIntType mantVal
) {
60 mantVal
&= (FloatProp::MANTISSA_MASK
);
61 bits
&= ~(FloatProp::MANTISSA_MASK
);
65 LIBC_INLINE UIntType
get_mantissa() const {
66 return bits
& FloatProp::MANTISSA_MASK
;
69 LIBC_INLINE UIntType
get_explicit_mantissa() const {
70 return bits
& (FloatProp::MANTISSA_MASK
| FloatProp::EXPLICIT_BIT_MASK
);
73 LIBC_INLINE
void set_unbiased_exponent(UIntType expVal
) {
75 (expVal
<< (FloatProp::BIT_WIDTH
- 1 - FloatProp::EXPONENT_WIDTH
)) &
76 FloatProp::EXPONENT_MASK
;
77 bits
&= ~(FloatProp::EXPONENT_MASK
);
81 LIBC_INLINE
uint16_t get_unbiased_exponent() const {
82 return uint16_t((bits
& FloatProp::EXPONENT_MASK
) >>
83 (FloatProp::BIT_WIDTH
- 1 - FloatProp::EXPONENT_WIDTH
));
86 LIBC_INLINE
void set_implicit_bit(bool implicitVal
) {
87 bits
&= ~(UIntType(1) << FloatProp::MANTISSA_WIDTH
);
88 bits
|= (UIntType(implicitVal
) << FloatProp::MANTISSA_WIDTH
);
91 LIBC_INLINE
bool get_implicit_bit() const {
92 return bool((bits
& (UIntType(1) << FloatProp::MANTISSA_WIDTH
)) >>
93 FloatProp::MANTISSA_WIDTH
);
96 LIBC_INLINE
void set_sign(bool signVal
) {
97 bits
&= ~(FloatProp::SIGN_MASK
);
98 UIntType sign1
= UIntType(signVal
) << (FloatProp::BIT_WIDTH
- 1);
102 LIBC_INLINE
bool get_sign() const {
103 return bool((bits
& FloatProp::SIGN_MASK
) >> (FloatProp::BIT_WIDTH
- 1));
106 FPBits() : bits(0) {}
108 template <typename XType
,
109 cpp::enable_if_t
<cpp::is_same_v
<long double, XType
>, int> = 0>
110 explicit FPBits(XType x
) : bits(cpp::bit_cast
<UIntType
>(x
)) {
111 // bits starts uninitialized, and setting it to a long double only
112 // overwrites the first 80 bits. This clears those upper bits.
113 bits
= bits
& ((UIntType(1) << 80) - 1);
116 template <typename XType
,
117 cpp::enable_if_t
<cpp::is_same_v
<XType
, UIntType
>, int> = 0>
118 explicit FPBits(XType x
) : bits(x
) {}
120 LIBC_INLINE
operator long double() {
121 return cpp::bit_cast
<long double>(bits
);
124 LIBC_INLINE UIntType
uintval() {
125 // We zero the padding bits as they can contain garbage.
126 static constexpr UIntType MASK
=
127 (UIntType(1) << (sizeof(long double) * 8 -
128 Padding
<sizeof(uintptr_t)>::VALUE
)) -
133 LIBC_INLINE
long double get_val() const {
134 return cpp::bit_cast
<long double>(bits
);
137 LIBC_INLINE
int get_exponent() const {
138 if (get_unbiased_exponent() == 0)
139 return int(1) - EXPONENT_BIAS
;
140 return int(get_unbiased_exponent()) - EXPONENT_BIAS
;
143 LIBC_INLINE
bool is_zero() const {
144 return get_unbiased_exponent() == 0 && get_mantissa() == 0 &&
145 get_implicit_bit() == 0;
148 LIBC_INLINE
bool is_inf() const {
149 return get_unbiased_exponent() == MAX_EXPONENT
&& get_mantissa() == 0 &&
150 get_implicit_bit() == 1;
153 LIBC_INLINE
bool is_nan() const {
154 if (get_unbiased_exponent() == MAX_EXPONENT
) {
155 return (get_implicit_bit() == 0) || get_mantissa() != 0;
156 } else if (get_unbiased_exponent() != 0) {
157 return get_implicit_bit() == 0;
162 LIBC_INLINE
bool is_inf_or_nan() const {
163 return (get_unbiased_exponent() == MAX_EXPONENT
) ||
164 (get_unbiased_exponent() != 0 && get_implicit_bit() == 0);
167 // Methods below this are used by tests.
169 LIBC_INLINE
static FPBits
<long double> zero() {
170 return FPBits
<long double>(0.0l);
173 LIBC_INLINE
static FPBits
<long double> neg_zero() {
174 FPBits
<long double> bits(0.0l);
179 LIBC_INLINE
static FPBits
<long double> inf() {
180 FPBits
<long double> bits(0.0l);
181 bits
.set_unbiased_exponent(MAX_EXPONENT
);
182 bits
.set_implicit_bit(1);
186 LIBC_INLINE
static FPBits
<long double> neg_inf() {
187 FPBits
<long double> bits(0.0l);
188 bits
.set_unbiased_exponent(MAX_EXPONENT
);
189 bits
.set_implicit_bit(1);
194 LIBC_INLINE
static long double build_nan(UIntType v
) {
195 FPBits
<long double> bits(0.0l);
196 bits
.set_unbiased_exponent(MAX_EXPONENT
);
197 bits
.set_implicit_bit(1);
198 bits
.set_mantissa(v
);
202 LIBC_INLINE
static long double build_quiet_nan(UIntType v
) {
203 return build_nan(FloatProp::QUIET_NAN_MASK
| v
);
206 LIBC_INLINE
static FPBits
<long double>
207 create_value(bool sign
, UIntType unbiased_exp
, UIntType mantissa
) {
208 FPBits
<long double> result
;
209 result
.set_sign(sign
);
210 result
.set_unbiased_exponent(unbiased_exp
);
211 result
.set_mantissa(mantissa
);
217 sizeof(FPBits
<long double>) == sizeof(long double),
218 "Internal long double representation does not match the machine format.");
220 } // namespace fputil
221 } // namespace __llvm_libc
223 #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_H