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_UTILS_FPUTIL_FP_BITS_H
10 #define LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H
11 
12 #include "PlatformDefs.h"
13 
14 #include "utils/CPP/TypeTraits.h"
15 
16 #include "FloatProperties.h"
17 #include <stdint.h>
18 
19 namespace __llvm_libc {
20 namespace fputil {
21 
22 template <typename T> struct MantissaWidth {
23   static constexpr unsigned value = FloatProperties<T>::mantissaWidth;
24 };
25 
26 template <typename T> struct ExponentWidth {
27   static constexpr unsigned value = FloatProperties<T>::exponentWidth;
28 };
29 
30 // A generic class to represent single precision, double precision, and quad
31 // precision IEEE 754 floating point formats.
32 // On most platforms, the 'float' type corresponds to single precision floating
33 // point numbers, the 'double' type corresponds to double precision floating
34 // point numers, and the 'long double' type corresponds to the quad precision
35 // floating numbers. On x86 platforms however, the 'long double' type maps to
36 // an x87 floating point format. This format is an IEEE 754 extension format.
37 // It is handled as an explicit specialization of this class.
38 template <typename T> union FPBits {
39   static_assert(cpp::IsFloatingPointType<T>::Value,
40                 "FPBits instantiated with invalid type.");
41 
42   // Reinterpreting bits as an integer value and interpreting the bits of an
43   // integer value as a floating point value is used in tests. So, a convenient
44   // type is provided for such reinterpretations.
45   using FloatProp = FloatProperties<T>;
46   // TODO: Change UintType name to BitsType for consistency.
47   using UIntType = typename FloatProp::BitsType;
48 
49   UIntType bits;
50 
setMantissa(UIntType mantVal)51   void setMantissa(UIntType mantVal) {
52     mantVal &= (FloatProp::mantissaMask);
53     bits &= ~(FloatProp::mantissaMask);
54     bits |= mantVal;
55   }
56 
getMantissa()57   UIntType getMantissa() const { return bits & FloatProp::mantissaMask; }
58 
setUnbiasedExponent(UIntType expVal)59   void setUnbiasedExponent(UIntType expVal) {
60     expVal = (expVal << (FloatProp::mantissaWidth)) & FloatProp::exponentMask;
61     bits &= ~(FloatProp::exponentMask);
62     bits |= expVal;
63   }
64 
getUnbiasedExponent()65   uint16_t getUnbiasedExponent() const {
66     return uint16_t((bits & FloatProp::exponentMask) >>
67                     (FloatProp::mantissaWidth));
68   }
69 
setSign(bool signVal)70   void setSign(bool signVal) {
71     bits &= ~(FloatProp::signMask);
72     UIntType sign = UIntType(signVal) << (FloatProp::bitWidth - 1);
73     bits |= sign;
74   }
75 
getSign()76   bool getSign() const {
77     return ((bits & FloatProp::signMask) >> (FloatProp::bitWidth - 1));
78   }
79   T val;
80 
81   static_assert(sizeof(T) == sizeof(UIntType),
82                 "Data type and integral representation have different sizes.");
83 
84   static constexpr int exponentBias = (1 << (ExponentWidth<T>::value - 1)) - 1;
85   static constexpr int maxExponent = (1 << ExponentWidth<T>::value) - 1;
86 
87   static constexpr UIntType minSubnormal = UIntType(1);
88   static constexpr UIntType maxSubnormal =
89       (UIntType(1) << MantissaWidth<T>::value) - 1;
90   static constexpr UIntType minNormal =
91       (UIntType(1) << MantissaWidth<T>::value);
92   static constexpr UIntType maxNormal =
93       ((UIntType(maxExponent) - 1) << MantissaWidth<T>::value) | maxSubnormal;
94 
95   // We don't want accidental type promotions/conversions so we require exact
96   // type match.
97   template <typename XType,
98             cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0>
FPBits(XType x)99   explicit FPBits(XType x) : val(x) {}
100 
101   template <typename XType,
102             cpp::EnableIfType<cpp::IsSame<XType, UIntType>::Value, int> = 0>
FPBits(XType x)103   explicit FPBits(XType x) : bits(x) {}
104 
FPBits()105   FPBits() : bits(0) {}
106 
T()107   explicit operator T() { return val; }
108 
uintval()109   UIntType uintval() const { return bits; }
110 
getExponent()111   int getExponent() const { return int(getUnbiasedExponent()) - exponentBias; }
112 
isZero()113   bool isZero() const {
114     return getMantissa() == 0 && getUnbiasedExponent() == 0;
115   }
116 
isInf()117   bool isInf() const {
118     return getMantissa() == 0 && getUnbiasedExponent() == maxExponent;
119   }
120 
isNaN()121   bool isNaN() const {
122     return getUnbiasedExponent() == maxExponent && getMantissa() != 0;
123   }
124 
isInfOrNaN()125   bool isInfOrNaN() const { return getUnbiasedExponent() == maxExponent; }
126 
zero()127   static FPBits<T> zero() { return FPBits(); }
128 
negZero()129   static FPBits<T> negZero() {
130     return FPBits(UIntType(1) << (sizeof(UIntType) * 8 - 1));
131   }
132 
inf()133   static FPBits<T> inf() {
134     FPBits<T> bits;
135     bits.setUnbiasedExponent(maxExponent);
136     return bits;
137   }
138 
negInf()139   static FPBits<T> negInf() {
140     FPBits<T> bits = inf();
141     bits.setSign(1);
142     return bits;
143   }
144 
buildNaN(UIntType v)145   static T buildNaN(UIntType v) {
146     FPBits<T> bits = inf();
147     bits.setMantissa(v);
148     return T(bits);
149   }
150 };
151 
152 } // namespace fputil
153 } // namespace __llvm_libc
154 
155 #ifdef SPECIAL_X86_LONG_DOUBLE
156 #include "utils/FPUtil/LongDoubleBitsX86.h"
157 #endif
158 
159 #endif // LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H
160