1 //===-- Abstract class for bit manipulation of float 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_SRC_SUPPORT_FPUTIL_FP_BITS_H
10 #define LLVM_LIBC_SRC_SUPPORT_FPUTIL_FP_BITS_H
11 
12 #include "PlatformDefs.h"
13 
14 #include "src/__support/CPP/Bit.h"
15 #include "src/__support/CPP/TypeTraits.h"
16 #include "src/__support/FPUtil/builtin_wrappers.h"
17 #include "src/__support/common.h"
18 
19 #include "FloatProperties.h"
20 #include <stdint.h>
21 
22 namespace __llvm_libc {
23 namespace fputil {
24 
25 template <typename T> struct MantissaWidth {
26   static constexpr unsigned VALUE = FloatProperties<T>::MANTISSA_WIDTH;
27 };
28 
29 template <typename T> struct ExponentWidth {
30   static constexpr unsigned VALUE = FloatProperties<T>::EXPONENT_WIDTH;
31 };
32 
33 // A generic class to represent single precision, double precision, and quad
34 // precision IEEE 754 floating point formats.
35 // On most platforms, the 'float' type corresponds to single precision floating
36 // point numbers, the 'double' type corresponds to double precision floating
37 // point numers, and the 'long double' type corresponds to the quad precision
38 // floating numbers. On x86 platforms however, the 'long double' type maps to
39 // an x87 floating point format. This format is an IEEE 754 extension format.
40 // It is handled as an explicit specialization of this class.
41 template <typename T> struct FPBits {
42   static_assert(cpp::IsFloatingPointType<T>::Value,
43                 "FPBits instantiated with invalid type.");
44 
45   // Reinterpreting bits as an integer value and interpreting the bits of an
46   // integer value as a floating point value is used in tests. So, a convenient
47   // type is provided for such reinterpretations.
48   using FloatProp = FloatProperties<T>;
49   // TODO: Change UintType name to BitsType for consistency.
50   using UIntType = typename FloatProp::BitsType;
51 
52   UIntType bits;
53 
set_mantissaFPBits54   void set_mantissa(UIntType mantVal) {
55     mantVal &= (FloatProp::MANTISSA_MASK);
56     bits &= ~(FloatProp::MANTISSA_MASK);
57     bits |= mantVal;
58   }
59 
get_mantissaFPBits60   UIntType get_mantissa() const { return bits & FloatProp::MANTISSA_MASK; }
61 
set_unbiased_exponentFPBits62   void set_unbiased_exponent(UIntType expVal) {
63     expVal = (expVal << (FloatProp::MANTISSA_WIDTH)) & FloatProp::EXPONENT_MASK;
64     bits &= ~(FloatProp::EXPONENT_MASK);
65     bits |= expVal;
66   }
67 
get_unbiased_exponentFPBits68   uint16_t get_unbiased_exponent() const {
69     return uint16_t((bits & FloatProp::EXPONENT_MASK) >>
70                     (FloatProp::MANTISSA_WIDTH));
71   }
72 
73   // The function return mantissa with the implicit bit set iff the current
74   // value is a valid normal number.
get_explicit_mantissaFPBits75   constexpr UIntType get_explicit_mantissa() {
76     return ((get_unbiased_exponent() > 0 && !is_inf_or_nan())
77                 ? (FloatProp::MANTISSA_MASK + 1)
78                 : 0) |
79            (FloatProp::MANTISSA_MASK & bits);
80   }
81 
set_signFPBits82   void set_sign(bool signVal) {
83     bits |= FloatProp::SIGN_MASK;
84     if (!signVal)
85       bits -= FloatProp::SIGN_MASK;
86   }
87 
get_signFPBits88   bool get_sign() const { return (bits & FloatProp::SIGN_MASK) != 0; }
89 
90   static_assert(sizeof(T) == sizeof(UIntType),
91                 "Data type and integral representation have different sizes.");
92 
93   static constexpr int EXPONENT_BIAS = (1 << (ExponentWidth<T>::VALUE - 1)) - 1;
94   static constexpr int MAX_EXPONENT = (1 << ExponentWidth<T>::VALUE) - 1;
95 
96   static constexpr UIntType MIN_SUBNORMAL = UIntType(1);
97   static constexpr UIntType MAX_SUBNORMAL =
98       (UIntType(1) << MantissaWidth<T>::VALUE) - 1;
99   static constexpr UIntType MIN_NORMAL =
100       (UIntType(1) << MantissaWidth<T>::VALUE);
101   static constexpr UIntType MAX_NORMAL =
102       ((UIntType(MAX_EXPONENT) - 1) << MantissaWidth<T>::VALUE) | MAX_SUBNORMAL;
103 
104   // We don't want accidental type promotions/conversions, so we require exact
105   // type match.
106   template <typename XType,
107             cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0>
FPBitsFPBits108   constexpr explicit FPBits(XType x)
109       : bits(__llvm_libc::bit_cast<UIntType>(x)) {}
110 
111   template <typename XType,
112             cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0>
FPBitsFPBits113   constexpr explicit FPBits(XType x) : bits(x) {}
114 
FPBitsFPBits115   FPBits() : bits(0) {}
116 
get_valFPBits117   T get_val() const { return __llvm_libc::bit_cast<T>(bits); }
118 
set_valFPBits119   void set_val(T value) { bits = __llvm_libc::bit_cast<UIntType>(value); }
120 
TFPBits121   explicit operator T() const { return get_val(); }
122 
uintvalFPBits123   UIntType uintval() const { return bits; }
124 
get_exponentFPBits125   int get_exponent() const {
126     return int(get_unbiased_exponent()) - EXPONENT_BIAS;
127   }
128 
is_zeroFPBits129   bool is_zero() const {
130     // Remove sign bit by shift
131     return (bits << 1) == 0;
132   }
133 
is_infFPBits134   bool is_inf() const {
135     return (bits & FloatProp::EXP_MANT_MASK) == FloatProp::EXPONENT_MASK;
136   }
137 
is_nanFPBits138   bool is_nan() const {
139     return (bits & FloatProp::EXP_MANT_MASK) > FloatProp::EXPONENT_MASK;
140   }
141 
is_quiet_nanFPBits142   bool is_quiet_nan() const {
143     return (bits & FloatProp::EXP_MANT_MASK) ==
144            (FloatProp::EXPONENT_MASK | FloatProp::QUIET_NAN_MASK);
145   }
146 
is_inf_or_nanFPBits147   bool is_inf_or_nan() const {
148     return (bits & FloatProp::EXPONENT_MASK) == FloatProp::EXPONENT_MASK;
149   }
150 
151   static constexpr FPBits<T> zero(bool sign = false) {
152     return FPBits(sign ? FloatProp::SIGN_MASK : UIntType(0));
153   }
154 
neg_zeroFPBits155   static constexpr FPBits<T> neg_zero() { return zero(true); }
156 
infFPBits157   static constexpr FPBits<T> inf() {
158     FPBits<T> bits;
159     bits.set_unbiased_exponent(MAX_EXPONENT);
160     return bits;
161   }
162 
neg_infFPBits163   static constexpr FPBits<T> neg_inf() {
164     FPBits<T> bits = inf();
165     bits.set_sign(1);
166     return bits;
167   }
168 
build_nanFPBits169   static constexpr T build_nan(UIntType v) {
170     FPBits<T> bits = inf();
171     bits.set_mantissa(v);
172     return T(bits);
173   }
174 
175   // The function convert integer number and unbiased exponent to proper float
176   // T type:
177   //   Result = number * 2^(ep+1 - exponent_bias)
178   // Be careful!
179   //   1) "ep" is raw exponent value.
180   //   2) The function add to +1 to ep for seamless normalized to denormalized
181   //      transition.
182   //   3) The function did not check exponent high limit.
183   //   4) "number" zero value is not processed correctly.
184   //   5) Number is unsigned, so the result can be only positive.
make_valueFPBits185   inline static constexpr FPBits<T> make_value(UIntType number, int ep) {
186     FPBits<T> result;
187     // offset: +1 for sign, but -1 for implicit first bit
188     int lz = fputil::unsafe_clz(number) - FloatProp::EXPONENT_WIDTH;
189     number <<= lz;
190     ep -= lz;
191 
192     if (likely(ep >= 0)) {
193       // Implicit number bit will be removed by mask
194       result.set_mantissa(number);
195       result.set_unbiased_exponent(ep + 1);
196     } else {
197       result.set_mantissa(number >> -ep);
198     }
199     return result;
200   }
201 };
202 
203 } // namespace fputil
204 } // namespace __llvm_libc
205 
206 #ifdef SPECIAL_X86_LONG_DOUBLE
207 #include "x86_64/LongDoubleBits.h"
208 #endif
209 
210 #endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_FP_BITS_H
211