[libc][NFC] Move aligned access implementations to separate header
[llvm-project.git] / libc / src / __support / FPUtil / x86_64 / LongDoubleBits.h
blobbb03eea38be82f1705341d5a5be00b82b12c57bf
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_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"
19 #endif
21 #include "src/__support/FPUtil/FPBits.h"
23 #include <stdint.h>
25 namespace __llvm_libc {
26 namespace fputil {
28 template <unsigned Width> struct Padding;
30 // i386 padding.
31 template <> struct Padding<4> {
32 static constexpr unsigned VALUE = 16;
35 // x86_64 padding.
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>;
57 UIntType bits;
59 LIBC_INLINE void set_mantissa(UIntType mantVal) {
60 mantVal &= (FloatProp::MANTISSA_MASK);
61 bits &= ~(FloatProp::MANTISSA_MASK);
62 bits |= mantVal;
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) {
74 expVal =
75 (expVal << (FloatProp::BIT_WIDTH - 1 - FloatProp::EXPONENT_WIDTH)) &
76 FloatProp::EXPONENT_MASK;
77 bits &= ~(FloatProp::EXPONENT_MASK);
78 bits |= expVal;
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);
99 bits |= sign1;
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)) -
130 return bits & MASK;
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;
159 return false;
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);
175 bits.set_sign(1);
176 return bits;
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);
183 return bits;
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);
190 bits.set_sign(1);
191 return bits;
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);
199 return bits;
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);
212 return result;
216 static_assert(
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