@@ -80,27 +80,105 @@ template <> struct FPBaseProperties<FPType::X86_Binary80> {
80
80
FPEncoding::X86_ExtendedPrecision;
81
81
};
82
82
83
+ // TODO: Move this utility elsewhere.
84
+ template <typename T, size_t count> static constexpr T mask_trailing_ones () {
85
+ static_assert (cpp::is_unsigned_v<T>);
86
+ constexpr unsigned t_bits = CHAR_BIT * sizeof (T);
87
+ static_assert (count <= t_bits && " Invalid bit index" );
88
+ return count == 0 ? 0 : (T (-1 ) >> (t_bits - count));
89
+ }
90
+
83
91
// Derives more properties from 'FPBaseProperties' above.
84
92
// This class serves as a halfway point between 'FPBaseProperties' and
85
93
// 'FPProperties' below.
86
94
template <FPType fp_type>
87
95
struct FPCommonProperties : private FPBaseProperties <fp_type> {
96
+ private:
88
97
using UP = FPBaseProperties<fp_type>;
89
- using BitsType = typename UP::UIntType;
98
+ using UP::EXP_BITS;
99
+ using UP::SIG_BITS;
100
+ using UP::TOTAL_BITS;
101
+ using UIntType = typename UP::UIntType;
102
+
103
+ LIBC_INLINE_VAR static constexpr int STORAGE_BITS =
104
+ sizeof (UIntType) * CHAR_BIT;
105
+ static_assert (STORAGE_BITS >= TOTAL_BITS);
90
106
91
- LIBC_INLINE_VAR static constexpr uint32_t BIT_WIDTH = UP::TOTAL_BITS;
92
- LIBC_INLINE_VAR static constexpr uint32_t MANTISSA_WIDTH = UP::SIG_BITS;
93
- LIBC_INLINE_VAR static constexpr uint32_t EXPONENT_WIDTH = UP::EXP_BITS;
107
+ // The number of bits to represent sign.
108
+ // For documentation purpose, always 1.
109
+ LIBC_INLINE_VAR static constexpr int SIGN_BITS = 1 ;
110
+ static_assert (SIGN_BITS + EXP_BITS + SIG_BITS == TOTAL_BITS);
94
111
95
112
// The exponent bias. Always positive.
113
+ LIBC_INLINE_VAR static constexpr int32_t EXP_BIAS =
114
+ (1U << (EXP_BITS - 1U )) - 1U ;
115
+ static_assert (EXP_BIAS > 0 );
116
+
117
+ // Shifts
118
+ LIBC_INLINE_VAR static constexpr int SIG_MASK_SHIFT = 0 ;
119
+ LIBC_INLINE_VAR static constexpr int EXP_MASK_SHIFT = SIG_BITS;
120
+ LIBC_INLINE_VAR static constexpr int SIGN_MASK_SHIFT = SIG_BITS + EXP_BITS;
121
+
122
+ // Masks
123
+ LIBC_INLINE_VAR static constexpr UIntType SIG_MASK =
124
+ mask_trailing_ones<UIntType, SIG_BITS>() << SIG_MASK_SHIFT;
125
+ LIBC_INLINE_VAR static constexpr UIntType EXP_MASK =
126
+ mask_trailing_ones<UIntType, EXP_BITS>() << EXP_MASK_SHIFT;
127
+ // Trailing underscore on SIGN_MASK_ is temporary - it will be removed
128
+ // once we can replace the public part below with the private one.
129
+ LIBC_INLINE_VAR static constexpr UIntType SIGN_MASK_ =
130
+ mask_trailing_ones<UIntType, SIGN_BITS>() << SIGN_MASK_SHIFT;
131
+ LIBC_INLINE_VAR static constexpr UIntType FP_MASK =
132
+ mask_trailing_ones<UIntType, TOTAL_BITS>();
133
+ static_assert ((SIG_MASK & EXP_MASK & SIGN_MASK_) == 0 , " masks disjoint" );
134
+ static_assert ((SIG_MASK | EXP_MASK | SIGN_MASK_) == FP_MASK, " masks covers" );
135
+
136
+ LIBC_INLINE static constexpr UIntType bit_at (int position) {
137
+ return UIntType (1 ) << position;
138
+ }
139
+
140
+ LIBC_INLINE_VAR static constexpr UIntType QNAN_MASK =
141
+ UP::ENCODING == FPEncoding::X86_ExtendedPrecision
142
+ ? bit_at(SIG_BITS - 1 ) | bit_at(SIG_BITS - 2 ) // 0b1100...
143
+ : bit_at(SIG_BITS - 1 ); // 0b1000...
144
+
145
+ LIBC_INLINE_VAR static constexpr UIntType SNAN_MASK =
146
+ UP::ENCODING == FPEncoding::X86_ExtendedPrecision
147
+ ? bit_at(SIG_BITS - 1 ) | bit_at(SIG_BITS - 3 ) // 0b1010...
148
+ : bit_at(SIG_BITS - 2 ); // 0b0100...
149
+
150
+ // The number of bits after the decimal dot when the number if in normal form.
151
+ LIBC_INLINE_VAR static constexpr int FRACTION_BITS =
152
+ UP::ENCODING == FPEncoding::X86_ExtendedPrecision ? SIG_BITS - 1
153
+ : SIG_BITS;
154
+
155
+ public:
156
+ // Public facing API to keep the change local to this file.
157
+ using BitsType = UIntType;
158
+
159
+ LIBC_INLINE_VAR static constexpr uint32_t BIT_WIDTH = TOTAL_BITS;
160
+ LIBC_INLINE_VAR static constexpr uint32_t MANTISSA_WIDTH = FRACTION_BITS;
161
+ LIBC_INLINE_VAR static constexpr uint32_t MANTISSA_PRECISION =
162
+ MANTISSA_WIDTH + 1 ;
163
+ LIBC_INLINE_VAR static constexpr BitsType MANTISSA_MASK =
164
+ mask_trailing_ones<UIntType, MANTISSA_WIDTH>();
165
+ LIBC_INLINE_VAR static constexpr uint32_t EXPONENT_WIDTH = EXP_BITS;
96
166
LIBC_INLINE_VAR static constexpr uint32_t EXPONENT_BIAS =
97
- (1U << (UP::EXP_BITS - 1U )) - 1U ;
98
- static_assert (EXPONENT_BIAS > 0 );
167
+ static_cast <uint32_t >(EXP_BIAS);
168
+ LIBC_INLINE_VAR static constexpr BitsType SIGN_MASK = SIGN_MASK_;
169
+ LIBC_INLINE_VAR static constexpr BitsType EXPONENT_MASK = EXP_MASK;
170
+ LIBC_INLINE_VAR static constexpr BitsType EXP_MANT_MASK = EXP_MASK | SIG_MASK;
171
+
172
+ // If a number x is a NAN, then it is a quiet NAN if:
173
+ // QuietNaNMask & bits(x) != 0
174
+ // Else, it is a signalling NAN.
175
+ static constexpr BitsType QUIET_NAN_MASK = QNAN_MASK;
99
176
};
100
177
101
178
} // namespace internal
102
179
103
- template <FPType> struct FPProperties {};
180
+ template <FPType fp_type>
181
+ struct FPProperties : public internal ::FPCommonProperties<fp_type> {};
104
182
105
183
// ----------------
106
184
// Work In Progress
@@ -110,90 +188,14 @@ template <FPType> struct FPProperties {};
110
188
// empty, 'FPProperties' declaration can be fully replace with
111
189
// 'FPCommonProperties' implementation.
112
190
113
- template <>
114
- struct FPProperties <FPType::IEEE754_Binary32>
115
- : public internal::FPCommonProperties<FPType::IEEE754_Binary32> {
116
- // The mantissa precision includes the implicit bit.
117
- static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1 ;
118
- static constexpr BitsType MANTISSA_MASK = (BitsType(1 ) << MANTISSA_WIDTH) - 1 ;
119
- static constexpr BitsType SIGN_MASK = BitsType(1 )
120
- << (EXPONENT_WIDTH + MANTISSA_WIDTH);
121
- static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
122
- static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK;
123
- static_assert (EXP_MANT_MASK == ~SIGN_MASK,
124
- " Exponent and mantissa masks are not as expected." );
125
-
126
- // If a number x is a NAN, then it is a quiet NAN if:
127
- // QuietNaNMask & bits(x) != 0
128
- // Else, it is a signalling NAN.
129
- static constexpr BitsType QUIET_NAN_MASK = 0x00400000U ;
130
- };
131
-
132
- template <>
133
- struct FPProperties <FPType::IEEE754_Binary64>
134
- : public internal::FPCommonProperties<FPType::IEEE754_Binary64> {
135
- static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1 ;
136
- static constexpr BitsType MANTISSA_MASK = (BitsType(1 ) << MANTISSA_WIDTH) - 1 ;
137
- static constexpr BitsType SIGN_MASK = BitsType(1 )
138
- << (EXPONENT_WIDTH + MANTISSA_WIDTH);
139
- static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
140
- static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK + EXPONENT_MASK;
141
- static_assert (EXP_MANT_MASK == ~SIGN_MASK,
142
- " Exponent and mantissa masks are not as expected." );
143
-
144
- // If a number x is a NAN, then it is a quiet NAN if:
145
- // QuietNaNMask & bits(x) != 0
146
- // Else, it is a signalling NAN.
147
- static constexpr BitsType QUIET_NAN_MASK = 0x0008000000000000ULL ;
148
- };
149
-
150
191
// Properties for numbers represented in 80 bits long double on non-Windows x86
151
192
// platforms.
152
193
template <>
153
194
struct FPProperties <FPType::X86_Binary80>
154
195
: public internal::FPCommonProperties<FPType::X86_Binary80> {
155
- static constexpr BitsType FULL_WIDTH_MASK = ((BitsType(1 ) << BIT_WIDTH) - 1 );
156
- static constexpr uint32_t MANTISSA_WIDTH = 63 ;
157
- static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1 ;
158
- static constexpr BitsType MANTISSA_MASK = (BitsType(1 ) << MANTISSA_WIDTH) - 1 ;
159
196
// The x86 80 bit float represents the leading digit of the mantissa
160
197
// explicitly. This is the mask for that bit.
161
198
static constexpr BitsType EXPLICIT_BIT_MASK = (BitsType(1 ) << MANTISSA_WIDTH);
162
- static constexpr BitsType SIGN_MASK =
163
- BitsType (1 ) << (EXPONENT_WIDTH + MANTISSA_WIDTH + 1 );
164
- static constexpr BitsType EXPONENT_MASK =
165
- ((BitsType(1 ) << EXPONENT_WIDTH) - 1 ) << (MANTISSA_WIDTH + 1 );
166
- static constexpr BitsType EXP_MANT_MASK =
167
- MANTISSA_MASK | EXPLICIT_BIT_MASK | EXPONENT_MASK;
168
- static_assert (EXP_MANT_MASK == (~SIGN_MASK & FULL_WIDTH_MASK),
169
- " Exponent and mantissa masks are not as expected." );
170
-
171
- // If a number x is a NAN, then it is a quiet NAN if:
172
- // QuietNaNMask & bits(x) != 0
173
- // Else, it is a signalling NAN.
174
- static constexpr BitsType QUIET_NAN_MASK = BitsType(1 )
175
- << (MANTISSA_WIDTH - 1 );
176
- };
177
-
178
- // Properties for numbers represented in 128 bits long double on non x86
179
- // platform.
180
- template <>
181
- struct FPProperties <FPType::IEEE754_Binary128>
182
- : public internal::FPCommonProperties<FPType::IEEE754_Binary128> {
183
- static constexpr uint32_t MANTISSA_PRECISION = MANTISSA_WIDTH + 1 ;
184
- static constexpr BitsType MANTISSA_MASK = (BitsType(1 ) << MANTISSA_WIDTH) - 1 ;
185
- static constexpr BitsType SIGN_MASK = BitsType(1 )
186
- << (EXPONENT_WIDTH + MANTISSA_WIDTH);
187
- static constexpr BitsType EXPONENT_MASK = ~(SIGN_MASK | MANTISSA_MASK);
188
- static constexpr BitsType EXP_MANT_MASK = MANTISSA_MASK | EXPONENT_MASK;
189
- static_assert (EXP_MANT_MASK == ~SIGN_MASK,
190
- " Exponent and mantissa masks are not as expected." );
191
-
192
- // If a number x is a NAN, then it is a quiet NAN if:
193
- // QuietNaNMask & bits(x) != 0
194
- // Else, it is a signalling NAN.
195
- static constexpr BitsType QUIET_NAN_MASK = BitsType(1 )
196
- << (MANTISSA_WIDTH - 1 );
197
199
};
198
200
199
201
// -----------------------------------------------------------------------------
0 commit comments