Revert "[libc][NFC] Implement `FPBits` in terms of `FloatProperties` to reduce clutte...
[llvm-project.git] / libc / src / __support / FPUtil / x86_64 / LongDoubleBits.h
blobf1ef928f2308194321eb5913e8e0eba32aeccb72
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 //===----------------------------------------------------------------------===//
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"
20 #endif
22 #include "src/__support/FPUtil/FPBits.h"
24 #include <stdint.h>
26 namespace LIBC_NAMESPACE {
27 namespace fputil {
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>;
46 UIntType bits;
48 LIBC_INLINE constexpr void set_mantissa(UIntType mantVal) {
49 mantVal &= (FloatProp::MANTISSA_MASK);
50 bits &= ~(FloatProp::MANTISSA_MASK);
51 bits |= mantVal;
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) {
67 expVal =
68 (expVal << (FloatProp::BIT_WIDTH - 1 - FloatProp::EXPONENT_WIDTH)) &
69 FloatProp::EXPONENT_MASK;
70 bits &= ~(FloatProp::EXPONENT_MASK);
71 bits |= expVal;
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);
92 bits |= sign1;
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());
139 if (is_zero()) {
140 return 0;
141 } else if (biased_exp == 0) {
142 return 1 - EXPONENT_BIAS;
143 } else {
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;
164 return false;
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);
182 if (sign) {
183 bits.set_sign(true);
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);
195 return bits;
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);
224 return result;
228 static_assert(
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