1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
//===-- Properties of floating point numbers --------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT_PROPERTIES_H
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT_PROPERTIES_H
#include "PlatformDefs.h"
#include "src/__support/UInt128.h"
#include <stdint.h>
namespace __llvm_libc {
namespace fputil {
template <typename T> struct FloatProperties {};
template <> struct FloatProperties<float> {
typedef uint32_t BitsType;
static_assert(sizeof(BitsType) == sizeof(float),
"Unexpected size of 'float' type.");
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;
static constexpr uint32_t MANTISSA_WIDTH = 23;
static constexpr uint32_t EXPONENT_WIDTH = 8;
static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1;
static constexpr BitsType SIGN_MASK = BitsType(1)
<< (EXPONENT_WIDTH + MANTISSA_WIDTH);
static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
static constexpr uint32_t EXPONENT_BIAS = 127;
static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK;
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
"Exponent and mantissa masks are not as expected.");
// If a number x is a NAN, then it is a quiet NAN if:
// QuietNaNMask & bits(x) != 0
// Else, it is a signalling NAN.
static constexpr BitsType QUIET_NAN_MASK = 0x00400000U;
};
template <> struct FloatProperties<double> {
typedef uint64_t BitsType;
static_assert(sizeof(BitsType) == sizeof(double),
"Unexpected size of 'double' type.");
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) * 8;
static constexpr uint32_t MANTISSA_WIDTH = 52;
static constexpr uint32_t EXPONENT_WIDTH = 11;
static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1;
static constexpr BitsType SIGN_MASK = BitsType(1)
<< (EXPONENT_WIDTH + MANTISSA_WIDTH);
static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
static constexpr uint32_t EXPONENT_BIAS = 1023;
static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK;
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
"Exponent and mantissa masks are not as expected.");
// If a number x is a NAN, then it is a quiet NAN if:
// QuietNaNMask & bits(x) != 0
// Else, it is a signalling NAN.
static constexpr BitsType QUIET_NAN_MASK = 0x0008000000000000ULL;
};
#if defined(LONG_DOUBLE_IS_DOUBLE)
// Properties for numbers represented in 64 bits long double on Windows
// platform.
template <> struct FloatProperties<long double> {
typedef uint64_t BitsType;
static_assert(sizeof(BitsType) == sizeof(double),
"Unexpected size of 'double' type.");
static constexpr uint32_t BIT_WIDTH = FloatProperties<double>::BIT_WIDTH;
static constexpr uint32_t MANTISSA_WIDTH =
FloatProperties<double>::MANTISSA_WIDTH;
static constexpr uint32_t EXPONENT_WIDTH =
FloatProperties<double>::EXPONENT_WIDTH;
static constexpr BitsType MANTISSA_MASK =
FloatProperties<double>::MANTISSA_MASK;
static constexpr BitsType SIGN_MASK = FloatProperties<double>::SIGN_MASK;
static constexpr BitsType EXPONENT_MASK =
FloatProperties<double>::EXPONENT_MASK;
static constexpr uint32_t EXPONENT_BIAS =
FloatProperties<double>::EXPONENT_BIAS;
static constexpr BitsType EXP_MANT_MASK =
FloatProperties<double>::EXP_MANT_MASK;
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
"Exponent and mantissa masks are not as expected.");
// If a number x is a NAN, then it is a quiet NAN if:
// QuietNaNMask & bits(x) != 0
// Else, it is a signalling NAN.
static constexpr BitsType QUIET_NAN_MASK =
FloatProperties<double>::QUIET_NAN_MASK;
};
#elif defined(SPECIAL_X86_LONG_DOUBLE)
// Properties for numbers represented in 80 bits long double on non-Windows x86
// platforms.
template <> struct FloatProperties<long double> {
typedef UInt128 BitsType;
static_assert(sizeof(BitsType) == sizeof(long double),
"Unexpected size of 'long double' type.");
static constexpr uint32_t BIT_WIDTH = (sizeof(BitsType) * 8) - 48;
static constexpr BitsType FULL_WIDTH_MASK = ((BitsType(1) << BIT_WIDTH) - 1);
static constexpr uint32_t MANTISSA_WIDTH = 63;
static constexpr uint32_t EXPONENT_WIDTH = 15;
static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1;
// The x86 80 bit float represents the leading digit of the mantissa
// explicitly. This is the mask for that bit.
static constexpr BitsType EXPLICIT_BIT_MASK = (BitsType(1) << MANTISSA_WIDTH);
static constexpr BitsType SIGN_MASK =
BitsType(1) << (EXPONENT_WIDTH + MANTISSA_WIDTH + 1);
static constexpr BitsType EXPONENT_MASK =
((BitsType(1) << EXPONENT_WIDTH) - 1) << (MANTISSA_WIDTH + 1);
static constexpr uint32_t EXPONENT_BIAS = 16383;
static constexpr BitsType EXP_MANT_MASK =
MANTISSA_MASK | EXPLICIT_BIT_MASK | EXPONENT_MASK;
static_assert(EXP_MANT_MASK == (~SIGN_MASK & FULL_WIDTH_MASK),
"Exponent and mantissa masks are not as expected.");
// If a number x is a NAN, then it is a quiet NAN if:
// QuietNaNMask & bits(x) != 0
// Else, it is a signalling NAN.
static constexpr BitsType QUIET_NAN_MASK = BitsType(1)
<< (MANTISSA_WIDTH - 1);
};
#else
// Properties for numbers represented in 128 bits long double on non x86
// platform.
template <> struct FloatProperties<long double> {
typedef UInt128 BitsType;
static_assert(sizeof(BitsType) == sizeof(long double),
"Unexpected size of 'long double' type.");
static constexpr uint32_t BIT_WIDTH = sizeof(BitsType) << 3;
static constexpr uint32_t MANTISSA_WIDTH = 112;
static constexpr uint32_t EXPONENT_WIDTH = 15;
static constexpr BitsType MANTISSA_MASK = (BitsType(1) << MANTISSA_WIDTH) - 1;
static constexpr BitsType SIGN_MASK = BitsType(1)
<< (EXPONENT_WIDTH + MANTISSA_WIDTH);
static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
static constexpr uint32_t EXPONENT_BIAS = 16383;
static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK | EXPONENT_MASK;
static_assert(EXP_MANT_MASK == ~SIGN_MASK,
"Exponent and mantissa masks are not as expected.");
// If a number x is a NAN, then it is a quiet NAN if:
// QuietNaNMask & bits(x) != 0
// Else, it is a signalling NAN.
static constexpr BitsType QUIET_NAN_MASK = BitsType(1)
<< (MANTISSA_WIDTH - 1);
};
#endif
// Define the float type corresponding to the BitsType.
template <typename BitsType> struct FloatType;
template <> struct FloatType<uint32_t> {
static_assert(sizeof(uint32_t) == sizeof(float),
"Unexpected size of 'float' type.");
typedef float Type;
};
template <> struct FloatType<uint64_t> {
static_assert(sizeof(uint64_t) == sizeof(double),
"Unexpected size of 'double' type.");
typedef double Type;
};
template <typename BitsType>
using FloatTypeT = typename FloatType<BitsType>::Type;
} // namespace fputil
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_FLOAT_PROPERTIES_H
|