• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "utils/CPP/TypeTraits.h"
13 
14 #include <stdint.h>
15 
16 namespace __llvm_libc {
17 namespace fputil {
18 
19 template <typename T> struct MantissaWidth {};
20 template <> struct MantissaWidth<float> {
21   static constexpr unsigned value = 23;
22 };
23 template <> struct MantissaWidth<double> {
24   static constexpr unsigned value = 52;
25 };
26 
27 template <typename T> struct ExponentWidth {};
28 template <> struct ExponentWidth<float> {
29   static constexpr unsigned value = 8;
30 };
31 template <> struct ExponentWidth<double> {
32   static constexpr unsigned value = 11;
33 };
34 template <> struct ExponentWidth<long double> {
35   static constexpr unsigned value = 15;
36 };
37 
38 template <typename T> struct FPUIntType {};
39 template <> struct FPUIntType<float> { using Type = uint32_t; };
40 template <> struct FPUIntType<double> { using Type = uint64_t; };
41 
42 #if !(defined(__x86_64__) || defined(__i386__))
43 // TODO: This has to be extended for visual studio where long double and
44 // double are equivalent.
45 template <> struct MantissaWidth<long double> {
46   static constexpr unsigned value = 112;
47 };
48 
49 template <> struct FPUIntType<long double> { using Type = __uint128_t; };
50 #endif
51 
52 // A generic class to represent single precision, double precision, and quad
53 // precision IEEE 754 floating point formats.
54 // On most platforms, the 'float' type corresponds to single precision floating
55 // point numbers, the 'double' type corresponds to double precision floating
56 // point numers, and the 'long double' type corresponds to the quad precision
57 // floating numbers. On x86 platforms however, the 'long double' type maps to
58 // an x87 floating point format. This format is an IEEE 754 extension format.
59 // It is handled as an explicit specialization of this class.
60 template <typename T> struct __attribute__((packed)) FPBits {
61   static_assert(cpp::IsFloatingPointType<T>::Value,
62                 "FPBits instantiated with invalid type.");
63 
64   // Reinterpreting bits as an integer value and interpreting the bits of an
65   // integer value as a floating point value is used in tests. So, a convenient
66   // type is provided for such reinterpretations.
67   using UIntType = typename FPUIntType<T>::Type;
68 
69   UIntType mantissa : MantissaWidth<T>::value;
70   uint16_t exponent : ExponentWidth<T>::value;
71   uint8_t sign : 1;
72 
73   static constexpr int exponentBias = (1 << (ExponentWidth<T>::value - 1)) - 1;
74   static constexpr int maxExponent = (1 << ExponentWidth<T>::value) - 1;
75 
76   static constexpr UIntType minSubnormal = UIntType(1);
77   static constexpr UIntType maxSubnormal =
78       (UIntType(1) << MantissaWidth<T>::value) - 1;
79   static constexpr UIntType minNormal =
80       (UIntType(1) << MantissaWidth<T>::value);
81   static constexpr UIntType maxNormal =
82       ((UIntType(maxExponent) - 1) << MantissaWidth<T>::value) | maxSubnormal;
83 
84   // We don't want accidental type promotions/conversions so we require exact
85   // type match.
86   template <typename XType,
87             cpp::EnableIfType<cpp::IsSame<T, XType>::Value, int> = 0>
88   explicit FPBits(XType x) {
89     *this = *reinterpret_cast<FPBits<T> *>(&x);
90   }
91 
92   operator T() { return *reinterpret_cast<T *>(this); }
93 
94   int getExponent() const { return int(exponent) - exponentBias; }
95 
96   bool isZero() const { return mantissa == 0 && exponent == 0; }
97 
98   bool isInf() const { return mantissa == 0 && exponent == maxExponent; }
99 
100   bool isNaN() const { return exponent == maxExponent && mantissa != 0; }
101 
102   bool isInfOrNaN() const { return exponent == maxExponent; }
103 
104   // Methods below this are used by tests.
105   // The to and from integer bits converters are only used in tests. Hence,
106   // the potential software implementations of UIntType will not slow real
107   // code.
108 
109   template <typename XType,
110             cpp::EnableIfType<cpp::IsSame<UIntType, XType>::Value, int> = 0>
111   explicit FPBits<long double>(XType x) {
112     // The last 4 bytes of v are ignored in case of i386.
113     *this = *reinterpret_cast<FPBits<T> *>(&x);
114   }
115 
116   UIntType bitsAsUInt() const {
117     return *reinterpret_cast<const UIntType *>(this);
118   }
119 
120   static FPBits<T> zero() { return FPBits(T(0.0)); }
121 
122   static FPBits<T> negZero() {
123     FPBits<T> bits(T(0.0));
124     bits.sign = 1;
125     return bits;
126   }
127 
128   static FPBits<T> inf() {
129     FPBits<T> bits(T(0.0));
130     bits.exponent = maxExponent;
131     return bits;
132   }
133 
134   static FPBits<T> negInf() {
135     FPBits<T> bits(T(0.0));
136     bits.exponent = maxExponent;
137     bits.sign = 1;
138     return bits;
139   }
140 
141   static T buildNaN(UIntType v) {
142     FPBits<T> bits(T(0.0));
143     bits.exponent = maxExponent;
144     bits.mantissa = v;
145     return bits;
146   }
147 };
148 
149 } // namespace fputil
150 } // namespace __llvm_libc
151 
152 #if defined(__x86_64__) || defined(__i386__)
153 #include "utils/FPUtil/LongDoubleBitsX86.h"
154 #endif
155 
156 #endif // LLVM_LIBC_UTILS_FPUTIL_FP_BITS_H
157