Coverage Report

Created: 2026-01-16 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spirv-tools/source/util/hex_float.h
Line
Count
Source
1
// Copyright (c) 2015-2016 The Khronos Group Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#ifndef SOURCE_UTIL_HEX_FLOAT_H_
16
#define SOURCE_UTIL_HEX_FLOAT_H_
17
18
#include <cassert>
19
#include <cctype>
20
#include <cmath>
21
#include <cstdint>
22
#include <iomanip>
23
#include <limits>
24
#include <sstream>
25
#include <vector>
26
27
#include "source/util/bitutils.h"
28
29
#ifndef __GNUC__
30
#define GCC_VERSION 0
31
#else
32
#define GCC_VERSION \
33
  (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
34
#endif
35
36
namespace spvtools {
37
namespace utils {
38
39
class Float8_E4M3 {
40
 public:
41
38.8k
  Float8_E4M3(uint8_t v) : val(v) {}
42
  Float8_E4M3() = default;
43
0
  static bool isNan(const Float8_E4M3& val) { return (val.val & 0x7f) == 0x7f; }
44
  // Returns true if the given value is any kind of infinity.
45
0
  static bool isInfinity(const Float8_E4M3&) {
46
0
    return false;  // E4M3 has no infinity representation
47
0
  }
48
0
  Float8_E4M3(const Float8_E4M3& other) { val = other.val; }
49
38.8k
  uint8_t get_value() const { return val; }
50
51
  // Returns the maximum normal value.
52
742
  static Float8_E4M3 max() { return Float8_E4M3(0x7e); }
53
  // Returns the lowest normal value.
54
0
  static Float8_E4M3 lowest() { return Float8_E4M3(0x8); }
55
56
 private:
57
  uint8_t val;
58
};
59
60
class Float8_E5M2 {
61
 public:
62
55.9k
  Float8_E5M2(uint8_t v) : val(v) {}
63
  Float8_E5M2() = default;
64
0
  static bool isNan(const Float8_E5M2& val) {
65
0
    return ((val.val & 0x7c) == 0x7c) && ((val.val & 0x3) != 0);
66
0
  }
67
  // Returns true if the given value is any kind of infinity.
68
17.5k
  static bool isInfinity(const Float8_E5M2& val) {
69
17.5k
    return (val.val & 0x7f) == 0x7c;
70
17.5k
  }
71
0
  Float8_E5M2(const Float8_E5M2& other) { val = other.val; }
72
38.3k
  uint8_t get_value() const { return val; }
73
74
  // Returns the maximum normal value.
75
24
  static Float8_E5M2 max() { return Float8_E5M2(0x7b); }
76
  // Returns the lowest normal value.
77
4
  static Float8_E5M2 lowest() { return Float8_E5M2(0x4); }
78
79
 private:
80
  uint8_t val;
81
};
82
83
class Float16 {
84
 public:
85
53.0k
  Float16(uint16_t v) : val(v) {}
86
  Float16() = default;
87
1.07k
  static bool isNan(const Float16& val) {
88
1.07k
    return ((val.val & 0x7C00) == 0x7C00) && ((val.val & 0x3FF) != 0);
89
1.07k
  }
90
  // Returns true if the given value is any kind of infinity.
91
16.5k
  static bool isInfinity(const Float16& val) {
92
16.5k
    return ((val.val & 0x7C00) == 0x7C00) && ((val.val & 0x3FF) == 0);
93
16.5k
  }
94
0
  Float16(const Float16& other) { val = other.val; }
95
35.4k
  uint16_t get_value() const { return val; }
96
97
  // Returns the maximum normal value.
98
14
  static Float16 max() { return Float16(0x7bff); }
99
  // Returns the lowest normal value.
100
14
  static Float16 lowest() { return Float16(0xfbff); }
101
102
 private:
103
  uint16_t val;
104
};
105
106
class BFloat16 {
107
 public:
108
47.0k
  BFloat16(uint16_t v) : val(v) {}
109
  BFloat16() = default;
110
0
  BFloat16(const BFloat16& other) { val = other.val; }
111
112
  // Exponent mask: 0x7F80, Mantissa mask: 0x007F
113
0
  static bool isNan(const BFloat16& val) {
114
0
    return ((val.val & 0x7F80) == 0x7F80) && ((val.val & 0x007F) != 0);
115
0
  }
116
13.1k
  static bool isInfinity(const BFloat16& val) {
117
13.1k
    return ((val.val & 0x7F80) == 0x7F80) && ((val.val & 0x007F) == 0);
118
13.1k
  }
119
120
33.9k
  uint16_t get_value() const { return val; }
121
122
  // a sign bit of 0, and an all 1 mantissa.
123
0
  static BFloat16 max() { return BFloat16(0x7F7F); }
124
  // a sign bit of 1, and an all 1 mantissa.
125
0
  static BFloat16 lowest() { return BFloat16(0xFF7F); }
126
127
 private:
128
  // 15: Sign
129
  // 14-7: Exponent
130
  // 6-0: Mantissa
131
  uint16_t val;
132
};
133
134
// To specialize this type, you must override uint_type to define
135
// an unsigned integer that can fit your floating point type.
136
// You must also add a isNan function that returns true if
137
// a value is Nan.
138
template <typename T>
139
struct FloatProxyTraits {
140
  using uint_type = void;
141
};
142
143
template <>
144
struct FloatProxyTraits<float> {
145
  using uint_type = uint32_t;
146
51.1k
  static bool isNan(float f) { return std::isnan(f); }
147
  // Returns true if the given value is any kind of infinity.
148
125k
  static bool isInfinity(float f) { return std::isinf(f); }
149
  // Returns the maximum normal value.
150
20
  static float max() { return std::numeric_limits<float>::max(); }
151
  // Returns the lowest normal value.
152
14
  static float lowest() { return std::numeric_limits<float>::lowest(); }
153
  // Returns the value as the native floating point format.
154
2.48M
  static float getAsFloat(const uint_type& t) { return BitwiseCast<float>(t); }
155
  // Returns the bits from the given floating pointer number.
156
1.21M
  static uint_type getBitsFromFloat(const float& t) {
157
1.21M
    return BitwiseCast<uint_type>(t);
158
1.21M
  }
159
  // Returns the bitwidth.
160
634k
  static uint32_t width() { return 32u; }
161
};
162
163
template <>
164
struct FloatProxyTraits<double> {
165
  using uint_type = uint64_t;
166
0
  static bool isNan(double f) { return std::isnan(f); }
167
  // Returns true if the given value is any kind of infinity.
168
5.29k
  static bool isInfinity(double f) { return std::isinf(f); }
169
  // Returns the maximum normal value.
170
4
  static double max() { return std::numeric_limits<double>::max(); }
171
  // Returns the lowest normal value.
172
6
  static double lowest() { return std::numeric_limits<double>::lowest(); }
173
  // Returns the value as the native floating point format.
174
31.5k
  static double getAsFloat(const uint_type& t) {
175
31.5k
    return BitwiseCast<double>(t);
176
31.5k
  }
177
  // Returns the bits from the given floating pointer number.
178
52.4k
  static uint_type getBitsFromFloat(const double& t) {
179
52.4k
    return BitwiseCast<uint_type>(t);
180
52.4k
  }
181
  // Returns the bitwidth.
182
0
  static uint32_t width() { return 64u; }
183
};
184
185
template <>
186
struct FloatProxyTraits<Float8_E4M3> {
187
  using uint_type = uint8_t;
188
0
  static bool isNan(Float8_E4M3 f) { return Float8_E4M3::isNan(f); }
189
  // Returns true if the given value is any kind of infinity.
190
0
  static bool isInfinity(Float8_E4M3 f) { return Float8_E4M3::isInfinity(f); }
191
  // Returns the maximum normal value.
192
734
  static Float8_E4M3 max() { return Float8_E4M3::max(); }
193
  // Returns the lowest normal value.
194
0
  static Float8_E4M3 lowest() { return Float8_E4M3::lowest(); }
195
  // Returns the value as the native floating point format.
196
38.1k
  static Float8_E4M3 getAsFloat(const uint_type& t) { return Float8_E4M3(t); }
197
  // Returns the bits from the given floating pointer number.
198
738
  static uint_type getBitsFromFloat(const Float8_E4M3& t) {
199
738
    return t.get_value();
200
738
  }
201
  // Returns the bitwidth.
202
0
  static uint32_t width() { return 8u; }
203
};
204
205
template <>
206
struct FloatProxyTraits<Float8_E5M2> {
207
  using uint_type = uint8_t;
208
0
  static bool isNan(Float8_E5M2 f) { return Float8_E5M2::isNan(f); }
209
  // Returns true if the given value is any kind of infinity.
210
0
  static bool isInfinity(Float8_E5M2 f) { return Float8_E5M2::isInfinity(f); }
211
  // Returns the maximum normal value.
212
0
  static Float8_E5M2 max() { return Float8_E5M2::max(); }
213
  // Returns the lowest normal value.
214
0
  static Float8_E5M2 lowest() { return Float8_E5M2::lowest(); }
215
  // Returns the value as the native floating point format.
216
55.8k
  static Float8_E5M2 getAsFloat(const uint_type& t) { return Float8_E5M2(t); }
217
  // Returns the bits from the given floating pointer number.
218
28
  static uint_type getBitsFromFloat(const Float8_E5M2& t) {
219
28
    return t.get_value();
220
28
  }
221
  // Returns the bitwidth.
222
0
  static uint32_t width() { return 8u; }
223
};
224
225
template <>
226
struct FloatProxyTraits<Float16> {
227
  using uint_type = uint16_t;
228
1.07k
  static bool isNan(Float16 f) { return Float16::isNan(f); }
229
  // Returns true if the given value is any kind of infinity.
230
947
  static bool isInfinity(Float16 f) { return Float16::isInfinity(f); }
231
  // Returns the maximum normal value.
232
0
  static Float16 max() { return Float16::max(); }
233
  // Returns the lowest normal value.
234
0
  static Float16 lowest() { return Float16::lowest(); }
235
  // Returns the value as the native floating point format.
236
53.0k
  static Float16 getAsFloat(const uint_type& t) { return Float16(t); }
237
  // Returns the bits from the given floating pointer number.
238
28
  static uint_type getBitsFromFloat(const Float16& t) { return t.get_value(); }
239
  // Returns the bitwidth.
240
0
  static uint32_t width() { return 16u; }
241
};
242
243
template <>
244
struct FloatProxyTraits<BFloat16> {
245
  using uint_type = uint16_t;
246
0
  static bool isNan(BFloat16 f) { return BFloat16::isNan(f); }
247
  // Returns true if the given value is any kind of infinity.
248
0
  static bool isInfinity(BFloat16 f) { return BFloat16::isInfinity(f); }
249
  // Returns the maximum normal value.
250
0
  static BFloat16 max() { return BFloat16::max(); }
251
  // Returns the lowest normal value.
252
0
  static BFloat16 lowest() { return BFloat16::lowest(); }
253
  // Returns the value as the native floating point format.
254
47.0k
  static BFloat16 getAsFloat(const uint_type& t) { return BFloat16(t); }
255
  // Returns the bits from the given floating pointer number.
256
0
  static uint_type getBitsFromFloat(const BFloat16& t) { return t.get_value(); }
257
  // Returns the bitwidth.
258
0
  static uint32_t width() { return 16u; }
259
};
260
261
// Since copying a floating point number (especially if it is NaN)
262
// does not guarantee that bits are preserved, this class lets us
263
// store the type and use it as a float when necessary.
264
template <typename T>
265
class FloatProxy {
266
 public:
267
  using uint_type = typename FloatProxyTraits<T>::uint_type;
268
269
  // Since this is to act similar to the normal floats,
270
  // do not initialize the data by default.
271
  FloatProxy() = default;
272
273
  // Intentionally non-explicit. This is a proxy type so
274
  // implicit conversions allow us to use it more transparently.
275
1.26M
  FloatProxy(T val) { data_ = FloatProxyTraits<T>::getBitsFromFloat(val); }
spvtools::utils::FloatProxy<float>::FloatProxy(float)
Line
Count
Source
275
1.21M
  FloatProxy(T val) { data_ = FloatProxyTraits<T>::getBitsFromFloat(val); }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>::FloatProxy(spvtools::utils::Float8_E4M3)
Line
Count
Source
275
4
  FloatProxy(T val) { data_ = FloatProxyTraits<T>::getBitsFromFloat(val); }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>::FloatProxy(spvtools::utils::Float8_E5M2)
Line
Count
Source
275
28
  FloatProxy(T val) { data_ = FloatProxyTraits<T>::getBitsFromFloat(val); }
Unexecuted instantiation: spvtools::utils::FloatProxy<spvtools::utils::BFloat16>::FloatProxy(spvtools::utils::BFloat16)
spvtools::utils::FloatProxy<spvtools::utils::Float16>::FloatProxy(spvtools::utils::Float16)
Line
Count
Source
275
28
  FloatProxy(T val) { data_ = FloatProxyTraits<T>::getBitsFromFloat(val); }
spvtools::utils::FloatProxy<double>::FloatProxy(double)
Line
Count
Source
275
52.4k
  FloatProxy(T val) { data_ = FloatProxyTraits<T>::getBitsFromFloat(val); }
276
277
  // Intentionally non-explicit. This is a proxy type so
278
  // implicit conversions allow us to use it more transparently.
279
3.18M
  FloatProxy(uint_type val) { data_ = val; }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>::FloatProxy(unsigned char)
Line
Count
Source
279
209k
  FloatProxy(uint_type val) { data_ = val; }
spvtools::utils::FloatProxy<spvtools::utils::Float16>::FloatProxy(unsigned short)
Line
Count
Source
279
254k
  FloatProxy(uint_type val) { data_ = val; }
spvtools::utils::FloatProxy<float>::FloatProxy(unsigned int)
Line
Count
Source
279
2.27M
  FloatProxy(uint_type val) { data_ = val; }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>::FloatProxy(unsigned char)
Line
Count
Source
279
190k
  FloatProxy(uint_type val) { data_ = val; }
spvtools::utils::FloatProxy<spvtools::utils::BFloat16>::FloatProxy(unsigned short)
Line
Count
Source
279
208k
  FloatProxy(uint_type val) { data_ = val; }
spvtools::utils::FloatProxy<double>::FloatProxy(unsigned long)
Line
Count
Source
279
46.6k
  FloatProxy(uint_type val) { data_ = val; }
280
281
  // This is helpful to have and is guaranteed not to stomp bits.
282
32.6k
  FloatProxy<T> operator-() const {
283
32.6k
    return static_cast<uint_type>(data_ ^
284
32.6k
                                  (uint_type(0x1) << (sizeof(T) * 8 - 1)));
285
32.6k
  }
spvtools::utils::FloatProxy<float>::operator-() const
Line
Count
Source
282
23.0k
  FloatProxy<T> operator-() const {
283
23.0k
    return static_cast<uint_type>(data_ ^
284
23.0k
                                  (uint_type(0x1) << (sizeof(T) * 8 - 1)));
285
23.0k
  }
spvtools::utils::FloatProxy<spvtools::utils::Float16>::operator-() const
Line
Count
Source
282
1.55k
  FloatProxy<T> operator-() const {
283
1.55k
    return static_cast<uint_type>(data_ ^
284
1.55k
                                  (uint_type(0x1) << (sizeof(T) * 8 - 1)));
285
1.55k
  }
spvtools::utils::FloatProxy<spvtools::utils::BFloat16>::operator-() const
Line
Count
Source
282
2.57k
  FloatProxy<T> operator-() const {
283
2.57k
    return static_cast<uint_type>(data_ ^
284
2.57k
                                  (uint_type(0x1) << (sizeof(T) * 8 - 1)));
285
2.57k
  }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>::operator-() const
Line
Count
Source
282
1.98k
  FloatProxy<T> operator-() const {
283
1.98k
    return static_cast<uint_type>(data_ ^
284
1.98k
                                  (uint_type(0x1) << (sizeof(T) * 8 - 1)));
285
1.98k
  }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>::operator-() const
Line
Count
Source
282
1.19k
  FloatProxy<T> operator-() const {
283
1.19k
    return static_cast<uint_type>(data_ ^
284
1.19k
                                  (uint_type(0x1) << (sizeof(T) * 8 - 1)));
285
1.19k
  }
spvtools::utils::FloatProxy<double>::operator-() const
Line
Count
Source
282
2.26k
  FloatProxy<T> operator-() const {
283
2.26k
    return static_cast<uint_type>(data_ ^
284
2.26k
                                  (uint_type(0x1) << (sizeof(T) * 8 - 1)));
285
2.26k
  }
286
287
  // Returns the data as a floating point value.
288
2.71M
  T getAsFloat() const { return FloatProxyTraits<T>::getAsFloat(data_); }
spvtools::utils::FloatProxy<spvtools::utils::Float16>::getAsFloat() const
Line
Count
Source
288
53.0k
  T getAsFloat() const { return FloatProxyTraits<T>::getAsFloat(data_); }
spvtools::utils::FloatProxy<spvtools::utils::BFloat16>::getAsFloat() const
Line
Count
Source
288
47.0k
  T getAsFloat() const { return FloatProxyTraits<T>::getAsFloat(data_); }
spvtools::utils::FloatProxy<float>::getAsFloat() const
Line
Count
Source
288
2.48M
  T getAsFloat() const { return FloatProxyTraits<T>::getAsFloat(data_); }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>::getAsFloat() const
Line
Count
Source
288
55.8k
  T getAsFloat() const { return FloatProxyTraits<T>::getAsFloat(data_); }
spvtools::utils::FloatProxy<double>::getAsFloat() const
Line
Count
Source
288
31.5k
  T getAsFloat() const { return FloatProxyTraits<T>::getAsFloat(data_); }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>::getAsFloat() const
Line
Count
Source
288
38.1k
  T getAsFloat() const { return FloatProxyTraits<T>::getAsFloat(data_); }
289
290
  // Returns the raw data.
291
2.05M
  uint_type data() const { return data_; }
spvtools::utils::FloatProxy<float>::data() const
Line
Count
Source
291
1.65M
  uint_type data() const { return data_; }
spvtools::utils::FloatProxy<spvtools::utils::Float16>::data() const
Line
Count
Source
291
136k
  uint_type data() const { return data_; }
spvtools::utils::FloatProxy<spvtools::utils::BFloat16>::data() const
Line
Count
Source
291
94.4k
  uint_type data() const { return data_; }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>::data() const
Line
Count
Source
291
58.7k
  uint_type data() const { return data_; }
spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>::data() const
Line
Count
Source
291
77.7k
  uint_type data() const { return data_; }
spvtools::utils::FloatProxy<double>::data() const
Line
Count
Source
291
25.5k
  uint_type data() const { return data_; }
292
293
  // Returns a vector of words suitable for use in an Operand.
294
634k
  std::vector<uint32_t> GetWords() const {
295
634k
    std::vector<uint32_t> words;
296
634k
    if (FloatProxyTraits<T>::width() == 64) {
297
0
      FloatProxyTraits<double>::uint_type d = data();
298
0
      words.push_back(static_cast<uint32_t>(d));
299
0
      words.push_back(static_cast<uint32_t>(d >> 32));
300
634k
    } else {
301
634k
      words.push_back(static_cast<uint32_t>(data()));
302
634k
    }
303
634k
    return words;
304
634k
  }
Unexecuted instantiation: spvtools::utils::FloatProxy<double>::GetWords() const
spvtools::utils::FloatProxy<float>::GetWords() const
Line
Count
Source
294
634k
  std::vector<uint32_t> GetWords() const {
295
634k
    std::vector<uint32_t> words;
296
634k
    if (FloatProxyTraits<T>::width() == 64) {
297
0
      FloatProxyTraits<double>::uint_type d = data();
298
0
      words.push_back(static_cast<uint32_t>(d));
299
0
      words.push_back(static_cast<uint32_t>(d >> 32));
300
634k
    } else {
301
634k
      words.push_back(static_cast<uint32_t>(data()));
302
634k
    }
303
634k
    return words;
304
634k
  }
305
306
  // Returns true if the value represents any type of NaN.
307
52.1k
  bool isNan() { return FloatProxyTraits<T>::isNan(getAsFloat()); }
spvtools::utils::FloatProxy<float>::isNan()
Line
Count
Source
307
51.1k
  bool isNan() { return FloatProxyTraits<T>::isNan(getAsFloat()); }
spvtools::utils::FloatProxy<spvtools::utils::Float16>::isNan()
Line
Count
Source
307
1.07k
  bool isNan() { return FloatProxyTraits<T>::isNan(getAsFloat()); }
308
  // Returns true if the value represents any type of infinity.
309
131k
  bool isInfinity() { return FloatProxyTraits<T>::isInfinity(getAsFloat()); }
spvtools::utils::FloatProxy<float>::isInfinity()
Line
Count
Source
309
125k
  bool isInfinity() { return FloatProxyTraits<T>::isInfinity(getAsFloat()); }
spvtools::utils::FloatProxy<double>::isInfinity()
Line
Count
Source
309
5.29k
  bool isInfinity() { return FloatProxyTraits<T>::isInfinity(getAsFloat()); }
spvtools::utils::FloatProxy<spvtools::utils::Float16>::isInfinity()
Line
Count
Source
309
947
  bool isInfinity() { return FloatProxyTraits<T>::isInfinity(getAsFloat()); }
310
311
  // Returns the maximum normal value.
312
24
  static FloatProxy<T> max() {
313
24
    return FloatProxy<T>(FloatProxyTraits<T>::max());
314
24
  }
spvtools::utils::FloatProxy<float>::max()
Line
Count
Source
312
20
  static FloatProxy<T> max() {
313
20
    return FloatProxy<T>(FloatProxyTraits<T>::max());
314
20
  }
spvtools::utils::FloatProxy<double>::max()
Line
Count
Source
312
4
  static FloatProxy<T> max() {
313
4
    return FloatProxy<T>(FloatProxyTraits<T>::max());
314
4
  }
315
  // Returns the lowest normal value.
316
20
  static FloatProxy<T> lowest() {
317
20
    return FloatProxy<T>(FloatProxyTraits<T>::lowest());
318
20
  }
spvtools::utils::FloatProxy<float>::lowest()
Line
Count
Source
316
14
  static FloatProxy<T> lowest() {
317
14
    return FloatProxy<T>(FloatProxyTraits<T>::lowest());
318
14
  }
spvtools::utils::FloatProxy<double>::lowest()
Line
Count
Source
316
6
  static FloatProxy<T> lowest() {
317
6
    return FloatProxy<T>(FloatProxyTraits<T>::lowest());
318
6
  }
319
320
 private:
321
  uint_type data_;
322
};
323
324
template <typename T>
325
bool operator==(const FloatProxy<T>& first, const FloatProxy<T>& second) {
326
  return first.data() == second.data();
327
}
328
329
// Reads a FloatProxy value as a normal float from a stream.
330
template <typename T>
331
80.8k
std::istream& operator>>(std::istream& is, FloatProxy<T>& value) {
332
80.8k
  T float_val = static_cast<T>(0.0);
333
80.8k
  is >> float_val;
334
80.8k
  value = FloatProxy<T>(float_val);
335
80.8k
  return is;
336
80.8k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::operator>><float>(std::__1::basic_istream<char, std::__1::char_traits<char> >&, spvtools::utils::FloatProxy<float>&)
Line
Count
Source
331
75.5k
std::istream& operator>>(std::istream& is, FloatProxy<T>& value) {
332
75.5k
  T float_val = static_cast<T>(0.0);
333
75.5k
  is >> float_val;
334
75.5k
  value = FloatProxy<T>(float_val);
335
75.5k
  return is;
336
75.5k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::operator>><double>(std::__1::basic_istream<char, std::__1::char_traits<char> >&, spvtools::utils::FloatProxy<double>&)
Line
Count
Source
331
5.29k
std::istream& operator>>(std::istream& is, FloatProxy<T>& value) {
332
5.29k
  T float_val = static_cast<T>(0.0);
333
5.29k
  is >> float_val;
334
5.29k
  value = FloatProxy<T>(float_val);
335
5.29k
  return is;
336
5.29k
}
337
338
// This is an example traits. It is not meant to be used in practice, but will
339
// be the default for any non-specialized type.
340
template <typename T>
341
struct HexFloatTraits {
342
  // Integer type that can store the bit representation of this hex-float.
343
  using uint_type = void;
344
  // Signed integer type that can store the bit representation of this
345
  // hex-float.
346
  using int_type = void;
347
  // The numerical type that this HexFloat represents.
348
  using underlying_type = void;
349
  using underlying_typetraits = void;
350
  // The type needed to construct the underlying type.
351
  using native_type = void;
352
  // The number of bits that are actually relevant in the uint_type.
353
  // This allows us to deal with, for example, 24-bit values in a 32-bit
354
  // integer.
355
  static const uint32_t num_used_bits = 0;
356
  // Number of bits that represent the exponent.
357
  static const uint32_t num_exponent_bits = 0;
358
  // Number of bits that represent the fractional part.
359
  static const uint32_t num_fraction_bits = 0;
360
  // The bias of the exponent. (How much we need to subtract from the stored
361
  // value to get the correct value.)
362
  static const uint32_t exponent_bias = 0;
363
  static const bool has_infinity = true;
364
  static const uint32_t NaN_pattern = 0;
365
};
366
367
// Traits for IEEE float.
368
// 1 sign bit, 8 exponent bits, 23 fractional bits.
369
template <>
370
struct HexFloatTraits<FloatProxy<float>> {
371
  using uint_type = uint32_t;
372
  using int_type = int32_t;
373
  using underlying_type = FloatProxy<float>;
374
  using underlying_typetraits = FloatProxyTraits<float>;
375
  using native_type = float;
376
  static const uint_type num_used_bits = 32;
377
  static const uint_type num_exponent_bits = 8;
378
  static const uint_type num_fraction_bits = 23;
379
  static const uint_type exponent_bias = 127;
380
  static const bool has_infinity = true;
381
  static const uint_type NaN_pattern = 0x7f80000;
382
};
383
384
// Traits for IEEE double.
385
// 1 sign bit, 11 exponent bits, 52 fractional bits.
386
template <>
387
struct HexFloatTraits<FloatProxy<double>> {
388
  using uint_type = uint64_t;
389
  using int_type = int64_t;
390
  using underlying_type = FloatProxy<double>;
391
  using underlying_typetraits = FloatProxyTraits<double>;
392
  using native_type = double;
393
  static const uint_type num_used_bits = 64;
394
  static const uint_type num_exponent_bits = 11;
395
  static const uint_type num_fraction_bits = 52;
396
  static const uint_type exponent_bias = 1023;
397
  static const bool has_infinity = true;
398
  static const uint_type NaN_pattern = 0x7FF0000000000000;
399
};
400
401
// Traits for FP8 E4M3.
402
// 1 sign bit, 4 exponent bits, 3 fractional bits.
403
template <>
404
struct HexFloatTraits<FloatProxy<Float8_E4M3>> {
405
  using uint_type = uint8_t;
406
  using int_type = int8_t;
407
  using underlying_type = FloatProxy<Float8_E4M3>;
408
  using underlying_typetraits = FloatProxyTraits<Float8_E4M3>;
409
  using native_type = uint8_t;
410
  static const uint_type num_used_bits = 8;
411
  static const uint_type num_exponent_bits = 4;
412
  static const uint_type num_fraction_bits = 3;
413
  static const uint_type exponent_bias = 7;
414
  static const bool has_infinity = false;
415
  static const uint_type NaN_pattern = 0x7F;
416
};
417
418
// Traits for FP8 E5M2.
419
// 1 sign bit, 4 exponent bits, 3 fractional bits.
420
template <>
421
struct HexFloatTraits<FloatProxy<Float8_E5M2>> {
422
  using uint_type = uint8_t;
423
  using int_type = int8_t;
424
  using underlying_type = FloatProxy<Float8_E5M2>;
425
  using underlying_typetraits = FloatProxyTraits<Float8_E5M2>;
426
  using native_type = uint8_t;
427
  static const uint_type num_used_bits = 8;
428
  static const uint_type num_exponent_bits = 5;
429
  static const uint_type num_fraction_bits = 2;
430
  static const uint_type exponent_bias = 15;
431
  static const bool has_infinity = true;
432
  static const uint_type NaN_pattern = 0x7c;
433
};
434
435
// Traits for IEEE half.
436
// 1 sign bit, 5 exponent bits, 10 fractional bits.
437
template <>
438
struct HexFloatTraits<FloatProxy<Float16>> {
439
  using uint_type = uint16_t;
440
  using int_type = int16_t;
441
  using underlying_type = FloatProxy<Float16>;
442
  using underlying_typetraits = FloatProxyTraits<Float16>;
443
  using native_type = uint16_t;
444
  static const uint_type num_used_bits = 16;
445
  static const uint_type num_exponent_bits = 5;
446
  static const uint_type num_fraction_bits = 10;
447
  static const uint_type exponent_bias = 15;
448
  static const bool has_infinity = true;
449
  static const uint_type NaN_pattern = 0x7c00;
450
};
451
452
// Traits for BFloat16.
453
// 1 sign bit, 7 exponent bits, 8 fractional bits.
454
template <>
455
struct HexFloatTraits<FloatProxy<BFloat16>> {
456
  using uint_type = uint16_t;
457
  using int_type = int16_t;
458
  using underlying_type = FloatProxy<BFloat16>;
459
  using underlying_typetraits = FloatProxyTraits<BFloat16>;
460
  using native_type = uint16_t;
461
  static const uint_type num_used_bits = 16;
462
  static const uint_type num_exponent_bits = 8;
463
  static const uint_type num_fraction_bits = 7;
464
  static const uint_type exponent_bias = 127;
465
  static const bool has_infinity = true;
466
  static const uint_type NaN_pattern = 0x7F80;
467
};
468
469
enum class round_direction {
470
  kToZero,
471
  kToNearestEven,
472
  kToPositiveInfinity,
473
  kToNegativeInfinity,
474
  max = kToNegativeInfinity
475
};
476
477
// Template class that houses a floating pointer number.
478
// It exposes a number of constants based on the provided traits to
479
// assist in interpreting the bits of the value.
480
template <typename T, typename Traits = HexFloatTraits<T>>
481
class HexFloat {
482
 public:
483
  using uint_type = typename Traits::uint_type;
484
  using int_type = typename Traits::int_type;
485
  using underlying_type = typename Traits::underlying_type;
486
  using native_type = typename Traits::native_type;
487
  using traits = Traits;
488
489
853k
  explicit HexFloat(T f) : value_(f) {}
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::HexFloat(spvtools::utils::FloatProxy<spvtools::utils::Float16>)
Line
Count
Source
489
179k
  explicit HexFloat(T f) : value_(f) {}
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > >::HexFloat(spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>)
Line
Count
Source
489
134k
  explicit HexFloat(T f) : value_(f) {}
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >::HexFloat(spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>)
Line
Count
Source
489
115k
  explicit HexFloat(T f) : value_(f) {}
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >::HexFloat(spvtools::utils::FloatProxy<spvtools::utils::BFloat16>)
Line
Count
Source
489
142k
  explicit HexFloat(T f) : value_(f) {}
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::HexFloat(spvtools::utils::FloatProxy<float>)
Line
Count
Source
489
232k
  explicit HexFloat(T f) : value_(f) {}
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >::HexFloat(spvtools::utils::FloatProxy<double>)
Line
Count
Source
489
48.9k
  explicit HexFloat(T f) : value_(f) {}
490
491
748k
  T value() const { return value_; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::value() const
Line
Count
Source
491
177k
  T value() const { return value_; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >::value() const
Line
Count
Source
491
144k
  T value() const { return value_; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::value() const
Line
Count
Source
491
168k
  T value() const { return value_; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > >::value() const
Line
Count
Source
491
117k
  T value() const { return value_; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >::value() const
Line
Count
Source
491
115k
  T value() const { return value_; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >::value() const
Line
Count
Source
491
25.3k
  T value() const { return value_; }
492
404k
  void set_value(T f) { value_ = f; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::set_value(spvtools::utils::FloatProxy<float>)
Line
Count
Source
492
118k
  void set_value(T f) { value_ = f; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::set_value(spvtools::utils::FloatProxy<spvtools::utils::Float16>)
Line
Count
Source
492
58.2k
  void set_value(T f) { value_ = f; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >::set_value(spvtools::utils::FloatProxy<spvtools::utils::BFloat16>)
Line
Count
Source
492
58.1k
  void set_value(T f) { value_ = f; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > >::set_value(spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>)
Line
Count
Source
492
61.1k
  void set_value(T f) { value_ = f; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >::set_value(spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>)
Line
Count
Source
492
61.1k
  void set_value(T f) { value_ = f; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >::set_value(spvtools::utils::FloatProxy<double>)
Line
Count
Source
492
46.8k
  void set_value(T f) { value_ = f; }
493
494
  // These are all written like this because it is convenient to have
495
  // compile-time constants for all of these values.
496
497
  // Pass-through values to save typing.
498
  static const uint32_t num_used_bits = Traits::num_used_bits;
499
  static const uint32_t exponent_bias = Traits::exponent_bias;
500
  static const uint32_t num_exponent_bits = Traits::num_exponent_bits;
501
  static const uint32_t num_fraction_bits = Traits::num_fraction_bits;
502
503
  // Number of bits to shift left to set the highest relevant bit.
504
  static const uint32_t top_bit_left_shift = num_used_bits - 1;
505
  // How many nibbles (hex characters) the fractional part takes up.
506
  static const uint32_t fraction_nibbles = (num_fraction_bits + 3) / 4;
507
  // If the fractional part does not fit evenly into a hex character (4-bits)
508
  // then we have to left-shift to get rid of leading 0s. This is the amount
509
  // we have to shift (might be 0).
510
  static const uint32_t num_overflow_bits =
511
      fraction_nibbles * 4 - num_fraction_bits;
512
513
  // The representation of the fraction, not the actual bits. This
514
  // includes the leading bit that is usually implicit.
515
  static const uint_type fraction_represent_mask =
516
      SetBits<uint_type, 0, num_fraction_bits + num_overflow_bits>::get;
517
518
  // The topmost bit in the nibble-aligned fraction.
519
  static const uint_type fraction_top_bit =
520
      uint_type(1) << (num_fraction_bits + num_overflow_bits - 1);
521
522
  // The least significant bit in the exponent, which is also the bit
523
  // immediately to the left of the significand.
524
  static const uint_type first_exponent_bit = uint_type(1)
525
                                              << (num_fraction_bits);
526
527
  // The mask for the encoded fraction. It does not include the
528
  // implicit bit.
529
  static const uint_type fraction_encode_mask =
530
      SetBits<uint_type, 0, num_fraction_bits>::get;
531
532
  // The bit that is used as a sign.
533
  static const uint_type sign_mask = uint_type(1) << top_bit_left_shift;
534
535
  // The bits that represent the exponent.
536
  static const uint_type exponent_mask =
537
      SetBits<uint_type, num_fraction_bits, num_exponent_bits>::get;
538
539
  // How far left the exponent is shifted.
540
  static const uint32_t exponent_left_shift = num_fraction_bits;
541
542
  // How far from the right edge the fraction is shifted.
543
  static const uint32_t fraction_right_shift =
544
      static_cast<uint32_t>(sizeof(uint_type) * 8) - num_fraction_bits;
545
546
  // The maximum representable unbiased exponent.
547
  static const int_type max_exponent =
548
      (exponent_mask >> num_fraction_bits) - exponent_bias;
549
  // The minimum representable exponent for normalized numbers.
550
  static const int_type min_exponent = -static_cast<int_type>(exponent_bias);
551
552
  // Returns the bits associated with the value.
553
493k
  uint_type getBits() const { return value_.data(); }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getBits() const
Line
Count
Source
553
483k
  uint_type getBits() const { return value_.data(); }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::getBits() const
Line
Count
Source
553
9.84k
  uint_type getBits() const { return value_.data(); }
Unexecuted instantiation: spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >::getBits() const
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >::getBits() const
Line
Count
Source
553
28
  uint_type getBits() const { return value_.data(); }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >::getBits() const
Line
Count
Source
553
10
  uint_type getBits() const { return value_.data(); }
554
555
  // Returns the bits associated with the value, without the leading sign bit.
556
74.1k
  uint_type getUnsignedBits() const {
557
74.1k
    return static_cast<uint_type>(value_.data() & ~sign_mask);
558
74.1k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getUnsignedBits() const
Line
Count
Source
556
72.1k
  uint_type getUnsignedBits() const {
557
72.1k
    return static_cast<uint_type>(value_.data() & ~sign_mask);
558
72.1k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >::getUnsignedBits() const
Line
Count
Source
556
244
  uint_type getUnsignedBits() const {
557
244
    return static_cast<uint_type>(value_.data() & ~sign_mask);
558
244
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::getUnsignedBits() const
Line
Count
Source
556
1.79k
  uint_type getUnsignedBits() const {
557
1.79k
    return static_cast<uint_type>(value_.data() & ~sign_mask);
558
1.79k
  }
559
560
  // Returns the bits associated with the exponent, shifted to start at the
561
  // lsb of the type.
562
104k
  const uint_type getExponentBits() const {
563
104k
    return static_cast<uint_type>((getBits() & exponent_mask) >>
564
104k
                                  num_fraction_bits);
565
104k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getExponentBits() const
Line
Count
Source
562
102k
  const uint_type getExponentBits() const {
563
102k
    return static_cast<uint_type>((getBits() & exponent_mask) >>
564
102k
                                  num_fraction_bits);
565
102k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::getExponentBits() const
Line
Count
Source
562
2.15k
  const uint_type getExponentBits() const {
563
2.15k
    return static_cast<uint_type>((getBits() & exponent_mask) >>
564
2.15k
                                  num_fraction_bits);
565
2.15k
  }
566
567
  // Returns the exponent in unbiased form. This is the exponent in the
568
  // human-friendly form.
569
104k
  const int_type getUnbiasedExponent() const {
570
104k
    return static_cast<int_type>(getExponentBits() - exponent_bias);
571
104k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getUnbiasedExponent() const
Line
Count
Source
569
102k
  const int_type getUnbiasedExponent() const {
570
102k
    return static_cast<int_type>(getExponentBits() - exponent_bias);
571
102k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::getUnbiasedExponent() const
Line
Count
Source
569
2.15k
  const int_type getUnbiasedExponent() const {
570
2.15k
    return static_cast<int_type>(getExponentBits() - exponent_bias);
571
2.15k
  }
572
573
  // Returns just the significand bits from the value.
574
113k
  const uint_type getSignificandBits() const {
575
113k
    return getBits() & fraction_encode_mask;
576
113k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getSignificandBits() const
Line
Count
Source
574
111k
  const uint_type getSignificandBits() const {
575
111k
    return getBits() & fraction_encode_mask;
576
111k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::getSignificandBits() const
Line
Count
Source
574
2.38k
  const uint_type getSignificandBits() const {
575
2.38k
    return getBits() & fraction_encode_mask;
576
2.38k
  }
577
578
  // If the number was normalized, returns the unbiased exponent.
579
  // If the number was denormal, normalize the exponent first.
580
52.1k
  const int_type getUnbiasedNormalizedExponent() const {
581
52.1k
    if ((getBits() & ~sign_mask) == 0) {  // special case if everything is 0
582
0
      return 0;
583
0
    }
584
52.1k
    int_type exp = getUnbiasedExponent();
585
52.1k
    if (exp == min_exponent) {  // We are in denorm land.
586
9.51k
      uint_type significand_bits = getSignificandBits();
587
92.1k
      while ((significand_bits & (first_exponent_bit >> 1)) == 0) {
588
82.6k
        significand_bits = static_cast<uint_type>(significand_bits << 1);
589
82.6k
        exp = static_cast<int_type>(exp - 1);
590
82.6k
      }
591
9.51k
      significand_bits &= fraction_encode_mask;
592
9.51k
    }
593
52.1k
    return exp;
594
52.1k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getUnbiasedNormalizedExponent() const
Line
Count
Source
580
51.1k
  const int_type getUnbiasedNormalizedExponent() const {
581
51.1k
    if ((getBits() & ~sign_mask) == 0) {  // special case if everything is 0
582
0
      return 0;
583
0
    }
584
51.1k
    int_type exp = getUnbiasedExponent();
585
51.1k
    if (exp == min_exponent) {  // We are in denorm land.
586
9.29k
      uint_type significand_bits = getSignificandBits();
587
91.2k
      while ((significand_bits & (first_exponent_bit >> 1)) == 0) {
588
81.9k
        significand_bits = static_cast<uint_type>(significand_bits << 1);
589
81.9k
        exp = static_cast<int_type>(exp - 1);
590
81.9k
      }
591
9.29k
      significand_bits &= fraction_encode_mask;
592
9.29k
    }
593
51.1k
    return exp;
594
51.1k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::getUnbiasedNormalizedExponent() const
Line
Count
Source
580
1.07k
  const int_type getUnbiasedNormalizedExponent() const {
581
1.07k
    if ((getBits() & ~sign_mask) == 0) {  // special case if everything is 0
582
0
      return 0;
583
0
    }
584
1.07k
    int_type exp = getUnbiasedExponent();
585
1.07k
    if (exp == min_exponent) {  // We are in denorm land.
586
225
      uint_type significand_bits = getSignificandBits();
587
871
      while ((significand_bits & (first_exponent_bit >> 1)) == 0) {
588
646
        significand_bits = static_cast<uint_type>(significand_bits << 1);
589
646
        exp = static_cast<int_type>(exp - 1);
590
646
      }
591
225
      significand_bits &= fraction_encode_mask;
592
225
    }
593
1.07k
    return exp;
594
1.07k
  }
595
596
  // Returns the signficand after it has been normalized.
597
52.1k
  const uint_type getNormalizedSignificand() const {
598
52.1k
    int_type unbiased_exponent = getUnbiasedNormalizedExponent();
599
52.1k
    uint_type significand = getSignificandBits();
600
144k
    for (int_type i = unbiased_exponent; i <= min_exponent; ++i) {
601
92.1k
      significand = static_cast<uint_type>(significand << 1);
602
92.1k
    }
603
52.1k
    significand &= fraction_encode_mask;
604
52.1k
    return significand;
605
52.1k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getNormalizedSignificand() const
Line
Count
Source
597
51.1k
  const uint_type getNormalizedSignificand() const {
598
51.1k
    int_type unbiased_exponent = getUnbiasedNormalizedExponent();
599
51.1k
    uint_type significand = getSignificandBits();
600
142k
    for (int_type i = unbiased_exponent; i <= min_exponent; ++i) {
601
91.2k
      significand = static_cast<uint_type>(significand << 1);
602
91.2k
    }
603
51.1k
    significand &= fraction_encode_mask;
604
51.1k
    return significand;
605
51.1k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::getNormalizedSignificand() const
Line
Count
Source
597
1.07k
  const uint_type getNormalizedSignificand() const {
598
1.07k
    int_type unbiased_exponent = getUnbiasedNormalizedExponent();
599
1.07k
    uint_type significand = getSignificandBits();
600
1.95k
    for (int_type i = unbiased_exponent; i <= min_exponent; ++i) {
601
871
      significand = static_cast<uint_type>(significand << 1);
602
871
    }
603
1.07k
    significand &= fraction_encode_mask;
604
1.07k
    return significand;
605
1.07k
  }
606
607
  // Returns true if this number represents a negative value.
608
118k
  bool isNegative() const { return (getBits() & sign_mask) != 0; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::isNegative() const
Line
Count
Source
608
116k
  bool isNegative() const { return (getBits() & sign_mask) != 0; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::isNegative() const
Line
Count
Source
608
2.20k
  bool isNegative() const { return (getBits() & sign_mask) != 0; }
Unexecuted instantiation: spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >::isNegative() const
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >::isNegative() const
Line
Count
Source
608
28
  bool isNegative() const { return (getBits() & sign_mask) != 0; }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >::isNegative() const
Line
Count
Source
608
10
  bool isNegative() const { return (getBits() & sign_mask) != 0; }
609
610
  // Sets this HexFloat from the individual components.
611
  // Note this assumes EVERY significand is normalized, and has an implicit
612
  // leading one. This means that the only way that this method will set 0,
613
  // is if you set a number so denormalized that it underflows.
614
  // Do not use this method with raw bits extracted from a subnormal number,
615
  // since subnormals do not have an implicit leading 1 in the significand.
616
  // The significand is also expected to be in the
617
  // lowest-most num_fraction_bits of the uint_type.
618
  // The exponent is expected to be unbiased, meaning an exponent of
619
  // 0 actually means 0.
620
  // If underflow_round_up is set, then on underflow, if a number is non-0
621
  // and would underflow, we round up to the smallest denorm.
622
  void setFromSignUnbiasedExponentAndNormalizedSignificand(
623
      bool negative, int_type exponent, uint_type significand,
624
50.0k
      bool round_denorm_up) {
625
50.0k
    bool significand_is_zero = significand == 0;
626
627
50.0k
    if (exponent <= min_exponent) {
628
      // If this was denormalized, then we have to shift the bit on, meaning
629
      // the significand is not zero.
630
20.8k
      significand_is_zero = false;
631
20.8k
      significand |= first_exponent_bit;
632
20.8k
      significand = static_cast<uint_type>(significand >> 1);
633
20.8k
    }
634
635
787k
    while (exponent < min_exponent) {
636
737k
      significand = static_cast<uint_type>(significand >> 1);
637
737k
      ++exponent;
638
737k
    }
639
640
50.0k
    if (exponent == min_exponent) {
641
20.8k
      if (significand == 0 && !significand_is_zero && round_denorm_up) {
642
0
        significand = static_cast<uint_type>(0x1);
643
0
      }
644
20.8k
    }
645
646
50.0k
    uint_type new_value = 0;
647
50.0k
    if (negative) {
648
13.4k
      new_value = static_cast<uint_type>(new_value | sign_mask);
649
13.4k
    }
650
50.0k
    exponent = static_cast<int_type>(exponent + exponent_bias);
651
50.0k
    assert(exponent >= 0);
652
653
    // put it all together
654
50.0k
    exponent = static_cast<uint_type>((exponent << exponent_left_shift) &
655
50.0k
                                      exponent_mask);
656
50.0k
    significand = static_cast<uint_type>(significand & fraction_encode_mask);
657
50.0k
    new_value = static_cast<uint_type>(new_value | (exponent | significand));
658
50.0k
    value_ = T(new_value);
659
50.0k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::setFromSignUnbiasedExponentAndNormalizedSignificand(bool, short, unsigned short, bool)
Line
Count
Source
624
13.8k
      bool round_denorm_up) {
625
13.8k
    bool significand_is_zero = significand == 0;
626
627
13.8k
    if (exponent <= min_exponent) {
628
      // If this was denormalized, then we have to shift the bit on, meaning
629
      // the significand is not zero.
630
6.58k
      significand_is_zero = false;
631
6.58k
      significand |= first_exponent_bit;
632
6.58k
      significand = static_cast<uint_type>(significand >> 1);
633
6.58k
    }
634
635
449k
    while (exponent < min_exponent) {
636
436k
      significand = static_cast<uint_type>(significand >> 1);
637
436k
      ++exponent;
638
436k
    }
639
640
13.8k
    if (exponent == min_exponent) {
641
6.58k
      if (significand == 0 && !significand_is_zero && round_denorm_up) {
642
0
        significand = static_cast<uint_type>(0x1);
643
0
      }
644
6.58k
    }
645
646
13.8k
    uint_type new_value = 0;
647
13.8k
    if (negative) {
648
3.55k
      new_value = static_cast<uint_type>(new_value | sign_mask);
649
3.55k
    }
650
13.8k
    exponent = static_cast<int_type>(exponent + exponent_bias);
651
13.8k
    assert(exponent >= 0);
652
653
    // put it all together
654
13.8k
    exponent = static_cast<uint_type>((exponent << exponent_left_shift) &
655
13.8k
                                      exponent_mask);
656
13.8k
    significand = static_cast<uint_type>(significand & fraction_encode_mask);
657
13.8k
    new_value = static_cast<uint_type>(new_value | (exponent | significand));
658
13.8k
    value_ = T(new_value);
659
13.8k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >::setFromSignUnbiasedExponentAndNormalizedSignificand(bool, short, unsigned short, bool)
Line
Count
Source
624
8.31k
      bool round_denorm_up) {
625
8.31k
    bool significand_is_zero = significand == 0;
626
627
8.31k
    if (exponent <= min_exponent) {
628
      // If this was denormalized, then we have to shift the bit on, meaning
629
      // the significand is not zero.
630
2.89k
      significand_is_zero = false;
631
2.89k
      significand |= first_exponent_bit;
632
2.89k
      significand = static_cast<uint_type>(significand >> 1);
633
2.89k
    }
634
635
45.4k
    while (exponent < min_exponent) {
636
37.1k
      significand = static_cast<uint_type>(significand >> 1);
637
37.1k
      ++exponent;
638
37.1k
    }
639
640
8.31k
    if (exponent == min_exponent) {
641
2.89k
      if (significand == 0 && !significand_is_zero && round_denorm_up) {
642
0
        significand = static_cast<uint_type>(0x1);
643
0
      }
644
2.89k
    }
645
646
8.31k
    uint_type new_value = 0;
647
8.31k
    if (negative) {
648
3.31k
      new_value = static_cast<uint_type>(new_value | sign_mask);
649
3.31k
    }
650
8.31k
    exponent = static_cast<int_type>(exponent + exponent_bias);
651
8.31k
    assert(exponent >= 0);
652
653
    // put it all together
654
8.31k
    exponent = static_cast<uint_type>((exponent << exponent_left_shift) &
655
8.31k
                                      exponent_mask);
656
8.31k
    significand = static_cast<uint_type>(significand & fraction_encode_mask);
657
8.31k
    new_value = static_cast<uint_type>(new_value | (exponent | significand));
658
8.31k
    value_ = T(new_value);
659
8.31k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > >::setFromSignUnbiasedExponentAndNormalizedSignificand(bool, signed char, unsigned char, bool)
Line
Count
Source
624
12.9k
      bool round_denorm_up) {
625
12.9k
    bool significand_is_zero = significand == 0;
626
627
12.9k
    if (exponent <= min_exponent) {
628
      // If this was denormalized, then we have to shift the bit on, meaning
629
      // the significand is not zero.
630
5.48k
      significand_is_zero = false;
631
5.48k
      significand |= first_exponent_bit;
632
5.48k
      significand = static_cast<uint_type>(significand >> 1);
633
5.48k
    }
634
635
112k
    while (exponent < min_exponent) {
636
99.1k
      significand = static_cast<uint_type>(significand >> 1);
637
99.1k
      ++exponent;
638
99.1k
    }
639
640
12.9k
    if (exponent == min_exponent) {
641
5.48k
      if (significand == 0 && !significand_is_zero && round_denorm_up) {
642
0
        significand = static_cast<uint_type>(0x1);
643
0
      }
644
5.48k
    }
645
646
12.9k
    uint_type new_value = 0;
647
12.9k
    if (negative) {
648
3.03k
      new_value = static_cast<uint_type>(new_value | sign_mask);
649
3.03k
    }
650
12.9k
    exponent = static_cast<int_type>(exponent + exponent_bias);
651
12.9k
    assert(exponent >= 0);
652
653
    // put it all together
654
12.9k
    exponent = static_cast<uint_type>((exponent << exponent_left_shift) &
655
12.9k
                                      exponent_mask);
656
12.9k
    significand = static_cast<uint_type>(significand & fraction_encode_mask);
657
12.9k
    new_value = static_cast<uint_type>(new_value | (exponent | significand));
658
12.9k
    value_ = T(new_value);
659
12.9k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >::setFromSignUnbiasedExponentAndNormalizedSignificand(bool, signed char, unsigned char, bool)
Line
Count
Source
624
14.5k
      bool round_denorm_up) {
625
14.5k
    bool significand_is_zero = significand == 0;
626
627
14.5k
    if (exponent <= min_exponent) {
628
      // If this was denormalized, then we have to shift the bit on, meaning
629
      // the significand is not zero.
630
5.84k
      significand_is_zero = false;
631
5.84k
      significand |= first_exponent_bit;
632
5.84k
      significand = static_cast<uint_type>(significand >> 1);
633
5.84k
    }
634
635
179k
    while (exponent < min_exponent) {
636
165k
      significand = static_cast<uint_type>(significand >> 1);
637
165k
      ++exponent;
638
165k
    }
639
640
14.5k
    if (exponent == min_exponent) {
641
5.84k
      if (significand == 0 && !significand_is_zero && round_denorm_up) {
642
0
        significand = static_cast<uint_type>(0x1);
643
0
      }
644
5.84k
    }
645
646
14.5k
    uint_type new_value = 0;
647
14.5k
    if (negative) {
648
3.49k
      new_value = static_cast<uint_type>(new_value | sign_mask);
649
3.49k
    }
650
14.5k
    exponent = static_cast<int_type>(exponent + exponent_bias);
651
14.5k
    assert(exponent >= 0);
652
653
    // put it all together
654
14.5k
    exponent = static_cast<uint_type>((exponent << exponent_left_shift) &
655
14.5k
                                      exponent_mask);
656
14.5k
    significand = static_cast<uint_type>(significand & fraction_encode_mask);
657
14.5k
    new_value = static_cast<uint_type>(new_value | (exponent | significand));
658
14.5k
    value_ = T(new_value);
659
14.5k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::setFromSignUnbiasedExponentAndNormalizedSignificand(bool, int, unsigned int, bool)
Line
Count
Source
624
383
      bool round_denorm_up) {
625
383
    bool significand_is_zero = significand == 0;
626
627
383
    if (exponent <= min_exponent) {
628
      // If this was denormalized, then we have to shift the bit on, meaning
629
      // the significand is not zero.
630
0
      significand_is_zero = false;
631
0
      significand |= first_exponent_bit;
632
0
      significand = static_cast<uint_type>(significand >> 1);
633
0
    }
634
635
383
    while (exponent < min_exponent) {
636
0
      significand = static_cast<uint_type>(significand >> 1);
637
0
      ++exponent;
638
0
    }
639
640
383
    if (exponent == min_exponent) {
641
0
      if (significand == 0 && !significand_is_zero && round_denorm_up) {
642
0
        significand = static_cast<uint_type>(0x1);
643
0
      }
644
0
    }
645
646
383
    uint_type new_value = 0;
647
383
    if (negative) {
648
75
      new_value = static_cast<uint_type>(new_value | sign_mask);
649
75
    }
650
383
    exponent = static_cast<int_type>(exponent + exponent_bias);
651
383
    assert(exponent >= 0);
652
653
    // put it all together
654
383
    exponent = static_cast<uint_type>((exponent << exponent_left_shift) &
655
383
                                      exponent_mask);
656
383
    significand = static_cast<uint_type>(significand & fraction_encode_mask);
657
383
    new_value = static_cast<uint_type>(new_value | (exponent | significand));
658
383
    value_ = T(new_value);
659
383
  }
660
661
  // Increments the significand of this number by the given amount.
662
  // If this would spill the significand into the implicit bit,
663
  // carry is set to true and the significand is shifted to fit into
664
  // the correct location, otherwise carry is set to false.
665
  // All significands and to_increment are assumed to be within the bounds
666
  // for a valid significand.
667
  static uint_type incrementSignificand(uint_type significand,
668
0
                                        uint_type to_increment, bool* carry) {
669
0
    significand = static_cast<uint_type>(significand + to_increment);
670
0
    *carry = false;
671
0
    if (significand & first_exponent_bit) {
672
0
      *carry = true;
673
      // The implicit 1-bit will have carried, so we should zero-out the
674
      // top bit and shift back.
675
0
      significand = static_cast<uint_type>(significand & ~first_exponent_bit);
676
0
      significand = static_cast<uint_type>(significand >> 1);
677
0
    }
678
0
    return significand;
679
0
  }
Unexecuted instantiation: spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::incrementSignificand(unsigned int, unsigned int, bool*)
Unexecuted instantiation: spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::incrementSignificand(unsigned short, unsigned short, bool*)
680
681
#if GCC_VERSION == 40801
682
  // These exist because MSVC throws warnings on negative right-shifts
683
  // even if they are not going to be executed. Eg:
684
  // constant_number < 0? 0: constant_number
685
  // These convert the negative left-shifts into right shifts.
686
  template <int_type N>
687
  struct negatable_left_shift {
688
    static uint_type val(uint_type val) {
689
      if (N > 0) {
690
        return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
691
      } else {
692
        return static_cast<uint_type>(static_cast<uint64_t>(val) >> N);
693
      }
694
    }
695
  };
696
697
  template <int_type N>
698
  struct negatable_right_shift {
699
    static uint_type val(uint_type val) {
700
      if (N > 0) {
701
        return static_cast<uint_type>(val >> N);
702
      } else {
703
        return static_cast<uint_type>(val << N);
704
      }
705
    }
706
  };
707
708
#else
709
  // These exist because MSVC throws warnings on negative right-shifts
710
  // even if they are not going to be executed. Eg:
711
  // constant_number < 0? 0: constant_number
712
  // These convert the negative left-shifts into right shifts.
713
  template <int_type N, typename enable = void>
714
  struct negatable_left_shift {
715
132
    static uint_type val(uint_type val) {
716
132
      return static_cast<uint_type>(static_cast<uint64_t>(val) >> -N);
717
132
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<-13, void>::val(unsigned int)
Line
Count
Source
715
132
    static uint_type val(uint_type val) {
716
132
      return static_cast<uint_type>(static_cast<uint64_t>(val) >> -N);
717
132
    }
Unexecuted instantiation: spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<-16, void>::val(unsigned int)
Unexecuted instantiation: spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<-20, void>::val(unsigned int)
Unexecuted instantiation: spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<-21, void>::val(unsigned int)
Unexecuted instantiation: spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::negatable_left_shift<(short)-13, void>::val(unsigned short)
Unexecuted instantiation: spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::negatable_left_shift<(short)-14, void>::val(unsigned short)
718
  };
719
720
  template <int_type N>
721
  struct negatable_left_shift<N, typename std::enable_if<N >= 0>::type> {
722
146
    static uint_type val(uint_type val) {
723
146
      return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
724
146
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<13, void>::val(unsigned int)
Line
Count
Source
722
4
    static uint_type val(uint_type val) {
723
4
      return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
724
4
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<12, void>::val(unsigned int)
Line
Count
Source
722
4
    static uint_type val(uint_type val) {
723
4
      return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
724
4
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<16, void>::val(unsigned int)
Line
Count
Source
722
1
    static uint_type val(uint_type val) {
723
1
      return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
724
1
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<15, void>::val(unsigned int)
Line
Count
Source
722
1
    static uint_type val(uint_type val) {
723
1
      return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
724
1
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<20, void>::val(unsigned int)
Line
Count
Source
722
2
    static uint_type val(uint_type val) {
723
2
      return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
724
2
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<19, void>::val(unsigned int)
Line
Count
Source
722
1
    static uint_type val(uint_type val) {
723
1
      return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
724
1
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_left_shift<21, void>::val(unsigned int)
Line
Count
Source
722
1
    static uint_type val(uint_type val) {
723
1
      return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
724
1
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::negatable_left_shift<(short)13, void>::val(unsigned short)
Line
Count
Source
722
132
    static uint_type val(uint_type val) {
723
132
      return static_cast<uint_type>(static_cast<uint64_t>(val) << N);
724
132
    }
725
  };
726
727
  template <int_type N, typename enable = void>
728
  struct negatable_right_shift {
729
0
    static uint_type val(uint_type val) {
730
0
      return static_cast<uint_type>(static_cast<uint64_t>(val) << -N);
731
0
    }
732
  };
733
734
  template <int_type N>
735
  struct negatable_right_shift<N, typename std::enable_if<N >= 0>::type> {
736
51.1k
    static uint_type val(uint_type val) {
737
51.1k
      return static_cast<uint_type>(static_cast<uint64_t>(val) >> N);
738
51.1k
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_right_shift<13, void>::val(unsigned int)
Line
Count
Source
736
14.5k
    static uint_type val(uint_type val) {
737
14.5k
      return static_cast<uint_type>(static_cast<uint64_t>(val) >> N);
738
14.5k
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_right_shift<16, void>::val(unsigned int)
Line
Count
Source
736
8.31k
    static uint_type val(uint_type val) {
737
8.31k
      return static_cast<uint_type>(static_cast<uint64_t>(val) >> N);
738
8.31k
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_right_shift<20, void>::val(unsigned int)
Line
Count
Source
736
13.7k
    static uint_type val(uint_type val) {
737
13.7k
      return static_cast<uint_type>(static_cast<uint64_t>(val) >> N);
738
13.7k
    }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::negatable_right_shift<21, void>::val(unsigned int)
Line
Count
Source
736
14.5k
    static uint_type val(uint_type val) {
737
14.5k
      return static_cast<uint_type>(static_cast<uint64_t>(val) >> N);
738
14.5k
    }
739
  };
740
#endif
741
742
  // Returns the significand, rounded to fit in a significand in
743
  // other_T. This is shifted so that the most significant
744
  // bit of the rounded number lines up with the most significant bit
745
  // of the returned significand.
746
  template <typename other_T>
747
  typename other_T::uint_type getRoundedNormalizedSignificand(
748
52.1k
      round_direction dir, bool* carry_bit) {
749
52.1k
    using other_uint_type = typename other_T::uint_type;
750
52.1k
    static const int_type num_throwaway_bits =
751
52.1k
        static_cast<int_type>(num_fraction_bits) -
752
52.1k
        static_cast<int_type>(other_T::num_fraction_bits);
753
754
52.1k
    static const uint_type last_significant_bit =
755
52.1k
        (num_throwaway_bits < 0)
756
52.1k
            ? 0
757
52.1k
            : negatable_left_shift<num_throwaway_bits>::val(1u);
758
52.1k
    static const uint_type first_rounded_bit =
759
52.1k
        (num_throwaway_bits < 1)
760
52.1k
            ? 0
761
52.1k
            : negatable_left_shift<num_throwaway_bits - 1>::val(1u);
762
763
52.1k
    static const uint_type throwaway_mask_bits =
764
52.1k
        num_throwaway_bits > 0 ? num_throwaway_bits : 0;
765
52.1k
    static const uint_type throwaway_mask =
766
52.1k
        SetBits<uint_type, 0, throwaway_mask_bits>::get;
767
768
52.1k
    *carry_bit = false;
769
52.1k
    other_uint_type out_val = 0;
770
52.1k
    uint_type significand = getNormalizedSignificand();
771
    // If we are up-casting, then we just have to shift to the right location.
772
52.1k
    if (num_throwaway_bits <= 0) {
773
1.07k
      out_val = static_cast<other_uint_type>(significand);
774
1.07k
      uint_type shift_amount = static_cast<uint_type>(-num_throwaway_bits);
775
1.07k
      out_val = static_cast<other_uint_type>(out_val << shift_amount);
776
1.07k
      return out_val;
777
1.07k
    }
778
779
    // If every non-representable bit is 0, then we don't have any casting to
780
    // do.
781
51.1k
    if ((significand & throwaway_mask) == 0) {
782
26.4k
      return static_cast<other_uint_type>(
783
26.4k
          negatable_right_shift<num_throwaway_bits>::val(significand));
784
26.4k
    }
785
786
24.6k
    bool round_away_from_zero = false;
787
    // We actually have to narrow the significand here, so we have to follow the
788
    // rounding rules.
789
24.6k
    switch (dir) {
790
24.6k
      case round_direction::kToZero:
791
24.6k
        break;
792
0
      case round_direction::kToPositiveInfinity:
793
0
        round_away_from_zero = !isNegative();
794
0
        break;
795
0
      case round_direction::kToNegativeInfinity:
796
0
        round_away_from_zero = isNegative();
797
0
        break;
798
0
      case round_direction::kToNearestEven:
799
        // Have to round down, round bit is 0
800
0
        if ((first_rounded_bit & significand) == 0) {
801
0
          break;
802
0
        }
803
0
        if (((significand & throwaway_mask) & ~first_rounded_bit) != 0) {
804
          // If any subsequent bit of the rounded portion is non-0 then we round
805
          // up.
806
0
          round_away_from_zero = true;
807
0
          break;
808
0
        }
809
        // We are exactly half-way between 2 numbers, pick even.
810
0
        if ((significand & last_significant_bit) != 0) {
811
          // 1 for our last bit, round up.
812
0
          round_away_from_zero = true;
813
0
          break;
814
0
        }
815
0
        break;
816
24.6k
    }
817
818
24.6k
    if (round_away_from_zero) {
819
0
      return static_cast<other_uint_type>(
820
0
          negatable_right_shift<num_throwaway_bits>::val(incrementSignificand(
821
0
              significand, last_significant_bit, carry_bit)));
822
24.6k
    } else {
823
24.6k
      return static_cast<other_uint_type>(
824
24.6k
          negatable_right_shift<num_throwaway_bits>::val(significand));
825
24.6k
    }
826
24.6k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::uint_type spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getRoundedNormalizedSignificand<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > > >(spvtools::utils::round_direction, bool*)
Line
Count
Source
748
14.5k
      round_direction dir, bool* carry_bit) {
749
14.5k
    using other_uint_type = typename other_T::uint_type;
750
14.5k
    static const int_type num_throwaway_bits =
751
14.5k
        static_cast<int_type>(num_fraction_bits) -
752
14.5k
        static_cast<int_type>(other_T::num_fraction_bits);
753
754
14.5k
    static const uint_type last_significant_bit =
755
14.5k
        (num_throwaway_bits < 0)
756
14.5k
            ? 0
757
14.5k
            : negatable_left_shift<num_throwaway_bits>::val(1u);
758
14.5k
    static const uint_type first_rounded_bit =
759
14.5k
        (num_throwaway_bits < 1)
760
14.5k
            ? 0
761
14.5k
            : negatable_left_shift<num_throwaway_bits - 1>::val(1u);
762
763
14.5k
    static const uint_type throwaway_mask_bits =
764
14.5k
        num_throwaway_bits > 0 ? num_throwaway_bits : 0;
765
14.5k
    static const uint_type throwaway_mask =
766
14.5k
        SetBits<uint_type, 0, throwaway_mask_bits>::get;
767
768
14.5k
    *carry_bit = false;
769
14.5k
    other_uint_type out_val = 0;
770
14.5k
    uint_type significand = getNormalizedSignificand();
771
    // If we are up-casting, then we just have to shift to the right location.
772
14.5k
    if (num_throwaway_bits <= 0) {
773
0
      out_val = static_cast<other_uint_type>(significand);
774
0
      uint_type shift_amount = static_cast<uint_type>(-num_throwaway_bits);
775
0
      out_val = static_cast<other_uint_type>(out_val << shift_amount);
776
0
      return out_val;
777
0
    }
778
779
    // If every non-representable bit is 0, then we don't have any casting to
780
    // do.
781
14.5k
    if ((significand & throwaway_mask) == 0) {
782
7.75k
      return static_cast<other_uint_type>(
783
7.75k
          negatable_right_shift<num_throwaway_bits>::val(significand));
784
7.75k
    }
785
786
6.78k
    bool round_away_from_zero = false;
787
    // We actually have to narrow the significand here, so we have to follow the
788
    // rounding rules.
789
6.78k
    switch (dir) {
790
6.78k
      case round_direction::kToZero:
791
6.78k
        break;
792
0
      case round_direction::kToPositiveInfinity:
793
0
        round_away_from_zero = !isNegative();
794
0
        break;
795
0
      case round_direction::kToNegativeInfinity:
796
0
        round_away_from_zero = isNegative();
797
0
        break;
798
0
      case round_direction::kToNearestEven:
799
        // Have to round down, round bit is 0
800
0
        if ((first_rounded_bit & significand) == 0) {
801
0
          break;
802
0
        }
803
0
        if (((significand & throwaway_mask) & ~first_rounded_bit) != 0) {
804
          // If any subsequent bit of the rounded portion is non-0 then we round
805
          // up.
806
0
          round_away_from_zero = true;
807
0
          break;
808
0
        }
809
        // We are exactly half-way between 2 numbers, pick even.
810
0
        if ((significand & last_significant_bit) != 0) {
811
          // 1 for our last bit, round up.
812
0
          round_away_from_zero = true;
813
0
          break;
814
0
        }
815
0
        break;
816
6.78k
    }
817
818
6.78k
    if (round_away_from_zero) {
819
0
      return static_cast<other_uint_type>(
820
0
          negatable_right_shift<num_throwaway_bits>::val(incrementSignificand(
821
0
              significand, last_significant_bit, carry_bit)));
822
6.78k
    } else {
823
6.78k
      return static_cast<other_uint_type>(
824
6.78k
          negatable_right_shift<num_throwaway_bits>::val(significand));
825
6.78k
    }
826
6.78k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >::uint_type spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getRoundedNormalizedSignificand<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > > >(spvtools::utils::round_direction, bool*)
Line
Count
Source
748
8.31k
      round_direction dir, bool* carry_bit) {
749
8.31k
    using other_uint_type = typename other_T::uint_type;
750
8.31k
    static const int_type num_throwaway_bits =
751
8.31k
        static_cast<int_type>(num_fraction_bits) -
752
8.31k
        static_cast<int_type>(other_T::num_fraction_bits);
753
754
8.31k
    static const uint_type last_significant_bit =
755
8.31k
        (num_throwaway_bits < 0)
756
8.31k
            ? 0
757
8.31k
            : negatable_left_shift<num_throwaway_bits>::val(1u);
758
8.31k
    static const uint_type first_rounded_bit =
759
8.31k
        (num_throwaway_bits < 1)
760
8.31k
            ? 0
761
8.31k
            : negatable_left_shift<num_throwaway_bits - 1>::val(1u);
762
763
8.31k
    static const uint_type throwaway_mask_bits =
764
8.31k
        num_throwaway_bits > 0 ? num_throwaway_bits : 0;
765
8.31k
    static const uint_type throwaway_mask =
766
8.31k
        SetBits<uint_type, 0, throwaway_mask_bits>::get;
767
768
8.31k
    *carry_bit = false;
769
8.31k
    other_uint_type out_val = 0;
770
8.31k
    uint_type significand = getNormalizedSignificand();
771
    // If we are up-casting, then we just have to shift to the right location.
772
8.31k
    if (num_throwaway_bits <= 0) {
773
0
      out_val = static_cast<other_uint_type>(significand);
774
0
      uint_type shift_amount = static_cast<uint_type>(-num_throwaway_bits);
775
0
      out_val = static_cast<other_uint_type>(out_val << shift_amount);
776
0
      return out_val;
777
0
    }
778
779
    // If every non-representable bit is 0, then we don't have any casting to
780
    // do.
781
8.31k
    if ((significand & throwaway_mask) == 0) {
782
6.28k
      return static_cast<other_uint_type>(
783
6.28k
          negatable_right_shift<num_throwaway_bits>::val(significand));
784
6.28k
    }
785
786
2.02k
    bool round_away_from_zero = false;
787
    // We actually have to narrow the significand here, so we have to follow the
788
    // rounding rules.
789
2.02k
    switch (dir) {
790
2.02k
      case round_direction::kToZero:
791
2.02k
        break;
792
0
      case round_direction::kToPositiveInfinity:
793
0
        round_away_from_zero = !isNegative();
794
0
        break;
795
0
      case round_direction::kToNegativeInfinity:
796
0
        round_away_from_zero = isNegative();
797
0
        break;
798
0
      case round_direction::kToNearestEven:
799
        // Have to round down, round bit is 0
800
0
        if ((first_rounded_bit & significand) == 0) {
801
0
          break;
802
0
        }
803
0
        if (((significand & throwaway_mask) & ~first_rounded_bit) != 0) {
804
          // If any subsequent bit of the rounded portion is non-0 then we round
805
          // up.
806
0
          round_away_from_zero = true;
807
0
          break;
808
0
        }
809
        // We are exactly half-way between 2 numbers, pick even.
810
0
        if ((significand & last_significant_bit) != 0) {
811
          // 1 for our last bit, round up.
812
0
          round_away_from_zero = true;
813
0
          break;
814
0
        }
815
0
        break;
816
2.02k
    }
817
818
2.02k
    if (round_away_from_zero) {
819
0
      return static_cast<other_uint_type>(
820
0
          negatable_right_shift<num_throwaway_bits>::val(incrementSignificand(
821
0
              significand, last_significant_bit, carry_bit)));
822
2.02k
    } else {
823
2.02k
      return static_cast<other_uint_type>(
824
2.02k
          negatable_right_shift<num_throwaway_bits>::val(significand));
825
2.02k
    }
826
2.02k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > >::uint_type spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getRoundedNormalizedSignificand<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > > >(spvtools::utils::round_direction, bool*)
Line
Count
Source
748
13.7k
      round_direction dir, bool* carry_bit) {
749
13.7k
    using other_uint_type = typename other_T::uint_type;
750
13.7k
    static const int_type num_throwaway_bits =
751
13.7k
        static_cast<int_type>(num_fraction_bits) -
752
13.7k
        static_cast<int_type>(other_T::num_fraction_bits);
753
754
13.7k
    static const uint_type last_significant_bit =
755
13.7k
        (num_throwaway_bits < 0)
756
13.7k
            ? 0
757
13.7k
            : negatable_left_shift<num_throwaway_bits>::val(1u);
758
13.7k
    static const uint_type first_rounded_bit =
759
13.7k
        (num_throwaway_bits < 1)
760
13.7k
            ? 0
761
13.7k
            : negatable_left_shift<num_throwaway_bits - 1>::val(1u);
762
763
13.7k
    static const uint_type throwaway_mask_bits =
764
13.7k
        num_throwaway_bits > 0 ? num_throwaway_bits : 0;
765
13.7k
    static const uint_type throwaway_mask =
766
13.7k
        SetBits<uint_type, 0, throwaway_mask_bits>::get;
767
768
13.7k
    *carry_bit = false;
769
13.7k
    other_uint_type out_val = 0;
770
13.7k
    uint_type significand = getNormalizedSignificand();
771
    // If we are up-casting, then we just have to shift to the right location.
772
13.7k
    if (num_throwaway_bits <= 0) {
773
0
      out_val = static_cast<other_uint_type>(significand);
774
0
      uint_type shift_amount = static_cast<uint_type>(-num_throwaway_bits);
775
0
      out_val = static_cast<other_uint_type>(out_val << shift_amount);
776
0
      return out_val;
777
0
    }
778
779
    // If every non-representable bit is 0, then we don't have any casting to
780
    // do.
781
13.7k
    if ((significand & throwaway_mask) == 0) {
782
7.13k
      return static_cast<other_uint_type>(
783
7.13k
          negatable_right_shift<num_throwaway_bits>::val(significand));
784
7.13k
    }
785
786
6.60k
    bool round_away_from_zero = false;
787
    // We actually have to narrow the significand here, so we have to follow the
788
    // rounding rules.
789
6.60k
    switch (dir) {
790
6.60k
      case round_direction::kToZero:
791
6.60k
        break;
792
0
      case round_direction::kToPositiveInfinity:
793
0
        round_away_from_zero = !isNegative();
794
0
        break;
795
0
      case round_direction::kToNegativeInfinity:
796
0
        round_away_from_zero = isNegative();
797
0
        break;
798
0
      case round_direction::kToNearestEven:
799
        // Have to round down, round bit is 0
800
0
        if ((first_rounded_bit & significand) == 0) {
801
0
          break;
802
0
        }
803
0
        if (((significand & throwaway_mask) & ~first_rounded_bit) != 0) {
804
          // If any subsequent bit of the rounded portion is non-0 then we round
805
          // up.
806
0
          round_away_from_zero = true;
807
0
          break;
808
0
        }
809
        // We are exactly half-way between 2 numbers, pick even.
810
0
        if ((significand & last_significant_bit) != 0) {
811
          // 1 for our last bit, round up.
812
0
          round_away_from_zero = true;
813
0
          break;
814
0
        }
815
0
        break;
816
6.60k
    }
817
818
6.60k
    if (round_away_from_zero) {
819
0
      return static_cast<other_uint_type>(
820
0
          negatable_right_shift<num_throwaway_bits>::val(incrementSignificand(
821
0
              significand, last_significant_bit, carry_bit)));
822
6.60k
    } else {
823
6.60k
      return static_cast<other_uint_type>(
824
6.60k
          negatable_right_shift<num_throwaway_bits>::val(significand));
825
6.60k
    }
826
6.60k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >::uint_type spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::getRoundedNormalizedSignificand<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > > >(spvtools::utils::round_direction, bool*)
Line
Count
Source
748
14.5k
      round_direction dir, bool* carry_bit) {
749
14.5k
    using other_uint_type = typename other_T::uint_type;
750
14.5k
    static const int_type num_throwaway_bits =
751
14.5k
        static_cast<int_type>(num_fraction_bits) -
752
14.5k
        static_cast<int_type>(other_T::num_fraction_bits);
753
754
14.5k
    static const uint_type last_significant_bit =
755
14.5k
        (num_throwaway_bits < 0)
756
14.5k
            ? 0
757
14.5k
            : negatable_left_shift<num_throwaway_bits>::val(1u);
758
14.5k
    static const uint_type first_rounded_bit =
759
14.5k
        (num_throwaway_bits < 1)
760
14.5k
            ? 0
761
14.5k
            : negatable_left_shift<num_throwaway_bits - 1>::val(1u);
762
763
14.5k
    static const uint_type throwaway_mask_bits =
764
14.5k
        num_throwaway_bits > 0 ? num_throwaway_bits : 0;
765
14.5k
    static const uint_type throwaway_mask =
766
14.5k
        SetBits<uint_type, 0, throwaway_mask_bits>::get;
767
768
14.5k
    *carry_bit = false;
769
14.5k
    other_uint_type out_val = 0;
770
14.5k
    uint_type significand = getNormalizedSignificand();
771
    // If we are up-casting, then we just have to shift to the right location.
772
14.5k
    if (num_throwaway_bits <= 0) {
773
0
      out_val = static_cast<other_uint_type>(significand);
774
0
      uint_type shift_amount = static_cast<uint_type>(-num_throwaway_bits);
775
0
      out_val = static_cast<other_uint_type>(out_val << shift_amount);
776
0
      return out_val;
777
0
    }
778
779
    // If every non-representable bit is 0, then we don't have any casting to
780
    // do.
781
14.5k
    if ((significand & throwaway_mask) == 0) {
782
5.25k
      return static_cast<other_uint_type>(
783
5.25k
          negatable_right_shift<num_throwaway_bits>::val(significand));
784
5.25k
    }
785
786
9.27k
    bool round_away_from_zero = false;
787
    // We actually have to narrow the significand here, so we have to follow the
788
    // rounding rules.
789
9.27k
    switch (dir) {
790
9.27k
      case round_direction::kToZero:
791
9.27k
        break;
792
0
      case round_direction::kToPositiveInfinity:
793
0
        round_away_from_zero = !isNegative();
794
0
        break;
795
0
      case round_direction::kToNegativeInfinity:
796
0
        round_away_from_zero = isNegative();
797
0
        break;
798
0
      case round_direction::kToNearestEven:
799
        // Have to round down, round bit is 0
800
0
        if ((first_rounded_bit & significand) == 0) {
801
0
          break;
802
0
        }
803
0
        if (((significand & throwaway_mask) & ~first_rounded_bit) != 0) {
804
          // If any subsequent bit of the rounded portion is non-0 then we round
805
          // up.
806
0
          round_away_from_zero = true;
807
0
          break;
808
0
        }
809
        // We are exactly half-way between 2 numbers, pick even.
810
0
        if ((significand & last_significant_bit) != 0) {
811
          // 1 for our last bit, round up.
812
0
          round_away_from_zero = true;
813
0
          break;
814
0
        }
815
0
        break;
816
9.27k
    }
817
818
9.27k
    if (round_away_from_zero) {
819
0
      return static_cast<other_uint_type>(
820
0
          negatable_right_shift<num_throwaway_bits>::val(incrementSignificand(
821
0
              significand, last_significant_bit, carry_bit)));
822
9.27k
    } else {
823
9.27k
      return static_cast<other_uint_type>(
824
9.27k
          negatable_right_shift<num_throwaway_bits>::val(significand));
825
9.27k
    }
826
9.27k
  }
spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::uint_type spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::getRoundedNormalizedSignificand<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > > >(spvtools::utils::round_direction, bool*)
Line
Count
Source
748
1.07k
      round_direction dir, bool* carry_bit) {
749
1.07k
    using other_uint_type = typename other_T::uint_type;
750
1.07k
    static const int_type num_throwaway_bits =
751
1.07k
        static_cast<int_type>(num_fraction_bits) -
752
1.07k
        static_cast<int_type>(other_T::num_fraction_bits);
753
754
1.07k
    static const uint_type last_significant_bit =
755
1.07k
        (num_throwaway_bits < 0)
756
1.07k
            ? 0
757
1.07k
            : negatable_left_shift<num_throwaway_bits>::val(1u);
758
1.07k
    static const uint_type first_rounded_bit =
759
1.07k
        (num_throwaway_bits < 1)
760
1.07k
            ? 0
761
1.07k
            : negatable_left_shift<num_throwaway_bits - 1>::val(1u);
762
763
1.07k
    static const uint_type throwaway_mask_bits =
764
1.07k
        num_throwaway_bits > 0 ? num_throwaway_bits : 0;
765
1.07k
    static const uint_type throwaway_mask =
766
1.07k
        SetBits<uint_type, 0, throwaway_mask_bits>::get;
767
768
1.07k
    *carry_bit = false;
769
1.07k
    other_uint_type out_val = 0;
770
1.07k
    uint_type significand = getNormalizedSignificand();
771
    // If we are up-casting, then we just have to shift to the right location.
772
1.07k
    if (num_throwaway_bits <= 0) {
773
1.07k
      out_val = static_cast<other_uint_type>(significand);
774
1.07k
      uint_type shift_amount = static_cast<uint_type>(-num_throwaway_bits);
775
1.07k
      out_val = static_cast<other_uint_type>(out_val << shift_amount);
776
1.07k
      return out_val;
777
1.07k
    }
778
779
    // If every non-representable bit is 0, then we don't have any casting to
780
    // do.
781
0
    if ((significand & throwaway_mask) == 0) {
782
0
      return static_cast<other_uint_type>(
783
0
          negatable_right_shift<num_throwaway_bits>::val(significand));
784
0
    }
785
786
0
    bool round_away_from_zero = false;
787
    // We actually have to narrow the significand here, so we have to follow the
788
    // rounding rules.
789
0
    switch (dir) {
790
0
      case round_direction::kToZero:
791
0
        break;
792
0
      case round_direction::kToPositiveInfinity:
793
0
        round_away_from_zero = !isNegative();
794
0
        break;
795
0
      case round_direction::kToNegativeInfinity:
796
0
        round_away_from_zero = isNegative();
797
0
        break;
798
0
      case round_direction::kToNearestEven:
799
        // Have to round down, round bit is 0
800
0
        if ((first_rounded_bit & significand) == 0) {
801
0
          break;
802
0
        }
803
0
        if (((significand & throwaway_mask) & ~first_rounded_bit) != 0) {
804
          // If any subsequent bit of the rounded portion is non-0 then we round
805
          // up.
806
0
          round_away_from_zero = true;
807
0
          break;
808
0
        }
809
        // We are exactly half-way between 2 numbers, pick even.
810
0
        if ((significand & last_significant_bit) != 0) {
811
          // 1 for our last bit, round up.
812
0
          round_away_from_zero = true;
813
0
          break;
814
0
        }
815
0
        break;
816
0
    }
817
818
0
    if (round_away_from_zero) {
819
0
      return static_cast<other_uint_type>(
820
0
          negatable_right_shift<num_throwaway_bits>::val(incrementSignificand(
821
0
              significand, last_significant_bit, carry_bit)));
822
0
    } else {
823
0
      return static_cast<other_uint_type>(
824
0
          negatable_right_shift<num_throwaway_bits>::val(significand));
825
0
    }
826
0
  }
827
828
  // Casts this value to another HexFloat. If the cast is widening,
829
  // then round_dir is ignored. If the cast is narrowing, then
830
  // the result is rounded in the direction specified.
831
  // This number will retain Nan and Inf values.
832
  // It will also saturate to Inf if the number overflows, and
833
  // underflow to (0 or min depending on rounding) if the number underflows.
834
  template <typename other_T>
835
68.4k
  void castTo(other_T& other, round_direction round_dir) {
836
68.4k
    using other_traits = typename other_T::traits;
837
68.4k
    using other_underlyingtraits = typename other_traits::underlying_typetraits;
838
839
68.4k
    other = other_T(static_cast<typename other_T::native_type>(0));
840
68.4k
    bool negate = isNegative();
841
68.4k
    if (getUnsignedBits() == 0) {
842
16.2k
      if (negate) {
843
7.47k
        other.set_value(-other.value());
844
7.47k
      }
845
16.2k
      return;
846
16.2k
    }
847
52.1k
    uint_type significand = getSignificandBits();
848
52.1k
    bool carried = false;
849
52.1k
    typename other_T::uint_type rounded_significand =
850
52.1k
        getRoundedNormalizedSignificand<other_T>(round_dir, &carried);
851
852
52.1k
    int_type exponent = getUnbiasedExponent();
853
52.1k
    if (exponent == min_exponent) {
854
      // If we are denormal, normalize the exponent, so that we can encode
855
      // easily.
856
9.51k
      exponent = static_cast<int_type>(exponent + 1);
857
92.1k
      for (uint_type check_bit = first_exponent_bit >> 1; check_bit != 0;
858
92.1k
           check_bit = static_cast<uint_type>(check_bit >> 1)) {
859
92.1k
        exponent = static_cast<int_type>(exponent - 1);
860
92.1k
        if (check_bit & significand) break;
861
92.1k
      }
862
9.51k
    }
863
864
52.1k
    bool is_nan = T(getBits()).isNan();
865
52.1k
    bool is_inf =
866
52.1k
        !is_nan &&
867
51.9k
        ((exponent + carried) > static_cast<int_type>(other_T::exponent_bias) ||
868
50.5k
         T(getBits()).isInfinity());
869
870
    // If we are Nan or Inf we should pass that through.
871
52.1k
    if (is_inf) {
872
1.91k
      if (other_traits::has_infinity)
873
1.18k
        other.set_value(typename other_T::underlying_type(
874
1.18k
            static_cast<typename other_T::uint_type>(
875
1.18k
                (negate ? other_T::sign_mask : 0) | other_T::exponent_mask)));
876
734
      else  // if the type doesnt use infinity, set it to max value (E4M3)
877
734
        other.set_value(typename other_T::underlying_type(
878
734
            static_cast<typename other_T::uint_type>(
879
734
                (negate ? other_T::sign_mask : 0) |
880
734
                other_underlyingtraits::getBitsFromFloat(
881
734
                    other_underlyingtraits::max()))));
882
1.91k
      return;
883
1.91k
    }
884
50.2k
    if (is_nan) {
885
264
      typename other_T::uint_type shifted_significand;
886
264
      shifted_significand = static_cast<typename other_T::uint_type>(
887
264
          negatable_left_shift<
888
264
              static_cast<int_type>(other_T::num_fraction_bits) -
889
264
              static_cast<int_type>(num_fraction_bits)>::val(significand));
890
891
      // We are some sort of Nan. We try to keep the bit-pattern of the Nan
892
      // as close as possible. If we had to shift off bits so we are 0, then we
893
      // just set the last bit.
894
264
      other.set_value(typename other_T::underlying_type(
895
264
          static_cast<typename other_T::uint_type>(
896
264
              other_traits::NaN_pattern | (negate ? other_T::sign_mask : 0) |
897
264
              other_T::exponent_mask |
898
264
              (shifted_significand == 0 ? 0x1 : shifted_significand))));
899
264
      return;
900
264
    }
901
902
50.0k
    bool round_underflow_up =
903
50.0k
        isNegative() ? round_dir == round_direction::kToNegativeInfinity
904
50.0k
                     : round_dir == round_direction::kToPositiveInfinity;
905
50.0k
    using other_int_type = typename other_T::int_type;
906
    // setFromSignUnbiasedExponentAndNormalizedSignificand will
907
    // zero out any underflowing value (but retain the sign).
908
50.0k
    other.setFromSignUnbiasedExponentAndNormalizedSignificand(
909
50.0k
        negate, static_cast<other_int_type>(exponent), rounded_significand,
910
50.0k
        round_underflow_up);
911
50.0k
    return;
912
50.2k
  }
void spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::castTo<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > > >(spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >&, spvtools::utils::round_direction)
Line
Count
Source
835
17.3k
  void castTo(other_T& other, round_direction round_dir) {
836
17.3k
    using other_traits = typename other_T::traits;
837
17.3k
    using other_underlyingtraits = typename other_traits::underlying_typetraits;
838
839
17.3k
    other = other_T(static_cast<typename other_T::native_type>(0));
840
17.3k
    bool negate = isNegative();
841
17.3k
    if (getUnsignedBits() == 0) {
842
2.83k
      if (negate) {
843
1.55k
        other.set_value(-other.value());
844
1.55k
      }
845
2.83k
      return;
846
2.83k
    }
847
14.5k
    uint_type significand = getSignificandBits();
848
14.5k
    bool carried = false;
849
14.5k
    typename other_T::uint_type rounded_significand =
850
14.5k
        getRoundedNormalizedSignificand<other_T>(round_dir, &carried);
851
852
14.5k
    int_type exponent = getUnbiasedExponent();
853
14.5k
    if (exponent == min_exponent) {
854
      // If we are denormal, normalize the exponent, so that we can encode
855
      // easily.
856
3.51k
      exponent = static_cast<int_type>(exponent + 1);
857
22.4k
      for (uint_type check_bit = first_exponent_bit >> 1; check_bit != 0;
858
22.4k
           check_bit = static_cast<uint_type>(check_bit >> 1)) {
859
22.4k
        exponent = static_cast<int_type>(exponent - 1);
860
22.4k
        if (check_bit & significand) break;
861
22.4k
      }
862
3.51k
    }
863
864
14.5k
    bool is_nan = T(getBits()).isNan();
865
14.5k
    bool is_inf =
866
14.5k
        !is_nan &&
867
14.4k
        ((exponent + carried) > static_cast<int_type>(other_T::exponent_bias) ||
868
13.8k
         T(getBits()).isInfinity());
869
870
    // If we are Nan or Inf we should pass that through.
871
14.5k
    if (is_inf) {
872
592
      if (other_traits::has_infinity)
873
592
        other.set_value(typename other_T::underlying_type(
874
592
            static_cast<typename other_T::uint_type>(
875
592
                (negate ? other_T::sign_mask : 0) | other_T::exponent_mask)));
876
0
      else  // if the type doesnt use infinity, set it to max value (E4M3)
877
0
        other.set_value(typename other_T::underlying_type(
878
0
            static_cast<typename other_T::uint_type>(
879
0
                (negate ? other_T::sign_mask : 0) |
880
0
                other_underlyingtraits::getBitsFromFloat(
881
0
                    other_underlyingtraits::max()))));
882
592
      return;
883
592
    }
884
13.9k
    if (is_nan) {
885
132
      typename other_T::uint_type shifted_significand;
886
132
      shifted_significand = static_cast<typename other_T::uint_type>(
887
132
          negatable_left_shift<
888
132
              static_cast<int_type>(other_T::num_fraction_bits) -
889
132
              static_cast<int_type>(num_fraction_bits)>::val(significand));
890
891
      // We are some sort of Nan. We try to keep the bit-pattern of the Nan
892
      // as close as possible. If we had to shift off bits so we are 0, then we
893
      // just set the last bit.
894
132
      other.set_value(typename other_T::underlying_type(
895
132
          static_cast<typename other_T::uint_type>(
896
132
              other_traits::NaN_pattern | (negate ? other_T::sign_mask : 0) |
897
132
              other_T::exponent_mask |
898
132
              (shifted_significand == 0 ? 0x1 : shifted_significand))));
899
132
      return;
900
132
    }
901
902
13.8k
    bool round_underflow_up =
903
13.8k
        isNegative() ? round_dir == round_direction::kToNegativeInfinity
904
13.8k
                     : round_dir == round_direction::kToPositiveInfinity;
905
13.8k
    using other_int_type = typename other_T::int_type;
906
    // setFromSignUnbiasedExponentAndNormalizedSignificand will
907
    // zero out any underflowing value (but retain the sign).
908
13.8k
    other.setFromSignUnbiasedExponentAndNormalizedSignificand(
909
13.8k
        negate, static_cast<other_int_type>(exponent), rounded_significand,
910
13.8k
        round_underflow_up);
911
13.8k
    return;
912
13.9k
  }
void spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::castTo<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > > >(spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >&, spvtools::utils::round_direction)
Line
Count
Source
835
13.1k
  void castTo(other_T& other, round_direction round_dir) {
836
13.1k
    using other_traits = typename other_T::traits;
837
13.1k
    using other_underlyingtraits = typename other_traits::underlying_typetraits;
838
839
13.1k
    other = other_T(static_cast<typename other_T::native_type>(0));
840
13.1k
    bool negate = isNegative();
841
13.1k
    if (getUnsignedBits() == 0) {
842
4.83k
      if (negate) {
843
2.57k
        other.set_value(-other.value());
844
2.57k
      }
845
4.83k
      return;
846
4.83k
    }
847
8.31k
    uint_type significand = getSignificandBits();
848
8.31k
    bool carried = false;
849
8.31k
    typename other_T::uint_type rounded_significand =
850
8.31k
        getRoundedNormalizedSignificand<other_T>(round_dir, &carried);
851
852
8.31k
    int_type exponent = getUnbiasedExponent();
853
8.31k
    if (exponent == min_exponent) {
854
      // If we are denormal, normalize the exponent, so that we can encode
855
      // easily.
856
2.89k
      exponent = static_cast<int_type>(exponent + 1);
857
40.0k
      for (uint_type check_bit = first_exponent_bit >> 1; check_bit != 0;
858
40.0k
           check_bit = static_cast<uint_type>(check_bit >> 1)) {
859
40.0k
        exponent = static_cast<int_type>(exponent - 1);
860
40.0k
        if (check_bit & significand) break;
861
40.0k
      }
862
2.89k
    }
863
864
8.31k
    bool is_nan = T(getBits()).isNan();
865
8.31k
    bool is_inf =
866
8.31k
        !is_nan &&
867
8.31k
        ((exponent + carried) > static_cast<int_type>(other_T::exponent_bias) ||
868
8.31k
         T(getBits()).isInfinity());
869
870
    // If we are Nan or Inf we should pass that through.
871
8.31k
    if (is_inf) {
872
0
      if (other_traits::has_infinity)
873
0
        other.set_value(typename other_T::underlying_type(
874
0
            static_cast<typename other_T::uint_type>(
875
0
                (negate ? other_T::sign_mask : 0) | other_T::exponent_mask)));
876
0
      else  // if the type doesnt use infinity, set it to max value (E4M3)
877
0
        other.set_value(typename other_T::underlying_type(
878
0
            static_cast<typename other_T::uint_type>(
879
0
                (negate ? other_T::sign_mask : 0) |
880
0
                other_underlyingtraits::getBitsFromFloat(
881
0
                    other_underlyingtraits::max()))));
882
0
      return;
883
0
    }
884
8.31k
    if (is_nan) {
885
0
      typename other_T::uint_type shifted_significand;
886
0
      shifted_significand = static_cast<typename other_T::uint_type>(
887
0
          negatable_left_shift<
888
0
              static_cast<int_type>(other_T::num_fraction_bits) -
889
0
              static_cast<int_type>(num_fraction_bits)>::val(significand));
890
891
      // We are some sort of Nan. We try to keep the bit-pattern of the Nan
892
      // as close as possible. If we had to shift off bits so we are 0, then we
893
      // just set the last bit.
894
0
      other.set_value(typename other_T::underlying_type(
895
0
          static_cast<typename other_T::uint_type>(
896
0
              other_traits::NaN_pattern | (negate ? other_T::sign_mask : 0) |
897
0
              other_T::exponent_mask |
898
0
              (shifted_significand == 0 ? 0x1 : shifted_significand))));
899
0
      return;
900
0
    }
901
902
8.31k
    bool round_underflow_up =
903
8.31k
        isNegative() ? round_dir == round_direction::kToNegativeInfinity
904
8.31k
                     : round_dir == round_direction::kToPositiveInfinity;
905
8.31k
    using other_int_type = typename other_T::int_type;
906
    // setFromSignUnbiasedExponentAndNormalizedSignificand will
907
    // zero out any underflowing value (but retain the sign).
908
8.31k
    other.setFromSignUnbiasedExponentAndNormalizedSignificand(
909
8.31k
        negate, static_cast<other_int_type>(exponent), rounded_significand,
910
8.31k
        round_underflow_up);
911
8.31k
    return;
912
8.31k
  }
void spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::castTo<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > > >(spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > >&, spvtools::utils::round_direction)
Line
Count
Source
835
18.5k
  void castTo(other_T& other, round_direction round_dir) {
836
18.5k
    using other_traits = typename other_T::traits;
837
18.5k
    using other_underlyingtraits = typename other_traits::underlying_typetraits;
838
839
18.5k
    other = other_T(static_cast<typename other_T::native_type>(0));
840
18.5k
    bool negate = isNegative();
841
18.5k
    if (getUnsignedBits() == 0) {
842
4.84k
      if (negate) {
843
1.98k
        other.set_value(-other.value());
844
1.98k
      }
845
4.84k
      return;
846
4.84k
    }
847
13.7k
    uint_type significand = getSignificandBits();
848
13.7k
    bool carried = false;
849
13.7k
    typename other_T::uint_type rounded_significand =
850
13.7k
        getRoundedNormalizedSignificand<other_T>(round_dir, &carried);
851
852
13.7k
    int_type exponent = getUnbiasedExponent();
853
13.7k
    if (exponent == min_exponent) {
854
      // If we are denormal, normalize the exponent, so that we can encode
855
      // easily.
856
1.16k
      exponent = static_cast<int_type>(exponent + 1);
857
16.1k
      for (uint_type check_bit = first_exponent_bit >> 1; check_bit != 0;
858
16.1k
           check_bit = static_cast<uint_type>(check_bit >> 1)) {
859
16.1k
        exponent = static_cast<int_type>(exponent - 1);
860
16.1k
        if (check_bit & significand) break;
861
16.1k
      }
862
1.16k
    }
863
864
13.7k
    bool is_nan = T(getBits()).isNan();
865
13.7k
    bool is_inf =
866
13.7k
        !is_nan &&
867
13.7k
        ((exponent + carried) > static_cast<int_type>(other_T::exponent_bias) ||
868
12.9k
         T(getBits()).isInfinity());
869
870
    // If we are Nan or Inf we should pass that through.
871
13.7k
    if (is_inf) {
872
734
      if (other_traits::has_infinity)
873
0
        other.set_value(typename other_T::underlying_type(
874
0
            static_cast<typename other_T::uint_type>(
875
0
                (negate ? other_T::sign_mask : 0) | other_T::exponent_mask)));
876
734
      else  // if the type doesnt use infinity, set it to max value (E4M3)
877
734
        other.set_value(typename other_T::underlying_type(
878
734
            static_cast<typename other_T::uint_type>(
879
734
                (negate ? other_T::sign_mask : 0) |
880
734
                other_underlyingtraits::getBitsFromFloat(
881
734
                    other_underlyingtraits::max()))));
882
734
      return;
883
734
    }
884
12.9k
    if (is_nan) {
885
0
      typename other_T::uint_type shifted_significand;
886
0
      shifted_significand = static_cast<typename other_T::uint_type>(
887
0
          negatable_left_shift<
888
0
              static_cast<int_type>(other_T::num_fraction_bits) -
889
0
              static_cast<int_type>(num_fraction_bits)>::val(significand));
890
891
      // We are some sort of Nan. We try to keep the bit-pattern of the Nan
892
      // as close as possible. If we had to shift off bits so we are 0, then we
893
      // just set the last bit.
894
0
      other.set_value(typename other_T::underlying_type(
895
0
          static_cast<typename other_T::uint_type>(
896
0
              other_traits::NaN_pattern | (negate ? other_T::sign_mask : 0) |
897
0
              other_T::exponent_mask |
898
0
              (shifted_significand == 0 ? 0x1 : shifted_significand))));
899
0
      return;
900
0
    }
901
902
12.9k
    bool round_underflow_up =
903
12.9k
        isNegative() ? round_dir == round_direction::kToNegativeInfinity
904
12.9k
                     : round_dir == round_direction::kToPositiveInfinity;
905
12.9k
    using other_int_type = typename other_T::int_type;
906
    // setFromSignUnbiasedExponentAndNormalizedSignificand will
907
    // zero out any underflowing value (but retain the sign).
908
12.9k
    other.setFromSignUnbiasedExponentAndNormalizedSignificand(
909
12.9k
        negate, static_cast<other_int_type>(exponent), rounded_significand,
910
12.9k
        round_underflow_up);
911
12.9k
    return;
912
12.9k
  }
void spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >::castTo<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > > >(spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >&, spvtools::utils::round_direction)
Line
Count
Source
835
17.5k
  void castTo(other_T& other, round_direction round_dir) {
836
17.5k
    using other_traits = typename other_T::traits;
837
17.5k
    using other_underlyingtraits = typename other_traits::underlying_typetraits;
838
839
17.5k
    other = other_T(static_cast<typename other_T::native_type>(0));
840
17.5k
    bool negate = isNegative();
841
17.5k
    if (getUnsignedBits() == 0) {
842
3.00k
      if (negate) {
843
1.19k
        other.set_value(-other.value());
844
1.19k
      }
845
3.00k
      return;
846
3.00k
    }
847
14.5k
    uint_type significand = getSignificandBits();
848
14.5k
    bool carried = false;
849
14.5k
    typename other_T::uint_type rounded_significand =
850
14.5k
        getRoundedNormalizedSignificand<other_T>(round_dir, &carried);
851
852
14.5k
    int_type exponent = getUnbiasedExponent();
853
14.5k
    if (exponent == min_exponent) {
854
      // If we are denormal, normalize the exponent, so that we can encode
855
      // easily.
856
1.71k
      exponent = static_cast<int_type>(exponent + 1);
857
12.5k
      for (uint_type check_bit = first_exponent_bit >> 1; check_bit != 0;
858
12.5k
           check_bit = static_cast<uint_type>(check_bit >> 1)) {
859
12.5k
        exponent = static_cast<int_type>(exponent - 1);
860
12.5k
        if (check_bit & significand) break;
861
12.5k
      }
862
1.71k
    }
863
864
14.5k
    bool is_nan = T(getBits()).isNan();
865
14.5k
    bool is_inf =
866
14.5k
        !is_nan &&
867
14.5k
        ((exponent + carried) > static_cast<int_type>(other_T::exponent_bias) ||
868
14.5k
         T(getBits()).isInfinity());
869
870
    // If we are Nan or Inf we should pass that through.
871
14.5k
    if (is_inf) {
872
28
      if (other_traits::has_infinity)
873
28
        other.set_value(typename other_T::underlying_type(
874
28
            static_cast<typename other_T::uint_type>(
875
28
                (negate ? other_T::sign_mask : 0) | other_T::exponent_mask)));
876
0
      else  // if the type doesnt use infinity, set it to max value (E4M3)
877
0
        other.set_value(typename other_T::underlying_type(
878
0
            static_cast<typename other_T::uint_type>(
879
0
                (negate ? other_T::sign_mask : 0) |
880
0
                other_underlyingtraits::getBitsFromFloat(
881
0
                    other_underlyingtraits::max()))));
882
28
      return;
883
28
    }
884
14.5k
    if (is_nan) {
885
0
      typename other_T::uint_type shifted_significand;
886
0
      shifted_significand = static_cast<typename other_T::uint_type>(
887
0
          negatable_left_shift<
888
0
              static_cast<int_type>(other_T::num_fraction_bits) -
889
0
              static_cast<int_type>(num_fraction_bits)>::val(significand));
890
891
      // We are some sort of Nan. We try to keep the bit-pattern of the Nan
892
      // as close as possible. If we had to shift off bits so we are 0, then we
893
      // just set the last bit.
894
0
      other.set_value(typename other_T::underlying_type(
895
0
          static_cast<typename other_T::uint_type>(
896
0
              other_traits::NaN_pattern | (negate ? other_T::sign_mask : 0) |
897
0
              other_T::exponent_mask |
898
0
              (shifted_significand == 0 ? 0x1 : shifted_significand))));
899
0
      return;
900
0
    }
901
902
14.5k
    bool round_underflow_up =
903
14.5k
        isNegative() ? round_dir == round_direction::kToNegativeInfinity
904
14.5k
                     : round_dir == round_direction::kToPositiveInfinity;
905
14.5k
    using other_int_type = typename other_T::int_type;
906
    // setFromSignUnbiasedExponentAndNormalizedSignificand will
907
    // zero out any underflowing value (but retain the sign).
908
14.5k
    other.setFromSignUnbiasedExponentAndNormalizedSignificand(
909
14.5k
        negate, static_cast<other_int_type>(exponent), rounded_significand,
910
14.5k
        round_underflow_up);
911
14.5k
    return;
912
14.5k
  }
void spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >::castTo<spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > > >(spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >&, spvtools::utils::round_direction)
Line
Count
Source
835
1.79k
  void castTo(other_T& other, round_direction round_dir) {
836
1.79k
    using other_traits = typename other_T::traits;
837
1.79k
    using other_underlyingtraits = typename other_traits::underlying_typetraits;
838
839
1.79k
    other = other_T(static_cast<typename other_T::native_type>(0));
840
1.79k
    bool negate = isNegative();
841
1.79k
    if (getUnsignedBits() == 0) {
842
711
      if (negate) {
843
179
        other.set_value(-other.value());
844
179
      }
845
711
      return;
846
711
    }
847
1.07k
    uint_type significand = getSignificandBits();
848
1.07k
    bool carried = false;
849
1.07k
    typename other_T::uint_type rounded_significand =
850
1.07k
        getRoundedNormalizedSignificand<other_T>(round_dir, &carried);
851
852
1.07k
    int_type exponent = getUnbiasedExponent();
853
1.07k
    if (exponent == min_exponent) {
854
      // If we are denormal, normalize the exponent, so that we can encode
855
      // easily.
856
225
      exponent = static_cast<int_type>(exponent + 1);
857
871
      for (uint_type check_bit = first_exponent_bit >> 1; check_bit != 0;
858
871
           check_bit = static_cast<uint_type>(check_bit >> 1)) {
859
871
        exponent = static_cast<int_type>(exponent - 1);
860
871
        if (check_bit & significand) break;
861
871
      }
862
225
    }
863
864
1.07k
    bool is_nan = T(getBits()).isNan();
865
1.07k
    bool is_inf =
866
1.07k
        !is_nan &&
867
947
        ((exponent + carried) > static_cast<int_type>(other_T::exponent_bias) ||
868
947
         T(getBits()).isInfinity());
869
870
    // If we are Nan or Inf we should pass that through.
871
1.07k
    if (is_inf) {
872
564
      if (other_traits::has_infinity)
873
564
        other.set_value(typename other_T::underlying_type(
874
564
            static_cast<typename other_T::uint_type>(
875
564
                (negate ? other_T::sign_mask : 0) | other_T::exponent_mask)));
876
0
      else  // if the type doesnt use infinity, set it to max value (E4M3)
877
0
        other.set_value(typename other_T::underlying_type(
878
0
            static_cast<typename other_T::uint_type>(
879
0
                (negate ? other_T::sign_mask : 0) |
880
0
                other_underlyingtraits::getBitsFromFloat(
881
0
                    other_underlyingtraits::max()))));
882
564
      return;
883
564
    }
884
515
    if (is_nan) {
885
132
      typename other_T::uint_type shifted_significand;
886
132
      shifted_significand = static_cast<typename other_T::uint_type>(
887
132
          negatable_left_shift<
888
132
              static_cast<int_type>(other_T::num_fraction_bits) -
889
132
              static_cast<int_type>(num_fraction_bits)>::val(significand));
890
891
      // We are some sort of Nan. We try to keep the bit-pattern of the Nan
892
      // as close as possible. If we had to shift off bits so we are 0, then we
893
      // just set the last bit.
894
132
      other.set_value(typename other_T::underlying_type(
895
132
          static_cast<typename other_T::uint_type>(
896
132
              other_traits::NaN_pattern | (negate ? other_T::sign_mask : 0) |
897
132
              other_T::exponent_mask |
898
132
              (shifted_significand == 0 ? 0x1 : shifted_significand))));
899
132
      return;
900
132
    }
901
902
383
    bool round_underflow_up =
903
383
        isNegative() ? round_dir == round_direction::kToNegativeInfinity
904
383
                     : round_dir == round_direction::kToPositiveInfinity;
905
383
    using other_int_type = typename other_T::int_type;
906
    // setFromSignUnbiasedExponentAndNormalizedSignificand will
907
    // zero out any underflowing value (but retain the sign).
908
383
    other.setFromSignUnbiasedExponentAndNormalizedSignificand(
909
383
        negate, static_cast<other_int_type>(exponent), rounded_significand,
910
383
        round_underflow_up);
911
383
    return;
912
515
  }
913
914
 private:
915
  T value_;
916
917
  static_assert(num_used_bits ==
918
                    Traits::num_exponent_bits + Traits::num_fraction_bits + 1,
919
                "The number of bits do not fit");
920
  static_assert(sizeof(T) == sizeof(uint_type), "The type sizes do not match");
921
};
922
923
// Returns 4 bits represented by the hex character.
924
46.9M
inline uint8_t get_nibble_from_character(int character) {
925
46.9M
  const char* dec = "0123456789";
926
46.9M
  const char* lower = "abcdef";
927
46.9M
  const char* upper = "ABCDEF";
928
46.9M
  const char* p = nullptr;
929
46.9M
  if ((p = strchr(dec, character))) {
930
39.8M
    return static_cast<uint8_t>(p - dec);
931
39.8M
  } else if ((p = strchr(lower, character))) {
932
5.63M
    return static_cast<uint8_t>(p - lower + 0xa);
933
5.63M
  } else if ((p = strchr(upper, character))) {
934
1.46M
    return static_cast<uint8_t>(p - upper + 0xa);
935
1.46M
  }
936
937
46.9M
  assert(false && "This was called with a non-hex character");
938
0
  return 0;
939
0
}
940
941
// Outputs the given HexFloat to the stream.
942
template <typename T, typename Traits>
943
511k
std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
944
511k
  using HF = HexFloat<T, Traits>;
945
511k
  using uint_type = uint64_t;
946
511k
  using int_type = int64_t;
947
948
511k
  static_assert(HF::num_used_bits != 0,
949
511k
                "num_used_bits must be non-zero for a valid float");
950
511k
  static_assert(HF::num_exponent_bits != 0,
951
511k
                "num_exponent_bits must be non-zero for a valid float");
952
511k
  static_assert(HF::num_fraction_bits != 0,
953
511k
                "num_fractin_bits must be non-zero for a valid float");
954
955
511k
  const uint_type bits = value.value().data();
956
511k
  const char* const sign = (bits & HF::sign_mask) ? "-" : "";
957
511k
  const uint_type exponent = static_cast<uint_type>(
958
511k
      (bits & HF::exponent_mask) >> HF::num_fraction_bits);
959
960
511k
  uint_type fraction = static_cast<uint_type>((bits & HF::fraction_encode_mask)
961
511k
                                              << HF::num_overflow_bits);
962
963
511k
  const bool is_zero = exponent == 0 && fraction == 0;
964
511k
  const bool is_denorm = exponent == 0 && !is_zero;
965
966
  // exponent contains the biased exponent we have to convert it back into
967
  // the normal range.
968
511k
  int_type int_exponent = static_cast<int_type>(exponent - HF::exponent_bias);
969
  // If the number is all zeros, then we actually have to NOT shift the
970
  // exponent.
971
511k
  int_exponent = is_zero ? 0 : int_exponent;
972
973
  // If we are denorm, then start shifting, and decreasing the exponent until
974
  // our leading bit is 1.
975
976
511k
  if (is_denorm) {
977
1.98M
    while ((fraction & HF::fraction_top_bit) == 0) {
978
1.74M
      fraction = static_cast<uint_type>(fraction << 1);
979
1.74M
      int_exponent = static_cast<int_type>(int_exponent - 1);
980
1.74M
    }
981
    // Since this is denormalized, we have to consume the leading 1 since it
982
    // will end up being implicit.
983
242k
    fraction = static_cast<uint_type>(fraction << 1);  // eat the leading 1
984
242k
    fraction &= HF::fraction_represent_mask;
985
242k
  }
986
987
511k
  uint_type fraction_nibbles = HF::fraction_nibbles;
988
  // We do not have to display any trailing 0s, since this represents the
989
  // fractional part.
990
1.32M
  while (fraction_nibbles > 0 && (fraction & 0xF) == 0) {
991
    // Shift off any trailing values;
992
812k
    fraction = static_cast<uint_type>(fraction >> 4);
993
812k
    --fraction_nibbles;
994
812k
  }
995
996
511k
  const auto saved_flags = os.flags();
997
511k
  const auto saved_fill = os.fill();
998
999
511k
  os << sign << "0x" << (is_zero ? '0' : '1');
1000
511k
  if (fraction_nibbles) {
1001
    // Make sure to keep the leading 0s in place, since this is the fractional
1002
    // part.
1003
404k
    os << "." << std::setw(static_cast<int>(fraction_nibbles))
1004
404k
       << std::setfill('0') << std::hex << fraction;
1005
404k
  }
1006
511k
  os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
1007
1008
511k
  os.flags(saved_flags);
1009
511k
  os.fill(saved_fill);
1010
1011
511k
  return os;
1012
511k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& spvtools::utils::operator<< <spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > > const&)
Line
Count
Source
943
124k
std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
944
124k
  using HF = HexFloat<T, Traits>;
945
124k
  using uint_type = uint64_t;
946
124k
  using int_type = int64_t;
947
948
124k
  static_assert(HF::num_used_bits != 0,
949
124k
                "num_used_bits must be non-zero for a valid float");
950
124k
  static_assert(HF::num_exponent_bits != 0,
951
124k
                "num_exponent_bits must be non-zero for a valid float");
952
124k
  static_assert(HF::num_fraction_bits != 0,
953
124k
                "num_fractin_bits must be non-zero for a valid float");
954
955
124k
  const uint_type bits = value.value().data();
956
124k
  const char* const sign = (bits & HF::sign_mask) ? "-" : "";
957
124k
  const uint_type exponent = static_cast<uint_type>(
958
124k
      (bits & HF::exponent_mask) >> HF::num_fraction_bits);
959
960
124k
  uint_type fraction = static_cast<uint_type>((bits & HF::fraction_encode_mask)
961
124k
                                              << HF::num_overflow_bits);
962
963
124k
  const bool is_zero = exponent == 0 && fraction == 0;
964
124k
  const bool is_denorm = exponent == 0 && !is_zero;
965
966
  // exponent contains the biased exponent we have to convert it back into
967
  // the normal range.
968
124k
  int_type int_exponent = static_cast<int_type>(exponent - HF::exponent_bias);
969
  // If the number is all zeros, then we actually have to NOT shift the
970
  // exponent.
971
124k
  int_exponent = is_zero ? 0 : int_exponent;
972
973
  // If we are denorm, then start shifting, and decreasing the exponent until
974
  // our leading bit is 1.
975
976
124k
  if (is_denorm) {
977
307k
    while ((fraction & HF::fraction_top_bit) == 0) {
978
233k
      fraction = static_cast<uint_type>(fraction << 1);
979
233k
      int_exponent = static_cast<int_type>(int_exponent - 1);
980
233k
    }
981
    // Since this is denormalized, we have to consume the leading 1 since it
982
    // will end up being implicit.
983
73.7k
    fraction = static_cast<uint_type>(fraction << 1);  // eat the leading 1
984
73.7k
    fraction &= HF::fraction_represent_mask;
985
73.7k
  }
986
987
124k
  uint_type fraction_nibbles = HF::fraction_nibbles;
988
  // We do not have to display any trailing 0s, since this represents the
989
  // fractional part.
990
312k
  while (fraction_nibbles > 0 && (fraction & 0xF) == 0) {
991
    // Shift off any trailing values;
992
187k
    fraction = static_cast<uint_type>(fraction >> 4);
993
187k
    --fraction_nibbles;
994
187k
  }
995
996
124k
  const auto saved_flags = os.flags();
997
124k
  const auto saved_fill = os.fill();
998
999
124k
  os << sign << "0x" << (is_zero ? '0' : '1');
1000
124k
  if (fraction_nibbles) {
1001
    // Make sure to keep the leading 0s in place, since this is the fractional
1002
    // part.
1003
93.7k
    os << "." << std::setw(static_cast<int>(fraction_nibbles))
1004
93.7k
       << std::setfill('0') << std::hex << fraction;
1005
93.7k
  }
1006
124k
  os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
1007
1008
124k
  os.flags(saved_flags);
1009
124k
  os.fill(saved_fill);
1010
1011
124k
  return os;
1012
124k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& spvtools::utils::operator<< <spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > > const&)
Line
Count
Source
943
94.4k
std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
944
94.4k
  using HF = HexFloat<T, Traits>;
945
94.4k
  using uint_type = uint64_t;
946
94.4k
  using int_type = int64_t;
947
948
94.4k
  static_assert(HF::num_used_bits != 0,
949
94.4k
                "num_used_bits must be non-zero for a valid float");
950
94.4k
  static_assert(HF::num_exponent_bits != 0,
951
94.4k
                "num_exponent_bits must be non-zero for a valid float");
952
94.4k
  static_assert(HF::num_fraction_bits != 0,
953
94.4k
                "num_fractin_bits must be non-zero for a valid float");
954
955
94.4k
  const uint_type bits = value.value().data();
956
94.4k
  const char* const sign = (bits & HF::sign_mask) ? "-" : "";
957
94.4k
  const uint_type exponent = static_cast<uint_type>(
958
94.4k
      (bits & HF::exponent_mask) >> HF::num_fraction_bits);
959
960
94.4k
  uint_type fraction = static_cast<uint_type>((bits & HF::fraction_encode_mask)
961
94.4k
                                              << HF::num_overflow_bits);
962
963
94.4k
  const bool is_zero = exponent == 0 && fraction == 0;
964
94.4k
  const bool is_denorm = exponent == 0 && !is_zero;
965
966
  // exponent contains the biased exponent we have to convert it back into
967
  // the normal range.
968
94.4k
  int_type int_exponent = static_cast<int_type>(exponent - HF::exponent_bias);
969
  // If the number is all zeros, then we actually have to NOT shift the
970
  // exponent.
971
94.4k
  int_exponent = is_zero ? 0 : int_exponent;
972
973
  // If we are denorm, then start shifting, and decreasing the exponent until
974
  // our leading bit is 1.
975
976
94.4k
  if (is_denorm) {
977
52.7k
    while ((fraction & HF::fraction_top_bit) == 0) {
978
28.1k
      fraction = static_cast<uint_type>(fraction << 1);
979
28.1k
      int_exponent = static_cast<int_type>(int_exponent - 1);
980
28.1k
    }
981
    // Since this is denormalized, we have to consume the leading 1 since it
982
    // will end up being implicit.
983
24.6k
    fraction = static_cast<uint_type>(fraction << 1);  // eat the leading 1
984
24.6k
    fraction &= HF::fraction_represent_mask;
985
24.6k
  }
986
987
94.4k
  uint_type fraction_nibbles = HF::fraction_nibbles;
988
  // We do not have to display any trailing 0s, since this represents the
989
  // fractional part.
990
155k
  while (fraction_nibbles > 0 && (fraction & 0xF) == 0) {
991
    // Shift off any trailing values;
992
61.1k
    fraction = static_cast<uint_type>(fraction >> 4);
993
61.1k
    --fraction_nibbles;
994
61.1k
  }
995
996
94.4k
  const auto saved_flags = os.flags();
997
94.4k
  const auto saved_fill = os.fill();
998
999
94.4k
  os << sign << "0x" << (is_zero ? '0' : '1');
1000
94.4k
  if (fraction_nibbles) {
1001
    // Make sure to keep the leading 0s in place, since this is the fractional
1002
    // part.
1003
71.5k
    os << "." << std::setw(static_cast<int>(fraction_nibbles))
1004
71.5k
       << std::setfill('0') << std::hex << fraction;
1005
71.5k
  }
1006
94.4k
  os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
1007
1008
94.4k
  os.flags(saved_flags);
1009
94.4k
  os.fill(saved_fill);
1010
1011
94.4k
  return os;
1012
94.4k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& spvtools::utils::operator<< <spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > > const&)
Line
Count
Source
943
77.7k
std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
944
77.7k
  using HF = HexFloat<T, Traits>;
945
77.7k
  using uint_type = uint64_t;
946
77.7k
  using int_type = int64_t;
947
948
77.7k
  static_assert(HF::num_used_bits != 0,
949
77.7k
                "num_used_bits must be non-zero for a valid float");
950
77.7k
  static_assert(HF::num_exponent_bits != 0,
951
77.7k
                "num_exponent_bits must be non-zero for a valid float");
952
77.7k
  static_assert(HF::num_fraction_bits != 0,
953
77.7k
                "num_fractin_bits must be non-zero for a valid float");
954
955
77.7k
  const uint_type bits = value.value().data();
956
77.7k
  const char* const sign = (bits & HF::sign_mask) ? "-" : "";
957
77.7k
  const uint_type exponent = static_cast<uint_type>(
958
77.7k
      (bits & HF::exponent_mask) >> HF::num_fraction_bits);
959
960
77.7k
  uint_type fraction = static_cast<uint_type>((bits & HF::fraction_encode_mask)
961
77.7k
                                              << HF::num_overflow_bits);
962
963
77.7k
  const bool is_zero = exponent == 0 && fraction == 0;
964
77.7k
  const bool is_denorm = exponent == 0 && !is_zero;
965
966
  // exponent contains the biased exponent we have to convert it back into
967
  // the normal range.
968
77.7k
  int_type int_exponent = static_cast<int_type>(exponent - HF::exponent_bias);
969
  // If the number is all zeros, then we actually have to NOT shift the
970
  // exponent.
971
77.7k
  int_exponent = is_zero ? 0 : int_exponent;
972
973
  // If we are denorm, then start shifting, and decreasing the exponent until
974
  // our leading bit is 1.
975
976
77.7k
  if (is_denorm) {
977
3.99k
    while ((fraction & HF::fraction_top_bit) == 0) {
978
1.81k
      fraction = static_cast<uint_type>(fraction << 1);
979
1.81k
      int_exponent = static_cast<int_type>(int_exponent - 1);
980
1.81k
    }
981
    // Since this is denormalized, we have to consume the leading 1 since it
982
    // will end up being implicit.
983
2.17k
    fraction = static_cast<uint_type>(fraction << 1);  // eat the leading 1
984
2.17k
    fraction &= HF::fraction_represent_mask;
985
2.17k
  }
986
987
77.7k
  uint_type fraction_nibbles = HF::fraction_nibbles;
988
  // We do not have to display any trailing 0s, since this represents the
989
  // fractional part.
990
100k
  while (fraction_nibbles > 0 && (fraction & 0xF) == 0) {
991
    // Shift off any trailing values;
992
22.7k
    fraction = static_cast<uint_type>(fraction >> 4);
993
22.7k
    --fraction_nibbles;
994
22.7k
  }
995
996
77.7k
  const auto saved_flags = os.flags();
997
77.7k
  const auto saved_fill = os.fill();
998
999
77.7k
  os << sign << "0x" << (is_zero ? '0' : '1');
1000
77.7k
  if (fraction_nibbles) {
1001
    // Make sure to keep the leading 0s in place, since this is the fractional
1002
    // part.
1003
54.9k
    os << "." << std::setw(static_cast<int>(fraction_nibbles))
1004
54.9k
       << std::setfill('0') << std::hex << fraction;
1005
54.9k
  }
1006
77.7k
  os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
1007
1008
77.7k
  os.flags(saved_flags);
1009
77.7k
  os.fill(saved_fill);
1010
1011
77.7k
  return os;
1012
77.7k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& spvtools::utils::operator<< <spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > > const&)
Line
Count
Source
943
58.6k
std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
944
58.6k
  using HF = HexFloat<T, Traits>;
945
58.6k
  using uint_type = uint64_t;
946
58.6k
  using int_type = int64_t;
947
948
58.6k
  static_assert(HF::num_used_bits != 0,
949
58.6k
                "num_used_bits must be non-zero for a valid float");
950
58.6k
  static_assert(HF::num_exponent_bits != 0,
951
58.6k
                "num_exponent_bits must be non-zero for a valid float");
952
58.6k
  static_assert(HF::num_fraction_bits != 0,
953
58.6k
                "num_fractin_bits must be non-zero for a valid float");
954
955
58.6k
  const uint_type bits = value.value().data();
956
58.6k
  const char* const sign = (bits & HF::sign_mask) ? "-" : "";
957
58.6k
  const uint_type exponent = static_cast<uint_type>(
958
58.6k
      (bits & HF::exponent_mask) >> HF::num_fraction_bits);
959
960
58.6k
  uint_type fraction = static_cast<uint_type>((bits & HF::fraction_encode_mask)
961
58.6k
                                              << HF::num_overflow_bits);
962
963
58.6k
  const bool is_zero = exponent == 0 && fraction == 0;
964
58.6k
  const bool is_denorm = exponent == 0 && !is_zero;
965
966
  // exponent contains the biased exponent we have to convert it back into
967
  // the normal range.
968
58.6k
  int_type int_exponent = static_cast<int_type>(exponent - HF::exponent_bias);
969
  // If the number is all zeros, then we actually have to NOT shift the
970
  // exponent.
971
58.6k
  int_exponent = is_zero ? 0 : int_exponent;
972
973
  // If we are denorm, then start shifting, and decreasing the exponent until
974
  // our leading bit is 1.
975
976
58.6k
  if (is_denorm) {
977
2.92k
    while ((fraction & HF::fraction_top_bit) == 0) {
978
719
      fraction = static_cast<uint_type>(fraction << 1);
979
719
      int_exponent = static_cast<int_type>(int_exponent - 1);
980
719
    }
981
    // Since this is denormalized, we have to consume the leading 1 since it
982
    // will end up being implicit.
983
2.20k
    fraction = static_cast<uint_type>(fraction << 1);  // eat the leading 1
984
2.20k
    fraction &= HF::fraction_represent_mask;
985
2.20k
  }
986
987
58.6k
  uint_type fraction_nibbles = HF::fraction_nibbles;
988
  // We do not have to display any trailing 0s, since this represents the
989
  // fractional part.
990
79.8k
  while (fraction_nibbles > 0 && (fraction & 0xF) == 0) {
991
    // Shift off any trailing values;
992
21.1k
    fraction = static_cast<uint_type>(fraction >> 4);
993
21.1k
    --fraction_nibbles;
994
21.1k
  }
995
996
58.6k
  const auto saved_flags = os.flags();
997
58.6k
  const auto saved_fill = os.fill();
998
999
58.6k
  os << sign << "0x" << (is_zero ? '0' : '1');
1000
58.6k
  if (fraction_nibbles) {
1001
    // Make sure to keep the leading 0s in place, since this is the fractional
1002
    // part.
1003
37.5k
    os << "." << std::setw(static_cast<int>(fraction_nibbles))
1004
37.5k
       << std::setfill('0') << std::hex << fraction;
1005
37.5k
  }
1006
58.6k
  os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
1007
1008
58.6k
  os.flags(saved_flags);
1009
58.6k
  os.fill(saved_fill);
1010
1011
58.6k
  return os;
1012
58.6k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& spvtools::utils::operator<< <spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > > const&)
Line
Count
Source
943
130k
std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
944
130k
  using HF = HexFloat<T, Traits>;
945
130k
  using uint_type = uint64_t;
946
130k
  using int_type = int64_t;
947
948
130k
  static_assert(HF::num_used_bits != 0,
949
130k
                "num_used_bits must be non-zero for a valid float");
950
130k
  static_assert(HF::num_exponent_bits != 0,
951
130k
                "num_exponent_bits must be non-zero for a valid float");
952
130k
  static_assert(HF::num_fraction_bits != 0,
953
130k
                "num_fractin_bits must be non-zero for a valid float");
954
955
130k
  const uint_type bits = value.value().data();
956
130k
  const char* const sign = (bits & HF::sign_mask) ? "-" : "";
957
130k
  const uint_type exponent = static_cast<uint_type>(
958
130k
      (bits & HF::exponent_mask) >> HF::num_fraction_bits);
959
960
130k
  uint_type fraction = static_cast<uint_type>((bits & HF::fraction_encode_mask)
961
130k
                                              << HF::num_overflow_bits);
962
963
130k
  const bool is_zero = exponent == 0 && fraction == 0;
964
130k
  const bool is_denorm = exponent == 0 && !is_zero;
965
966
  // exponent contains the biased exponent we have to convert it back into
967
  // the normal range.
968
130k
  int_type int_exponent = static_cast<int_type>(exponent - HF::exponent_bias);
969
  // If the number is all zeros, then we actually have to NOT shift the
970
  // exponent.
971
130k
  int_exponent = is_zero ? 0 : int_exponent;
972
973
  // If we are denorm, then start shifting, and decreasing the exponent until
974
  // our leading bit is 1.
975
976
130k
  if (is_denorm) {
977
1.44M
    while ((fraction & HF::fraction_top_bit) == 0) {
978
1.32M
      fraction = static_cast<uint_type>(fraction << 1);
979
1.32M
      int_exponent = static_cast<int_type>(int_exponent - 1);
980
1.32M
    }
981
    // Since this is denormalized, we have to consume the leading 1 since it
982
    // will end up being implicit.
983
124k
    fraction = static_cast<uint_type>(fraction << 1);  // eat the leading 1
984
124k
    fraction &= HF::fraction_represent_mask;
985
124k
  }
986
987
130k
  uint_type fraction_nibbles = HF::fraction_nibbles;
988
  // We do not have to display any trailing 0s, since this represents the
989
  // fractional part.
990
563k
  while (fraction_nibbles > 0 && (fraction & 0xF) == 0) {
991
    // Shift off any trailing values;
992
432k
    fraction = static_cast<uint_type>(fraction >> 4);
993
432k
    --fraction_nibbles;
994
432k
  }
995
996
130k
  const auto saved_flags = os.flags();
997
130k
  const auto saved_fill = os.fill();
998
999
130k
  os << sign << "0x" << (is_zero ? '0' : '1');
1000
130k
  if (fraction_nibbles) {
1001
    // Make sure to keep the leading 0s in place, since this is the fractional
1002
    // part.
1003
122k
    os << "." << std::setw(static_cast<int>(fraction_nibbles))
1004
122k
       << std::setfill('0') << std::hex << fraction;
1005
122k
  }
1006
130k
  os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
1007
1008
130k
  os.flags(saved_flags);
1009
130k
  os.fill(saved_fill);
1010
1011
130k
  return os;
1012
130k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& spvtools::utils::operator<< <spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > > const&)
Line
Count
Source
943
25.3k
std::ostream& operator<<(std::ostream& os, const HexFloat<T, Traits>& value) {
944
25.3k
  using HF = HexFloat<T, Traits>;
945
25.3k
  using uint_type = uint64_t;
946
25.3k
  using int_type = int64_t;
947
948
25.3k
  static_assert(HF::num_used_bits != 0,
949
25.3k
                "num_used_bits must be non-zero for a valid float");
950
25.3k
  static_assert(HF::num_exponent_bits != 0,
951
25.3k
                "num_exponent_bits must be non-zero for a valid float");
952
25.3k
  static_assert(HF::num_fraction_bits != 0,
953
25.3k
                "num_fractin_bits must be non-zero for a valid float");
954
955
25.3k
  const uint_type bits = value.value().data();
956
25.3k
  const char* const sign = (bits & HF::sign_mask) ? "-" : "";
957
25.3k
  const uint_type exponent = static_cast<uint_type>(
958
25.3k
      (bits & HF::exponent_mask) >> HF::num_fraction_bits);
959
960
25.3k
  uint_type fraction = static_cast<uint_type>((bits & HF::fraction_encode_mask)
961
25.3k
                                              << HF::num_overflow_bits);
962
963
25.3k
  const bool is_zero = exponent == 0 && fraction == 0;
964
25.3k
  const bool is_denorm = exponent == 0 && !is_zero;
965
966
  // exponent contains the biased exponent we have to convert it back into
967
  // the normal range.
968
25.3k
  int_type int_exponent = static_cast<int_type>(exponent - HF::exponent_bias);
969
  // If the number is all zeros, then we actually have to NOT shift the
970
  // exponent.
971
25.3k
  int_exponent = is_zero ? 0 : int_exponent;
972
973
  // If we are denorm, then start shifting, and decreasing the exponent until
974
  // our leading bit is 1.
975
976
25.3k
  if (is_denorm) {
977
170k
    while ((fraction & HF::fraction_top_bit) == 0) {
978
155k
      fraction = static_cast<uint_type>(fraction << 1);
979
155k
      int_exponent = static_cast<int_type>(int_exponent - 1);
980
155k
    }
981
    // Since this is denormalized, we have to consume the leading 1 since it
982
    // will end up being implicit.
983
15.0k
    fraction = static_cast<uint_type>(fraction << 1);  // eat the leading 1
984
15.0k
    fraction &= HF::fraction_represent_mask;
985
15.0k
  }
986
987
25.3k
  uint_type fraction_nibbles = HF::fraction_nibbles;
988
  // We do not have to display any trailing 0s, since this represents the
989
  // fractional part.
990
111k
  while (fraction_nibbles > 0 && (fraction & 0xF) == 0) {
991
    // Shift off any trailing values;
992
86.6k
    fraction = static_cast<uint_type>(fraction >> 4);
993
86.6k
    --fraction_nibbles;
994
86.6k
  }
995
996
25.3k
  const auto saved_flags = os.flags();
997
25.3k
  const auto saved_fill = os.fill();
998
999
25.3k
  os << sign << "0x" << (is_zero ? '0' : '1');
1000
25.3k
  if (fraction_nibbles) {
1001
    // Make sure to keep the leading 0s in place, since this is the fractional
1002
    // part.
1003
24.6k
    os << "." << std::setw(static_cast<int>(fraction_nibbles))
1004
24.6k
       << std::setfill('0') << std::hex << fraction;
1005
24.6k
  }
1006
25.3k
  os << "p" << std::dec << (int_exponent >= 0 ? "+" : "") << int_exponent;
1007
1008
25.3k
  os.flags(saved_flags);
1009
25.3k
  os.fill(saved_fill);
1010
1011
25.3k
  return os;
1012
25.3k
}
1013
1014
// Returns true if negate_value is true and the next character on the
1015
// input stream is a plus or minus sign.  In that case we also set the fail bit
1016
// on the stream and set the value to the zero value for its type.
1017
template <typename T, typename Traits>
1018
inline bool RejectParseDueToLeadingSign(std::istream& is, bool negate_value,
1019
80.9k
                                        HexFloat<T, Traits>& value) {
1020
80.9k
  if (negate_value) {
1021
25.1k
    auto next_char = is.peek();
1022
25.1k
    if (next_char == '-' || next_char == '+') {
1023
      // Fail the parse.  Emulate standard behaviour by setting the value to
1024
      // the zero value, and set the fail bit on the stream.
1025
26
      value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type{0});
1026
26
      is.setstate(std::ios_base::failbit);
1027
26
      return true;
1028
26
    }
1029
25.1k
  }
1030
80.8k
  return false;
1031
80.9k
}
bool spvtools::utils::RejectParseDueToLeadingSign<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, bool, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >&)
Line
Count
Source
1019
75.6k
                                        HexFloat<T, Traits>& value) {
1020
75.6k
  if (negate_value) {
1021
22.9k
    auto next_char = is.peek();
1022
22.9k
    if (next_char == '-' || next_char == '+') {
1023
      // Fail the parse.  Emulate standard behaviour by setting the value to
1024
      // the zero value, and set the fail bit on the stream.
1025
22
      value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type{0});
1026
22
      is.setstate(std::ios_base::failbit);
1027
22
      return true;
1028
22
    }
1029
22.9k
  }
1030
75.5k
  return false;
1031
75.6k
}
bool spvtools::utils::RejectParseDueToLeadingSign<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, bool, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >&)
Line
Count
Source
1019
5.30k
                                        HexFloat<T, Traits>& value) {
1020
5.30k
  if (negate_value) {
1021
2.27k
    auto next_char = is.peek();
1022
2.27k
    if (next_char == '-' || next_char == '+') {
1023
      // Fail the parse.  Emulate standard behaviour by setting the value to
1024
      // the zero value, and set the fail bit on the stream.
1025
4
      value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type{0});
1026
4
      is.setstate(std::ios_base::failbit);
1027
4
      return true;
1028
4
    }
1029
2.27k
  }
1030
5.29k
  return false;
1031
5.30k
}
1032
1033
// Parses a floating point number from the given stream and stores it into the
1034
// value parameter.
1035
// If negate_value is true then the number may not have a leading minus or
1036
// plus, and if it successfully parses, then the number is negated before
1037
// being stored into the value parameter.
1038
// If the value cannot be correctly parsed or overflows the target floating
1039
// point type, then set the fail bit on the stream.
1040
// TODO(dneto): Promise C++11 standard behavior in how the value is set in
1041
// the error case, but only after all target platforms implement it correctly.
1042
// In particular, the Microsoft C++ runtime appears to be out of spec.
1043
template <typename T, typename Traits>
1044
inline std::istream& ParseNormalFloat(std::istream& is, bool negate_value,
1045
80.9k
                                      HexFloat<T, Traits>& value) {
1046
80.9k
  if (RejectParseDueToLeadingSign(is, negate_value, value)) {
1047
26
    return is;
1048
26
  }
1049
80.8k
  T val;
1050
80.8k
  is >> val;
1051
80.8k
  if (negate_value) {
1052
25.1k
    val = -val;
1053
25.1k
  }
1054
80.8k
  value.set_value(val);
1055
  // In the failure case, map -0.0 to 0.0.
1056
80.8k
  if (is.fail() && value.getUnsignedBits() == 0u) {
1057
5.18k
    value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type{0});
1058
5.18k
  }
1059
80.8k
  if (val.isInfinity()) {
1060
    // Fail the parse.  Emulate standard behaviour by setting the value to
1061
    // the closest normal value, and set the fail bit on the stream.
1062
44
    value.set_value((value.isNegative() | negate_value) ? T::lowest()
1063
44
                                                        : T::max());
1064
44
    is.setstate(std::ios_base::failbit);
1065
44
  }
1066
80.8k
  return is;
1067
80.9k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::ParseNormalFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, bool, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >&)
Line
Count
Source
1045
75.6k
                                      HexFloat<T, Traits>& value) {
1046
75.6k
  if (RejectParseDueToLeadingSign(is, negate_value, value)) {
1047
22
    return is;
1048
22
  }
1049
75.5k
  T val;
1050
75.5k
  is >> val;
1051
75.5k
  if (negate_value) {
1052
22.8k
    val = -val;
1053
22.8k
  }
1054
75.5k
  value.set_value(val);
1055
  // In the failure case, map -0.0 to 0.0.
1056
75.5k
  if (is.fail() && value.getUnsignedBits() == 0u) {
1057
5.11k
    value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type{0});
1058
5.11k
  }
1059
75.5k
  if (val.isInfinity()) {
1060
    // Fail the parse.  Emulate standard behaviour by setting the value to
1061
    // the closest normal value, and set the fail bit on the stream.
1062
34
    value.set_value((value.isNegative() | negate_value) ? T::lowest()
1063
34
                                                        : T::max());
1064
34
    is.setstate(std::ios_base::failbit);
1065
34
  }
1066
75.5k
  return is;
1067
75.6k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::ParseNormalFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, bool, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >&)
Line
Count
Source
1045
5.30k
                                      HexFloat<T, Traits>& value) {
1046
5.30k
  if (RejectParseDueToLeadingSign(is, negate_value, value)) {
1047
4
    return is;
1048
4
  }
1049
5.29k
  T val;
1050
5.29k
  is >> val;
1051
5.29k
  if (negate_value) {
1052
2.26k
    val = -val;
1053
2.26k
  }
1054
5.29k
  value.set_value(val);
1055
  // In the failure case, map -0.0 to 0.0.
1056
5.29k
  if (is.fail() && value.getUnsignedBits() == 0u) {
1057
64
    value = HexFloat<T, Traits>(typename HexFloat<T, Traits>::uint_type{0});
1058
64
  }
1059
5.29k
  if (val.isInfinity()) {
1060
    // Fail the parse.  Emulate standard behaviour by setting the value to
1061
    // the closest normal value, and set the fail bit on the stream.
1062
10
    value.set_value((value.isNegative() | negate_value) ? T::lowest()
1063
10
                                                        : T::max());
1064
10
    is.setstate(std::ios_base::failbit);
1065
10
  }
1066
5.29k
  return is;
1067
5.30k
}
1068
1069
// Specialization of ParseNormalFloat for FloatProxy<Float16> values.
1070
// This will parse the float as it were a 32-bit floating point number,
1071
// and then round it down to fit into a Float16 value.
1072
// The number is rounded towards zero.
1073
// If negate_value is true then the number may not have a leading minus or
1074
// plus, and if it successfully parses, then the number is negated before
1075
// being stored into the value parameter.
1076
// If the value cannot be correctly parsed or overflows the target floating
1077
// point type, then set the fail bit on the stream.
1078
// TODO(dneto): Promise C++11 standard behavior in how the value is set in
1079
// the error case, but only after all target platforms implement it correctly.
1080
// In particular, the Microsoft C++ runtime appears to be out of spec.
1081
template <>
1082
inline std::istream&
1083
ParseNormalFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>(
1084
    std::istream& is, bool negate_value,
1085
15.5k
    HexFloat<FloatProxy<Float16>, HexFloatTraits<FloatProxy<Float16>>>& value) {
1086
  // First parse as a 32-bit float.
1087
15.5k
  HexFloat<FloatProxy<float>> float_val(0.0f);
1088
15.5k
  ParseNormalFloat(is, negate_value, float_val);
1089
1090
  // Then convert to 16-bit float, saturating at infinities, and
1091
  // rounding toward zero.
1092
15.5k
  float_val.castTo(value, round_direction::kToZero);
1093
1094
  // Overflow on 16-bit behaves the same as for 32- and 64-bit: set the
1095
  // fail bit and set the lowest or highest value.
1096
  // /!\ We get an error if there is no overflow but the value is infinity.
1097
  // Is it what we want?
1098
15.5k
  if (Float16::isInfinity(value.value().getAsFloat())) {
1099
28
    value.set_value(value.isNegative() ? Float16::lowest() : Float16::max());
1100
28
    is.setstate(std::ios_base::failbit);
1101
28
  }
1102
15.5k
  return is;
1103
15.5k
}
1104
1105
// Same flow as Float16
1106
template <>
1107
inline std::istream&
1108
ParseNormalFloat<FloatProxy<BFloat16>, HexFloatTraits<FloatProxy<BFloat16>>>(
1109
    std::istream& is, bool negate_value,
1110
    HexFloat<FloatProxy<BFloat16>, HexFloatTraits<FloatProxy<BFloat16>>>&
1111
13.1k
        value) {
1112
13.1k
  HexFloat<FloatProxy<float>> float_val(0.0f);
1113
13.1k
  ParseNormalFloat(is, negate_value, float_val);
1114
1115
13.1k
  float_val.castTo(value, round_direction::kToZero);
1116
1117
13.1k
  if (BFloat16::isInfinity(value.value().getAsFloat())) {
1118
0
    value.set_value(value.isNegative() ? BFloat16::lowest() : BFloat16::max());
1119
0
    is.setstate(std::ios_base::failbit);
1120
0
  }
1121
13.1k
  return is;
1122
13.1k
}
1123
1124
// Specialization of ParseNormalFloat for FloatProxy<Float8_E4M3> values.
1125
// This will parse the float as it were a 32-bit floating point number,
1126
// and then round it down to fit into a Float8_E4M3 value.
1127
// The number is rounded towards zero.
1128
// If negate_value is true then the number may not have a leading minus or
1129
// plus, and if it successfully parses, then the number is negated before
1130
// being stored into the value parameter.
1131
// If the value cannot be correctly parsed or overflows the target floating
1132
// point type, then set the fail bit on the stream.
1133
// TODO(dneto): Promise C++11 standard behavior in how the value is set in
1134
// the error case, but only after all target platforms implement it correctly.
1135
// In particular, the Microsoft C++ runtime appears to be out of spec.
1136
template <>
1137
inline std::istream& ParseNormalFloat<FloatProxy<Float8_E4M3>,
1138
                                      HexFloatTraits<FloatProxy<Float8_E4M3>>>(
1139
    std::istream& is, bool negate_value,
1140
    HexFloat<FloatProxy<Float8_E4M3>, HexFloatTraits<FloatProxy<Float8_E4M3>>>&
1141
18.5k
        value) {
1142
  // First parse as a 32-bit float.
1143
18.5k
  HexFloat<FloatProxy<float>> float_val(0.0f);
1144
18.5k
  ParseNormalFloat(is, negate_value, float_val);
1145
1146
18.5k
  if (float_val.value().getAsFloat() > 448.0f) {
1147
4
    is.setstate(std::ios_base::failbit);
1148
4
    value.set_value(Float8_E4M3::max());
1149
4
    return is;
1150
18.5k
  } else if (float_val.value().getAsFloat() < -448.0f) {
1151
4
    is.setstate(std::ios_base::failbit);
1152
4
    value.set_value(0x80 | Float8_E4M3::max().get_value());
1153
4
    return is;
1154
4
  }
1155
  // Then convert to E4M3 float, saturating at infinities, and
1156
  // rounding toward zero.
1157
18.5k
  float_val.castTo(value, round_direction::kToZero);
1158
1159
18.5k
  return is;
1160
18.5k
}
1161
// Specialization of ParseNormalFloat for FloatProxy<Float8_E5M2> values.
1162
// This will parse the float as it were a Float8_E5M2 floating point number,
1163
// and then round it down to fit into a Float16 value.
1164
// The number is rounded towards zero.
1165
// If negate_value is true then the number may not have a leading minus or
1166
// plus, and if it successfully parses, then the number is negated before
1167
// being stored into the value parameter.
1168
// If the value cannot be correctly parsed or overflows the target floating
1169
// point type, then set the fail bit on the stream.
1170
// TODO(dneto): Promise C++11 standard behavior in how the value is set in
1171
// the error case, but only after all target platforms implement it correctly.
1172
// In particular, the Microsoft C++ runtime appears to be out of spec.
1173
template <>
1174
inline std::istream& ParseNormalFloat<FloatProxy<Float8_E5M2>,
1175
                                      HexFloatTraits<FloatProxy<Float8_E5M2>>>(
1176
    std::istream& is, bool negate_value,
1177
    HexFloat<FloatProxy<Float8_E5M2>, HexFloatTraits<FloatProxy<Float8_E5M2>>>&
1178
17.5k
        value) {
1179
  // First parse as a 32-bit float.
1180
17.5k
  HexFloat<FloatProxy<float>> float_val(0.0f);
1181
17.5k
  ParseNormalFloat(is, negate_value, float_val);
1182
1183
  // Then convert to Float8_E5M2 float, saturating at infinities, and
1184
  // rounding toward zero.
1185
17.5k
  float_val.castTo(value, round_direction::kToZero);
1186
1187
  // Overflow on Float8_E5M2 behaves the same as for 32- and 64-bit: set the
1188
  // fail bit and set the lowest or highest value.
1189
17.5k
  if (Float8_E5M2::isInfinity(value.value().getAsFloat())) {
1190
28
    value.set_value(value.isNegative() ? Float8_E5M2::lowest()
1191
28
                                       : Float8_E5M2::max());
1192
28
    is.setstate(std::ios_base::failbit);
1193
28
  }
1194
17.5k
  return is;
1195
17.5k
}
1196
1197
namespace detail {
1198
1199
// Returns a new value formed from 'value' by setting 'bit' that is the
1200
// 'n'th most significant bit (where 0 is the most significant bit).
1201
// If 'bit' is zero or 'n' is more than the number of bits in the integer
1202
// type, then return the original value.
1203
template <typename UINT_TYPE>
1204
UINT_TYPE set_nth_most_significant_bit(UINT_TYPE value, UINT_TYPE bit,
1205
139M
                                       UINT_TYPE n) {
1206
139M
  constexpr UINT_TYPE max_position = std::numeric_limits<UINT_TYPE>::digits - 1;
1207
139M
  if ((bit != 0) && (n <= max_position)) {
1208
424k
    return static_cast<UINT_TYPE>(value | (bit << (max_position - n)));
1209
424k
  }
1210
139M
  return value;
1211
139M
}
unsigned char spvtools::utils::detail::set_nth_most_significant_bit<unsigned char>(unsigned char, unsigned char, unsigned char)
Line
Count
Source
1205
1.10M
                                       UINT_TYPE n) {
1206
1.10M
  constexpr UINT_TYPE max_position = std::numeric_limits<UINT_TYPE>::digits - 1;
1207
1.10M
  if ((bit != 0) && (n <= max_position)) {
1208
104k
    return static_cast<UINT_TYPE>(value | (bit << (max_position - n)));
1209
104k
  }
1210
1.00M
  return value;
1211
1.10M
}
unsigned short spvtools::utils::detail::set_nth_most_significant_bit<unsigned short>(unsigned short, unsigned short, unsigned short)
Line
Count
Source
1205
6.00M
                                       UINT_TYPE n) {
1206
6.00M
  constexpr UINT_TYPE max_position = std::numeric_limits<UINT_TYPE>::digits - 1;
1207
6.00M
  if ((bit != 0) && (n <= max_position)) {
1208
177k
    return static_cast<UINT_TYPE>(value | (bit << (max_position - n)));
1209
177k
  }
1210
5.82M
  return value;
1211
6.00M
}
unsigned int spvtools::utils::detail::set_nth_most_significant_bit<unsigned int>(unsigned int, unsigned int, unsigned int)
Line
Count
Source
1205
27.7M
                                       UINT_TYPE n) {
1206
27.7M
  constexpr UINT_TYPE max_position = std::numeric_limits<UINT_TYPE>::digits - 1;
1207
27.7M
  if ((bit != 0) && (n <= max_position)) {
1208
26.2k
    return static_cast<UINT_TYPE>(value | (bit << (max_position - n)));
1209
26.2k
  }
1210
27.7M
  return value;
1211
27.7M
}
unsigned long spvtools::utils::detail::set_nth_most_significant_bit<unsigned long>(unsigned long, unsigned long, unsigned long)
Line
Count
Source
1205
104M
                                       UINT_TYPE n) {
1206
104M
  constexpr UINT_TYPE max_position = std::numeric_limits<UINT_TYPE>::digits - 1;
1207
104M
  if ((bit != 0) && (n <= max_position)) {
1208
116k
    return static_cast<UINT_TYPE>(value | (bit << (max_position - n)));
1209
116k
  }
1210
104M
  return value;
1211
104M
}
1212
1213
// Attempts to increment the argument.
1214
// If it does not overflow, then increments the argument and returns true.
1215
// If it would overflow, returns false.
1216
template <typename INT_TYPE>
1217
264M
bool saturated_inc(INT_TYPE& value) {
1218
264M
  if (value == std::numeric_limits<INT_TYPE>::max()) {
1219
65.8k
    return false;
1220
65.8k
  }
1221
264M
  value++;
1222
264M
  return true;
1223
264M
}
bool spvtools::utils::detail::saturated_inc<unsigned char>(unsigned char&)
Line
Count
Source
1217
1.10M
bool saturated_inc(INT_TYPE& value) {
1218
1.10M
  if (value == std::numeric_limits<INT_TYPE>::max()) {
1219
54.1k
    return false;
1220
54.1k
  }
1221
1.05M
  value++;
1222
1.05M
  return true;
1223
1.10M
}
bool spvtools::utils::detail::saturated_inc<signed char>(signed char&)
Line
Count
Source
1217
352k
bool saturated_inc(INT_TYPE& value) {
1218
352k
  if (value == std::numeric_limits<INT_TYPE>::max()) {
1219
8
    return false;
1220
8
  }
1221
352k
  value++;
1222
352k
  return true;
1223
352k
}
bool spvtools::utils::detail::saturated_inc<unsigned short>(unsigned short&)
Line
Count
Source
1217
6.00M
bool saturated_inc(INT_TYPE& value) {
1218
6.00M
  if (value == std::numeric_limits<INT_TYPE>::max()) {
1219
11.6k
    return false;
1220
11.6k
  }
1221
5.99M
  value++;
1222
5.99M
  return true;
1223
6.00M
}
bool spvtools::utils::detail::saturated_inc<short>(short&)
Line
Count
Source
1217
1.34M
bool saturated_inc(INT_TYPE& value) {
1218
1.34M
  if (value == std::numeric_limits<INT_TYPE>::max()) {
1219
4
    return false;
1220
4
  }
1221
1.34M
  value++;
1222
1.34M
  return true;
1223
1.34M
}
bool spvtools::utils::detail::saturated_inc<unsigned int>(unsigned int&)
Line
Count
Source
1217
27.7M
bool saturated_inc(INT_TYPE& value) {
1218
27.7M
  if (value == std::numeric_limits<INT_TYPE>::max()) {
1219
0
    return false;
1220
0
  }
1221
27.7M
  value++;
1222
27.7M
  return true;
1223
27.7M
}
bool spvtools::utils::detail::saturated_inc<int>(int&)
Line
Count
Source
1217
22.5M
bool saturated_inc(INT_TYPE& value) {
1218
22.5M
  if (value == std::numeric_limits<INT_TYPE>::max()) {
1219
0
    return false;
1220
0
  }
1221
22.5M
  value++;
1222
22.5M
  return true;
1223
22.5M
}
bool spvtools::utils::detail::saturated_inc<unsigned long>(unsigned long&)
Line
Count
Source
1217
104M
bool saturated_inc(INT_TYPE& value) {
1218
104M
  if (value == std::numeric_limits<INT_TYPE>::max()) {
1219
0
    return false;
1220
0
  }
1221
104M
  value++;
1222
104M
  return true;
1223
104M
}
bool spvtools::utils::detail::saturated_inc<long>(long&)
Line
Count
Source
1217
100M
bool saturated_inc(INT_TYPE& value) {
1218
100M
  if (value == std::numeric_limits<INT_TYPE>::max()) {
1219
0
    return false;
1220
0
  }
1221
100M
  value++;
1222
100M
  return true;
1223
100M
}
1224
1225
// Attempts to decrement the argument.
1226
// If it does not underflow, then decrements the argument and returns true.
1227
// If it would overflow, returns false.
1228
template <typename INT_TYPE>
1229
47.7M
bool saturated_dec(INT_TYPE& value) {
1230
47.7M
  if (value == std::numeric_limits<INT_TYPE>::min()) {
1231
8
    return false;
1232
8
  }
1233
47.7M
  value--;
1234
47.7M
  return true;
1235
47.7M
}
bool spvtools::utils::detail::saturated_dec<signed char>(signed char&)
Line
Count
Source
1229
538k
bool saturated_dec(INT_TYPE& value) {
1230
538k
  if (value == std::numeric_limits<INT_TYPE>::min()) {
1231
4
    return false;
1232
4
  }
1233
538k
  value--;
1234
538k
  return true;
1235
538k
}
bool spvtools::utils::detail::saturated_dec<short>(short&)
Line
Count
Source
1229
2.41M
bool saturated_dec(INT_TYPE& value) {
1230
2.41M
  if (value == std::numeric_limits<INT_TYPE>::min()) {
1231
4
    return false;
1232
4
  }
1233
2.41M
  value--;
1234
2.41M
  return true;
1235
2.41M
}
bool spvtools::utils::detail::saturated_dec<int>(int&)
Line
Count
Source
1229
18.7M
bool saturated_dec(INT_TYPE& value) {
1230
18.7M
  if (value == std::numeric_limits<INT_TYPE>::min()) {
1231
0
    return false;
1232
0
  }
1233
18.7M
  value--;
1234
18.7M
  return true;
1235
18.7M
}
bool spvtools::utils::detail::saturated_dec<long>(long&)
Line
Count
Source
1229
26.0M
bool saturated_dec(INT_TYPE& value) {
1230
26.0M
  if (value == std::numeric_limits<INT_TYPE>::min()) {
1231
0
    return false;
1232
0
  }
1233
26.0M
  value--;
1234
26.0M
  return true;
1235
26.0M
}
1236
}  // namespace detail
1237
1238
// Reads a HexFloat from the given stream.
1239
// If the float is not encoded as a hex-float then it will be parsed
1240
// as a regular float.
1241
// This may fail if your stream does not support at least one unget.
1242
// Nan values can be encoded with "0x1.<not zero>p+exponent_bias".
1243
// This would normally overflow a float and round to
1244
// infinity but this special pattern is the exact representation for a NaN,
1245
// and therefore is actually encoded as the correct NaN. To encode inf,
1246
// either 0x0p+exponent_bias can be specified or any exponent greater than
1247
// exponent_bias.
1248
// Examples using IEEE 32-bit float encoding.
1249
//    0x1.0p+128 (+inf)
1250
//    -0x1.0p-128 (-inf)
1251
//
1252
//    0x1.1p+128 (+Nan)
1253
//    -0x1.1p+128 (-Nan)
1254
//
1255
//    0x1p+129 (+inf)
1256
//    -0x1p+129 (-inf)
1257
template <typename T, typename Traits>
1258
198k
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
1259
198k
  using HF = HexFloat<T, Traits>;
1260
198k
  using uint_type = typename HF::uint_type;
1261
198k
  using int_type = typename HF::int_type;
1262
1263
198k
  value.set_value(static_cast<typename HF::native_type>(0.f));
1264
1265
198k
  if (is.flags() & std::ios::skipws) {
1266
    // If the user wants to skip whitespace , then we should obey that.
1267
210k
    while (std::isspace(is.peek())) {
1268
12.7k
      is.get();
1269
12.7k
    }
1270
198k
  }
1271
1272
198k
  auto next_char = is.peek();
1273
198k
  bool negate_value = false;
1274
1275
198k
  if (next_char != '-' && next_char != '0') {
1276
37.9k
    return ParseNormalFloat(is, negate_value, value);
1277
37.9k
  }
1278
1279
160k
  if (next_char == '-') {
1280
26.1k
    negate_value = true;
1281
26.1k
    is.get();
1282
26.1k
    next_char = is.peek();
1283
26.1k
  }
1284
1285
160k
  if (next_char == '0') {
1286
146k
    is.get();  // We may have to unget this.
1287
146k
    auto maybe_hex_start = is.peek();
1288
146k
    if (maybe_hex_start != 'x' && maybe_hex_start != 'X') {
1289
29.0k
      is.unget();
1290
29.0k
      return ParseNormalFloat(is, negate_value, value);
1291
117k
    } else {
1292
117k
      is.get();  // Throw away the 'x';
1293
117k
    }
1294
146k
  } else {
1295
13.9k
    return ParseNormalFloat(is, negate_value, value);
1296
13.9k
  }
1297
1298
  // This "looks" like a hex-float so treat it as one.
1299
117k
  bool seen_p = false;
1300
117k
  bool seen_dot = false;
1301
1302
  // The mantissa bits, without the most significant 1 bit, and with the
1303
  // the most recently read bits in the least significant positions.
1304
117k
  uint_type fraction = 0;
1305
  // The number of mantissa bits that have been read, including the leading 1
1306
  // bit that is not written into 'fraction'.
1307
117k
  uint_type fraction_index = 0;
1308
1309
  // TODO(dneto): handle overflow and underflow
1310
117k
  int_type exponent = HF::exponent_bias;
1311
1312
  // Strip off leading zeros so we don't have to special-case them later.
1313
473k
  while ((next_char = is.peek()) == '0') {
1314
356k
    is.get();
1315
356k
  }
1316
1317
  // Does the mantissa, as written, have non-zero digits to the left of
1318
  // the decimal point.  Assume no until proven otherwise.
1319
117k
  bool has_integer_part = false;
1320
117k
  bool bits_written = false;  // Stays false until we write a bit.
1321
1322
  // Scan the mantissa hex digits until we see a '.' or the 'p' that
1323
  // starts the exponent.
1324
31.4M
  while (!seen_p && !seen_dot) {
1325
    // Handle characters that are left of the fractional part.
1326
31.3M
    if (next_char == '.') {
1327
66.4k
      seen_dot = true;
1328
31.3M
    } else if (next_char == 'p') {
1329
50.1k
      seen_p = true;
1330
31.2M
    } else if (::isxdigit(next_char)) {
1331
      // We have stripped all leading zeroes and we have not yet seen a ".".
1332
31.2M
      has_integer_part = true;
1333
31.2M
      int number = get_nibble_from_character(next_char);
1334
156M
      for (int i = 0; i < 4; ++i, number <<= 1) {
1335
125M
        uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
1336
125M
        if (bits_written) {
1337
          // If we are here the bits represented belong in the fractional
1338
          // part of the float, and we have to adjust the exponent accordingly.
1339
124M
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1340
124M
                                                          fraction_index);
1341
          // Increment the fraction index. If the input has bizarrely many
1342
          // significant digits, then silently drop them.
1343
124M
          detail::saturated_inc(fraction_index);
1344
124M
          if (!detail::saturated_inc(exponent)) {
1345
            // Overflow failure
1346
12
            is.setstate(std::ios::failbit);
1347
12
            return is;
1348
12
          }
1349
124M
        }
1350
        // Since this updated after setting fraction bits, this effectively
1351
        // drops the leading 1 bit.
1352
125M
        bits_written |= write_bit != 0;
1353
125M
      }
1354
31.2M
    } else {
1355
      // We have not found our exponent yet, so we have to fail.
1356
636
      is.setstate(std::ios::failbit);
1357
636
      return is;
1358
636
    }
1359
31.3M
    is.get();
1360
31.3M
    next_char = is.peek();
1361
31.3M
  }
1362
1363
  // Finished reading the part preceding any '.' or 'p'.
1364
1365
116k
  bits_written = false;
1366
15.8M
  while (seen_dot && !seen_p) {
1367
    // Handle only fractional parts now.
1368
15.7M
    if (next_char == 'p') {
1369
65.8k
      seen_p = true;
1370
15.6M
    } else if (::isxdigit(next_char)) {
1371
15.6M
      int number = get_nibble_from_character(next_char);
1372
78.2M
      for (int i = 0; i < 4; ++i, number <<= 1) {
1373
62.5M
        uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
1374
62.5M
        bits_written |= write_bit != 0;
1375
62.5M
        if ((!has_integer_part) && !bits_written) {
1376
          // Handle modifying the exponent here this way we can handle
1377
          // an arbitrary number of hex values without overflowing our
1378
          // integer.
1379
47.7M
          if (!detail::saturated_dec(exponent)) {
1380
            // Overflow failure
1381
8
            is.setstate(std::ios::failbit);
1382
8
            return is;
1383
8
          }
1384
47.7M
        } else {
1385
14.8M
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1386
14.8M
                                                          fraction_index);
1387
          // Increment the fraction index. If the input has bizarrely many
1388
          // significant digits, then silently drop them.
1389
14.8M
          detail::saturated_inc(fraction_index);
1390
14.8M
        }
1391
62.5M
      }
1392
15.6M
    } else {
1393
      // We still have not found our 'p' exponent yet, so this is not a valid
1394
      // hex-float.
1395
668
      is.setstate(std::ios::failbit);
1396
668
      return is;
1397
668
    }
1398
15.7M
    is.get();
1399
15.7M
    next_char = is.peek();
1400
15.7M
  }
1401
1402
  // Finished reading the part preceding 'p'.
1403
  // In hex floats syntax, the binary exponent is required.
1404
1405
115k
  bool seen_exponent_sign = false;
1406
115k
  int8_t exponent_sign = 1;
1407
115k
  bool seen_written_exponent_digits = false;
1408
  // The magnitude of the exponent, as written, or the sentinel value to signal
1409
  // overflow.
1410
115k
  int_type written_exponent = 0;
1411
  // A sentinel value signalling overflow of the magnitude of the written
1412
  // exponent.  We'll assume that -written_exponent_overflow is valid for the
1413
  // type. Later we may add 1 or subtract 1 from the adjusted exponent, so leave
1414
  // room for an extra 1.
1415
115k
  const int_type written_exponent_overflow =
1416
115k
      std::numeric_limits<int_type>::max() - 1;
1417
1.14M
  while (true) {
1418
1.14M
    if (!seen_written_exponent_digits &&
1419
199k
        (next_char == '-' || next_char == '+')) {
1420
83.3k
      if (seen_exponent_sign) {
1421
26
        is.setstate(std::ios::failbit);
1422
26
        return is;
1423
26
      }
1424
83.3k
      seen_exponent_sign = true;
1425
83.3k
      exponent_sign = (next_char == '-') ? -1 : 1;
1426
1.05M
    } else if (::isdigit(next_char)) {
1427
942k
      seen_written_exponent_digits = true;
1428
      // Hex-floats express their exponent as decimal.
1429
942k
      int_type digit =
1430
942k
          static_cast<int_type>(static_cast<int_type>(next_char) - '0');
1431
942k
      if (written_exponent >= (written_exponent_overflow - digit) / 10) {
1432
        // The exponent is very big. Saturate rather than overflow the exponent.
1433
        // signed integer, which would be undefined behaviour.
1434
282k
        written_exponent = written_exponent_overflow;
1435
659k
      } else {
1436
659k
        written_exponent = static_cast<int_type>(
1437
659k
            static_cast<int_type>(written_exponent * 10) + digit);
1438
659k
      }
1439
942k
    } else {
1440
115k
      break;
1441
115k
    }
1442
1.02M
    is.get();
1443
1.02M
    next_char = is.peek();
1444
1.02M
  }
1445
115k
  if (!seen_written_exponent_digits) {
1446
    // Binary exponent had no digits.
1447
184
    is.setstate(std::ios::failbit);
1448
184
    return is;
1449
184
  }
1450
1451
115k
  written_exponent = static_cast<int_type>(written_exponent * exponent_sign);
1452
  // Now fold in the exponent bias into the written exponent, updating exponent.
1453
  // But avoid undefined behaviour that would result from overflowing int_type.
1454
115k
  if (written_exponent >= 0 && exponent >= 0) {
1455
    // Saturate up to written_exponent_overflow.
1456
54.9k
    if (written_exponent_overflow - exponent > written_exponent) {
1457
41.7k
      exponent = static_cast<int_type>(written_exponent + exponent);
1458
41.7k
    } else {
1459
13.1k
      exponent = written_exponent_overflow;
1460
13.1k
    }
1461
60.7k
  } else if (written_exponent < 0 && exponent < 0) {
1462
    // Saturate down to -written_exponent_overflow.
1463
19.8k
    if (written_exponent_overflow + exponent > -written_exponent) {
1464
13.2k
      exponent = static_cast<int_type>(written_exponent + exponent);
1465
13.2k
    } else {
1466
6.52k
      exponent = static_cast<int_type>(-written_exponent_overflow);
1467
6.52k
    }
1468
40.9k
  } else {
1469
    // They're of opposing sign, so it's safe to add.
1470
40.9k
    exponent = static_cast<int_type>(written_exponent + exponent);
1471
40.9k
  }
1472
1473
115k
  bool is_zero = (!has_integer_part) && (fraction == 0);
1474
115k
  if ((!has_integer_part) && !is_zero) {
1475
46.2k
    fraction = static_cast<uint_type>(fraction << 1);
1476
46.2k
    exponent = static_cast<int_type>(exponent - 1);
1477
69.4k
  } else if (is_zero) {
1478
24.1k
    exponent = 0;
1479
24.1k
  }
1480
1481
115k
  if (exponent <= 0 && !is_zero) {
1482
37.1k
    fraction = static_cast<uint_type>(fraction >> 1);
1483
37.1k
    fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
1484
37.1k
  }
1485
1486
115k
  fraction = (fraction >> HF::fraction_right_shift) & HF::fraction_encode_mask;
1487
1488
115k
  const int_type max_exponent =
1489
115k
      SetBits<uint_type, 0, HF::num_exponent_bits>::get;
1490
1491
  // Handle denorm numbers
1492
440k
  while (exponent < 0 && !is_zero) {
1493
324k
    fraction = static_cast<uint_type>(fraction >> 1);
1494
324k
    exponent = static_cast<int_type>(exponent + 1);
1495
1496
324k
    fraction &= HF::fraction_encode_mask;
1497
324k
    if (fraction == 0) {
1498
      // We have underflowed our fraction. We should clamp to zero.
1499
33.7k
      is_zero = true;
1500
33.7k
      exponent = 0;
1501
33.7k
    }
1502
324k
  }
1503
1504
  // We have overflowed so we should be inf/-inf.
1505
115k
  if (exponent > max_exponent) {
1506
21.3k
    exponent = max_exponent;
1507
21.3k
    fraction = 0;
1508
21.3k
  }
1509
1510
115k
  uint_type output_bits = static_cast<uint_type>(
1511
115k
      static_cast<uint_type>(negate_value ? 1 : 0) << HF::top_bit_left_shift);
1512
115k
  output_bits |= fraction;
1513
1514
115k
  uint_type shifted_exponent = static_cast<uint_type>(
1515
115k
      static_cast<uint_type>(exponent << HF::exponent_left_shift) &
1516
115k
      HF::exponent_mask);
1517
115k
  output_bits |= shifted_exponent;
1518
1519
115k
  T output_float(output_bits);
1520
115k
  value.set_value(output_float);
1521
1522
115k
  return is;
1523
115k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::operator>><spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E4M3> > >&)
Line
Count
Source
1258
38.6k
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
1259
38.6k
  using HF = HexFloat<T, Traits>;
1260
38.6k
  using uint_type = typename HF::uint_type;
1261
38.6k
  using int_type = typename HF::int_type;
1262
1263
38.6k
  value.set_value(static_cast<typename HF::native_type>(0.f));
1264
1265
38.6k
  if (is.flags() & std::ios::skipws) {
1266
    // If the user wants to skip whitespace , then we should obey that.
1267
40.3k
    while (std::isspace(is.peek())) {
1268
1.77k
      is.get();
1269
1.77k
    }
1270
38.6k
  }
1271
1272
38.6k
  auto next_char = is.peek();
1273
38.6k
  bool negate_value = false;
1274
1275
38.6k
  if (next_char != '-' && next_char != '0') {
1276
7.48k
    return ParseNormalFloat(is, negate_value, value);
1277
7.48k
  }
1278
1279
31.1k
  if (next_char == '-') {
1280
5.06k
    negate_value = true;
1281
5.06k
    is.get();
1282
5.06k
    next_char = is.peek();
1283
5.06k
  }
1284
1285
31.1k
  if (next_char == '0') {
1286
28.4k
    is.get();  // We may have to unget this.
1287
28.4k
    auto maybe_hex_start = is.peek();
1288
28.4k
    if (maybe_hex_start != 'x' && maybe_hex_start != 'X') {
1289
8.41k
      is.unget();
1290
8.41k
      return ParseNormalFloat(is, negate_value, value);
1291
20.0k
    } else {
1292
20.0k
      is.get();  // Throw away the 'x';
1293
20.0k
    }
1294
28.4k
  } else {
1295
2.67k
    return ParseNormalFloat(is, negate_value, value);
1296
2.67k
  }
1297
1298
  // This "looks" like a hex-float so treat it as one.
1299
20.0k
  bool seen_p = false;
1300
20.0k
  bool seen_dot = false;
1301
1302
  // The mantissa bits, without the most significant 1 bit, and with the
1303
  // the most recently read bits in the least significant positions.
1304
20.0k
  uint_type fraction = 0;
1305
  // The number of mantissa bits that have been read, including the leading 1
1306
  // bit that is not written into 'fraction'.
1307
20.0k
  uint_type fraction_index = 0;
1308
1309
  // TODO(dneto): handle overflow and underflow
1310
20.0k
  int_type exponent = HF::exponent_bias;
1311
1312
  // Strip off leading zeros so we don't have to special-case them later.
1313
47.9k
  while ((next_char = is.peek()) == '0') {
1314
27.9k
    is.get();
1315
27.9k
  }
1316
1317
  // Does the mantissa, as written, have non-zero digits to the left of
1318
  // the decimal point.  Assume no until proven otherwise.
1319
20.0k
  bool has_integer_part = false;
1320
20.0k
  bool bits_written = false;  // Stays false until we write a bit.
1321
1322
  // Scan the mantissa hex digits until we see a '.' or the 'p' that
1323
  // starts the exponent.
1324
84.2k
  while (!seen_p && !seen_dot) {
1325
    // Handle characters that are left of the fractional part.
1326
64.2k
    if (next_char == '.') {
1327
10.6k
      seen_dot = true;
1328
53.6k
    } else if (next_char == 'p') {
1329
9.27k
      seen_p = true;
1330
44.3k
    } else if (::isxdigit(next_char)) {
1331
      // We have stripped all leading zeroes and we have not yet seen a ".".
1332
44.2k
      has_integer_part = true;
1333
44.2k
      int number = get_nibble_from_character(next_char);
1334
221k
      for (int i = 0; i < 4; ++i, number <<= 1) {
1335
177k
        uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
1336
177k
        if (bits_written) {
1337
          // If we are here the bits represented belong in the fractional
1338
          // part of the float, and we have to adjust the exponent accordingly.
1339
159k
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1340
159k
                                                          fraction_index);
1341
          // Increment the fraction index. If the input has bizarrely many
1342
          // significant digits, then silently drop them.
1343
159k
          detail::saturated_inc(fraction_index);
1344
159k
          if (!detail::saturated_inc(exponent)) {
1345
            // Overflow failure
1346
6
            is.setstate(std::ios::failbit);
1347
6
            return is;
1348
6
          }
1349
159k
        }
1350
        // Since this updated after setting fraction bits, this effectively
1351
        // drops the leading 1 bit.
1352
177k
        bits_written |= write_bit != 0;
1353
177k
      }
1354
44.2k
    } else {
1355
      // We have not found our exponent yet, so we have to fail.
1356
96
      is.setstate(std::ios::failbit);
1357
96
      return is;
1358
96
    }
1359
64.1k
    is.get();
1360
64.1k
    next_char = is.peek();
1361
64.1k
  }
1362
1363
  // Finished reading the part preceding any '.' or 'p'.
1364
1365
19.9k
  bits_written = false;
1366
190k
  while (seen_dot && !seen_p) {
1367
    // Handle only fractional parts now.
1368
170k
    if (next_char == 'p') {
1369
10.5k
      seen_p = true;
1370
159k
    } else if (::isxdigit(next_char)) {
1371
159k
      int number = get_nibble_from_character(next_char);
1372
798k
      for (int i = 0; i < 4; ++i, number <<= 1) {
1373
638k
        uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
1374
638k
        bits_written |= write_bit != 0;
1375
638k
        if ((!has_integer_part) && !bits_written) {
1376
          // Handle modifying the exponent here this way we can handle
1377
          // an arbitrary number of hex values without overflowing our
1378
          // integer.
1379
247k
          if (!detail::saturated_dec(exponent)) {
1380
            // Overflow failure
1381
2
            is.setstate(std::ios::failbit);
1382
2
            return is;
1383
2
          }
1384
391k
        } else {
1385
391k
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1386
391k
                                                          fraction_index);
1387
          // Increment the fraction index. If the input has bizarrely many
1388
          // significant digits, then silently drop them.
1389
391k
          detail::saturated_inc(fraction_index);
1390
391k
        }
1391
638k
      }
1392
159k
    } else {
1393
      // We still have not found our 'p' exponent yet, so this is not a valid
1394
      // hex-float.
1395
78
      is.setstate(std::ios::failbit);
1396
78
      return is;
1397
78
    }
1398
170k
    is.get();
1399
170k
    next_char = is.peek();
1400
170k
  }
1401
1402
  // Finished reading the part preceding 'p'.
1403
  // In hex floats syntax, the binary exponent is required.
1404
1405
19.8k
  bool seen_exponent_sign = false;
1406
19.8k
  int8_t exponent_sign = 1;
1407
19.8k
  bool seen_written_exponent_digits = false;
1408
  // The magnitude of the exponent, as written, or the sentinel value to signal
1409
  // overflow.
1410
19.8k
  int_type written_exponent = 0;
1411
  // A sentinel value signalling overflow of the magnitude of the written
1412
  // exponent.  We'll assume that -written_exponent_overflow is valid for the
1413
  // type. Later we may add 1 or subtract 1 from the adjusted exponent, so leave
1414
  // room for an extra 1.
1415
19.8k
  const int_type written_exponent_overflow =
1416
19.8k
      std::numeric_limits<int_type>::max() - 1;
1417
127k
  while (true) {
1418
127k
    if (!seen_written_exponent_digits &&
1419
34.9k
        (next_char == '-' || next_char == '+')) {
1420
15.1k
      if (seen_exponent_sign) {
1421
4
        is.setstate(std::ios::failbit);
1422
4
        return is;
1423
4
      }
1424
15.1k
      seen_exponent_sign = true;
1425
15.1k
      exponent_sign = (next_char == '-') ? -1 : 1;
1426
112k
    } else if (::isdigit(next_char)) {
1427
92.7k
      seen_written_exponent_digits = true;
1428
      // Hex-floats express their exponent as decimal.
1429
92.7k
      int_type digit =
1430
92.7k
          static_cast<int_type>(static_cast<int_type>(next_char) - '0');
1431
92.7k
      if (written_exponent >= (written_exponent_overflow - digit) / 10) {
1432
        // The exponent is very big. Saturate rather than overflow the exponent.
1433
        // signed integer, which would be undefined behaviour.
1434
38.1k
        written_exponent = written_exponent_overflow;
1435
54.5k
      } else {
1436
54.5k
        written_exponent = static_cast<int_type>(
1437
54.5k
            static_cast<int_type>(written_exponent * 10) + digit);
1438
54.5k
      }
1439
92.7k
    } else {
1440
19.8k
      break;
1441
19.8k
    }
1442
107k
    is.get();
1443
107k
    next_char = is.peek();
1444
107k
  }
1445
19.8k
  if (!seen_written_exponent_digits) {
1446
    // Binary exponent had no digits.
1447
30
    is.setstate(std::ios::failbit);
1448
30
    return is;
1449
30
  }
1450
1451
19.8k
  written_exponent = static_cast<int_type>(written_exponent * exponent_sign);
1452
  // Now fold in the exponent bias into the written exponent, updating exponent.
1453
  // But avoid undefined behaviour that would result from overflowing int_type.
1454
19.8k
  if (written_exponent >= 0 && exponent >= 0) {
1455
    // Saturate up to written_exponent_overflow.
1456
8.31k
    if (written_exponent_overflow - exponent > written_exponent) {
1457
6.31k
      exponent = static_cast<int_type>(written_exponent + exponent);
1458
6.31k
    } else {
1459
1.99k
      exponent = written_exponent_overflow;
1460
1.99k
    }
1461
11.5k
  } else if (written_exponent < 0 && exponent < 0) {
1462
    // Saturate down to -written_exponent_overflow.
1463
6.10k
    if (written_exponent_overflow + exponent > -written_exponent) {
1464
3.91k
      exponent = static_cast<int_type>(written_exponent + exponent);
1465
3.91k
    } else {
1466
2.19k
      exponent = static_cast<int_type>(-written_exponent_overflow);
1467
2.19k
    }
1468
6.10k
  } else {
1469
    // They're of opposing sign, so it's safe to add.
1470
5.40k
    exponent = static_cast<int_type>(written_exponent + exponent);
1471
5.40k
  }
1472
1473
19.8k
  bool is_zero = (!has_integer_part) && (fraction == 0);
1474
19.8k
  if ((!has_integer_part) && !is_zero) {
1475
7.95k
    fraction = static_cast<uint_type>(fraction << 1);
1476
7.95k
    exponent = static_cast<int_type>(exponent - 1);
1477
11.8k
  } else if (is_zero) {
1478
3.79k
    exponent = 0;
1479
3.79k
  }
1480
1481
19.8k
  if (exponent <= 0 && !is_zero) {
1482
9.15k
    fraction = static_cast<uint_type>(fraction >> 1);
1483
9.15k
    fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
1484
9.15k
  }
1485
1486
19.8k
  fraction = (fraction >> HF::fraction_right_shift) & HF::fraction_encode_mask;
1487
1488
19.8k
  const int_type max_exponent =
1489
19.8k
      SetBits<uint_type, 0, HF::num_exponent_bits>::get;
1490
1491
  // Handle denorm numbers
1492
46.7k
  while (exponent < 0 && !is_zero) {
1493
26.9k
    fraction = static_cast<uint_type>(fraction >> 1);
1494
26.9k
    exponent = static_cast<int_type>(exponent + 1);
1495
1496
26.9k
    fraction &= HF::fraction_encode_mask;
1497
26.9k
    if (fraction == 0) {
1498
      // We have underflowed our fraction. We should clamp to zero.
1499
8.95k
      is_zero = true;
1500
8.95k
      exponent = 0;
1501
8.95k
    }
1502
26.9k
  }
1503
1504
  // We have overflowed so we should be inf/-inf.
1505
19.8k
  if (exponent > max_exponent) {
1506
5.51k
    exponent = max_exponent;
1507
5.51k
    fraction = 0;
1508
5.51k
  }
1509
1510
19.8k
  uint_type output_bits = static_cast<uint_type>(
1511
19.8k
      static_cast<uint_type>(negate_value ? 1 : 0) << HF::top_bit_left_shift);
1512
19.8k
  output_bits |= fraction;
1513
1514
19.8k
  uint_type shifted_exponent = static_cast<uint_type>(
1515
19.8k
      static_cast<uint_type>(exponent << HF::exponent_left_shift) &
1516
19.8k
      HF::exponent_mask);
1517
19.8k
  output_bits |= shifted_exponent;
1518
1519
19.8k
  T output_float(output_bits);
1520
19.8k
  value.set_value(output_float);
1521
1522
19.8k
  return is;
1523
19.8k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::operator>><spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float8_E5M2> > >&)
Line
Count
Source
1258
38.8k
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
1259
38.8k
  using HF = HexFloat<T, Traits>;
1260
38.8k
  using uint_type = typename HF::uint_type;
1261
38.8k
  using int_type = typename HF::int_type;
1262
1263
38.8k
  value.set_value(static_cast<typename HF::native_type>(0.f));
1264
1265
38.8k
  if (is.flags() & std::ios::skipws) {
1266
    // If the user wants to skip whitespace , then we should obey that.
1267
40.6k
    while (std::isspace(is.peek())) {
1268
1.84k
      is.get();
1269
1.84k
    }
1270
38.8k
  }
1271
1272
38.8k
  auto next_char = is.peek();
1273
38.8k
  bool negate_value = false;
1274
1275
38.8k
  if (next_char != '-' && next_char != '0') {
1276
8.22k
    return ParseNormalFloat(is, negate_value, value);
1277
8.22k
  }
1278
1279
30.5k
  if (next_char == '-') {
1280
4.72k
    negate_value = true;
1281
4.72k
    is.get();
1282
4.72k
    next_char = is.peek();
1283
4.72k
  }
1284
1285
30.5k
  if (next_char == '0') {
1286
28.1k
    is.get();  // We may have to unget this.
1287
28.1k
    auto maybe_hex_start = is.peek();
1288
28.1k
    if (maybe_hex_start != 'x' && maybe_hex_start != 'X') {
1289
6.88k
      is.unget();
1290
6.88k
      return ParseNormalFloat(is, negate_value, value);
1291
21.2k
    } else {
1292
21.2k
      is.get();  // Throw away the 'x';
1293
21.2k
    }
1294
28.1k
  } else {
1295
2.42k
    return ParseNormalFloat(is, negate_value, value);
1296
2.42k
  }
1297
1298
  // This "looks" like a hex-float so treat it as one.
1299
21.2k
  bool seen_p = false;
1300
21.2k
  bool seen_dot = false;
1301
1302
  // The mantissa bits, without the most significant 1 bit, and with the
1303
  // the most recently read bits in the least significant positions.
1304
21.2k
  uint_type fraction = 0;
1305
  // The number of mantissa bits that have been read, including the leading 1
1306
  // bit that is not written into 'fraction'.
1307
21.2k
  uint_type fraction_index = 0;
1308
1309
  // TODO(dneto): handle overflow and underflow
1310
21.2k
  int_type exponent = HF::exponent_bias;
1311
1312
  // Strip off leading zeros so we don't have to special-case them later.
1313
70.7k
  while ((next_char = is.peek()) == '0') {
1314
49.4k
    is.get();
1315
49.4k
  }
1316
1317
  // Does the mantissa, as written, have non-zero digits to the left of
1318
  // the decimal point.  Assume no until proven otherwise.
1319
21.2k
  bool has_integer_part = false;
1320
21.2k
  bool bits_written = false;  // Stays false until we write a bit.
1321
1322
  // Scan the mantissa hex digits until we see a '.' or the 'p' that
1323
  // starts the exponent.
1324
95.7k
  while (!seen_p && !seen_dot) {
1325
    // Handle characters that are left of the fractional part.
1326
74.5k
    if (next_char == '.') {
1327
11.4k
      seen_dot = true;
1328
63.0k
    } else if (next_char == 'p') {
1329
9.76k
      seen_p = true;
1330
53.3k
    } else if (::isxdigit(next_char)) {
1331
      // We have stripped all leading zeroes and we have not yet seen a ".".
1332
53.2k
      has_integer_part = true;
1333
53.2k
      int number = get_nibble_from_character(next_char);
1334
266k
      for (int i = 0; i < 4; ++i, number <<= 1) {
1335
213k
        uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
1336
213k
        if (bits_written) {
1337
          // If we are here the bits represented belong in the fractional
1338
          // part of the float, and we have to adjust the exponent accordingly.
1339
192k
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1340
192k
                                                          fraction_index);
1341
          // Increment the fraction index. If the input has bizarrely many
1342
          // significant digits, then silently drop them.
1343
192k
          detail::saturated_inc(fraction_index);
1344
192k
          if (!detail::saturated_inc(exponent)) {
1345
            // Overflow failure
1346
2
            is.setstate(std::ios::failbit);
1347
2
            return is;
1348
2
          }
1349
192k
        }
1350
        // Since this updated after setting fraction bits, this effectively
1351
        // drops the leading 1 bit.
1352
213k
        bits_written |= write_bit != 0;
1353
213k
      }
1354
53.2k
    } else {
1355
      // We have not found our exponent yet, so we have to fail.
1356
78
      is.setstate(std::ios::failbit);
1357
78
      return is;
1358
78
    }
1359
74.4k
    is.get();
1360
74.4k
    next_char = is.peek();
1361
74.4k
  }
1362
1363
  // Finished reading the part preceding any '.' or 'p'.
1364
1365
21.2k
  bits_written = false;
1366
196k
  while (seen_dot && !seen_p) {
1367
    // Handle only fractional parts now.
1368
174k
    if (next_char == 'p') {
1369
11.3k
      seen_p = true;
1370
163k
    } else if (::isxdigit(next_char)) {
1371
163k
      int number = get_nibble_from_character(next_char);
1372
817k
      for (int i = 0; i < 4; ++i, number <<= 1) {
1373
653k
        uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
1374
653k
        bits_written |= write_bit != 0;
1375
653k
        if ((!has_integer_part) && !bits_written) {
1376
          // Handle modifying the exponent here this way we can handle
1377
          // an arbitrary number of hex values without overflowing our
1378
          // integer.
1379
291k
          if (!detail::saturated_dec(exponent)) {
1380
            // Overflow failure
1381
2
            is.setstate(std::ios::failbit);
1382
2
            return is;
1383
2
          }
1384
362k
        } else {
1385
362k
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1386
362k
                                                          fraction_index);
1387
          // Increment the fraction index. If the input has bizarrely many
1388
          // significant digits, then silently drop them.
1389
362k
          detail::saturated_inc(fraction_index);
1390
362k
        }
1391
653k
      }
1392
163k
    } else {
1393
      // We still have not found our 'p' exponent yet, so this is not a valid
1394
      // hex-float.
1395
66
      is.setstate(std::ios::failbit);
1396
66
      return is;
1397
66
    }
1398
174k
    is.get();
1399
174k
    next_char = is.peek();
1400
174k
  }
1401
1402
  // Finished reading the part preceding 'p'.
1403
  // In hex floats syntax, the binary exponent is required.
1404
1405
21.1k
  bool seen_exponent_sign = false;
1406
21.1k
  int8_t exponent_sign = 1;
1407
21.1k
  bool seen_written_exponent_digits = false;
1408
  // The magnitude of the exponent, as written, or the sentinel value to signal
1409
  // overflow.
1410
21.1k
  int_type written_exponent = 0;
1411
  // A sentinel value signalling overflow of the magnitude of the written
1412
  // exponent.  We'll assume that -written_exponent_overflow is valid for the
1413
  // type. Later we may add 1 or subtract 1 from the adjusted exponent, so leave
1414
  // room for an extra 1.
1415
21.1k
  const int_type written_exponent_overflow =
1416
21.1k
      std::numeric_limits<int_type>::max() - 1;
1417
437k
  while (true) {
1418
437k
    if (!seen_written_exponent_digits &&
1419
37.8k
        (next_char == '-' || next_char == '+')) {
1420
16.6k
      if (seen_exponent_sign) {
1421
4
        is.setstate(std::ios::failbit);
1422
4
        return is;
1423
4
      }
1424
16.6k
      seen_exponent_sign = true;
1425
16.6k
      exponent_sign = (next_char == '-') ? -1 : 1;
1426
420k
    } else if (::isdigit(next_char)) {
1427
399k
      seen_written_exponent_digits = true;
1428
      // Hex-floats express their exponent as decimal.
1429
399k
      int_type digit =
1430
399k
          static_cast<int_type>(static_cast<int_type>(next_char) - '0');
1431
399k
      if (written_exponent >= (written_exponent_overflow - digit) / 10) {
1432
        // The exponent is very big. Saturate rather than overflow the exponent.
1433
        // signed integer, which would be undefined behaviour.
1434
137k
        written_exponent = written_exponent_overflow;
1435
262k
      } else {
1436
262k
        written_exponent = static_cast<int_type>(
1437
262k
            static_cast<int_type>(written_exponent * 10) + digit);
1438
262k
      }
1439
399k
    } else {
1440
21.1k
      break;
1441
21.1k
    }
1442
416k
    is.get();
1443
416k
    next_char = is.peek();
1444
416k
  }
1445
21.1k
  if (!seen_written_exponent_digits) {
1446
    // Binary exponent had no digits.
1447
30
    is.setstate(std::ios::failbit);
1448
30
    return is;
1449
30
  }
1450
1451
21.1k
  written_exponent = static_cast<int_type>(written_exponent * exponent_sign);
1452
  // Now fold in the exponent bias into the written exponent, updating exponent.
1453
  // But avoid undefined behaviour that would result from overflowing int_type.
1454
21.1k
  if (written_exponent >= 0 && exponent >= 0) {
1455
    // Saturate up to written_exponent_overflow.
1456
7.92k
    if (written_exponent_overflow - exponent > written_exponent) {
1457
6.15k
      exponent = static_cast<int_type>(written_exponent + exponent);
1458
6.15k
    } else {
1459
1.77k
      exponent = written_exponent_overflow;
1460
1.77k
    }
1461
13.1k
  } else if (written_exponent < 0 && exponent < 0) {
1462
    // Saturate down to -written_exponent_overflow.
1463
5.59k
    if (written_exponent_overflow + exponent > -written_exponent) {
1464
3.50k
      exponent = static_cast<int_type>(written_exponent + exponent);
1465
3.50k
    } else {
1466
2.09k
      exponent = static_cast<int_type>(-written_exponent_overflow);
1467
2.09k
    }
1468
7.57k
  } else {
1469
    // They're of opposing sign, so it's safe to add.
1470
7.57k
    exponent = static_cast<int_type>(written_exponent + exponent);
1471
7.57k
  }
1472
1473
21.1k
  bool is_zero = (!has_integer_part) && (fraction == 0);
1474
21.1k
  if ((!has_integer_part) && !is_zero) {
1475
9.30k
    fraction = static_cast<uint_type>(fraction << 1);
1476
9.30k
    exponent = static_cast<int_type>(exponent - 1);
1477
11.8k
  } else if (is_zero) {
1478
2.89k
    exponent = 0;
1479
2.89k
  }
1480
1481
21.1k
  if (exponent <= 0 && !is_zero) {
1482
9.84k
    fraction = static_cast<uint_type>(fraction >> 1);
1483
9.84k
    fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
1484
9.84k
  }
1485
1486
21.1k
  fraction = (fraction >> HF::fraction_right_shift) & HF::fraction_encode_mask;
1487
1488
21.1k
  const int_type max_exponent =
1489
21.1k
      SetBits<uint_type, 0, HF::num_exponent_bits>::get;
1490
1491
  // Handle denorm numbers
1492
39.6k
  while (exponent < 0 && !is_zero) {
1493
18.5k
    fraction = static_cast<uint_type>(fraction >> 1);
1494
18.5k
    exponent = static_cast<int_type>(exponent + 1);
1495
1496
18.5k
    fraction &= HF::fraction_encode_mask;
1497
18.5k
    if (fraction == 0) {
1498
      // We have underflowed our fraction. We should clamp to zero.
1499
9.16k
      is_zero = true;
1500
9.16k
      exponent = 0;
1501
9.16k
    }
1502
18.5k
  }
1503
1504
  // We have overflowed so we should be inf/-inf.
1505
21.1k
  if (exponent > max_exponent) {
1506
5.69k
    exponent = max_exponent;
1507
5.69k
    fraction = 0;
1508
5.69k
  }
1509
1510
21.1k
  uint_type output_bits = static_cast<uint_type>(
1511
21.1k
      static_cast<uint_type>(negate_value ? 1 : 0) << HF::top_bit_left_shift);
1512
21.1k
  output_bits |= fraction;
1513
1514
21.1k
  uint_type shifted_exponent = static_cast<uint_type>(
1515
21.1k
      static_cast<uint_type>(exponent << HF::exponent_left_shift) &
1516
21.1k
      HF::exponent_mask);
1517
21.1k
  output_bits |= shifted_exponent;
1518
1519
21.1k
  T output_float(output_bits);
1520
21.1k
  value.set_value(output_float);
1521
1522
21.1k
  return is;
1523
21.1k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::operator>><spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::BFloat16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::BFloat16> > >&)
Line
Count
Source
1258
34.4k
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
1259
34.4k
  using HF = HexFloat<T, Traits>;
1260
34.4k
  using uint_type = typename HF::uint_type;
1261
34.4k
  using int_type = typename HF::int_type;
1262
1263
34.4k
  value.set_value(static_cast<typename HF::native_type>(0.f));
1264
1265
34.4k
  if (is.flags() & std::ios::skipws) {
1266
    // If the user wants to skip whitespace , then we should obey that.
1267
37.0k
    while (std::isspace(is.peek())) {
1268
2.55k
      is.get();
1269
2.55k
    }
1270
34.4k
  }
1271
1272
34.4k
  auto next_char = is.peek();
1273
34.4k
  bool negate_value = false;
1274
1275
34.4k
  if (next_char != '-' && next_char != '0') {
1276
4.44k
    return ParseNormalFloat(is, negate_value, value);
1277
4.44k
  }
1278
1279
30.0k
  if (next_char == '-') {
1280
6.19k
    negate_value = true;
1281
6.19k
    is.get();
1282
6.19k
    next_char = is.peek();
1283
6.19k
  }
1284
1285
30.0k
  if (next_char == '0') {
1286
26.6k
    is.get();  // We may have to unget this.
1287
26.6k
    auto maybe_hex_start = is.peek();
1288
26.6k
    if (maybe_hex_start != 'x' && maybe_hex_start != 'X') {
1289
5.35k
      is.unget();
1290
5.35k
      return ParseNormalFloat(is, negate_value, value);
1291
21.3k
    } else {
1292
21.3k
      is.get();  // Throw away the 'x';
1293
21.3k
    }
1294
26.6k
  } else {
1295
3.35k
    return ParseNormalFloat(is, negate_value, value);
1296
3.35k
  }
1297
1298
  // This "looks" like a hex-float so treat it as one.
1299
21.3k
  bool seen_p = false;
1300
21.3k
  bool seen_dot = false;
1301
1302
  // The mantissa bits, without the most significant 1 bit, and with the
1303
  // the most recently read bits in the least significant positions.
1304
21.3k
  uint_type fraction = 0;
1305
  // The number of mantissa bits that have been read, including the leading 1
1306
  // bit that is not written into 'fraction'.
1307
21.3k
  uint_type fraction_index = 0;
1308
1309
  // TODO(dneto): handle overflow and underflow
1310
21.3k
  int_type exponent = HF::exponent_bias;
1311
1312
  // Strip off leading zeros so we don't have to special-case them later.
1313
245k
  while ((next_char = is.peek()) == '0') {
1314
224k
    is.get();
1315
224k
  }
1316
1317
  // Does the mantissa, as written, have non-zero digits to the left of
1318
  // the decimal point.  Assume no until proven otherwise.
1319
21.3k
  bool has_integer_part = false;
1320
21.3k
  bool bits_written = false;  // Stays false until we write a bit.
1321
1322
  // Scan the mantissa hex digits until we see a '.' or the 'p' that
1323
  // starts the exponent.
1324
267k
  while (!seen_p && !seen_dot) {
1325
    // Handle characters that are left of the fractional part.
1326
246k
    if (next_char == '.') {
1327
9.77k
      seen_dot = true;
1328
236k
    } else if (next_char == 'p') {
1329
11.4k
      seen_p = true;
1330
225k
    } else if (::isxdigit(next_char)) {
1331
      // We have stripped all leading zeroes and we have not yet seen a ".".
1332
225k
      has_integer_part = true;
1333
225k
      int number = get_nibble_from_character(next_char);
1334
1.12M
      for (int i = 0; i < 4; ++i, number <<= 1) {
1335
901k
        uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
1336
901k
        if (bits_written) {
1337
          // If we are here the bits represented belong in the fractional
1338
          // part of the float, and we have to adjust the exponent accordingly.
1339
881k
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1340
881k
                                                          fraction_index);
1341
          // Increment the fraction index. If the input has bizarrely many
1342
          // significant digits, then silently drop them.
1343
881k
          detail::saturated_inc(fraction_index);
1344
881k
          if (!detail::saturated_inc(exponent)) {
1345
            // Overflow failure
1346
2
            is.setstate(std::ios::failbit);
1347
2
            return is;
1348
2
          }
1349
881k
        }
1350
        // Since this updated after setting fraction bits, this effectively
1351
        // drops the leading 1 bit.
1352
901k
        bits_written |= write_bit != 0;
1353
901k
      }
1354
225k
    } else {
1355
      // We have not found our exponent yet, so we have to fail.
1356
134
      is.setstate(std::ios::failbit);
1357
134
      return is;
1358
134
    }
1359
246k
    is.get();
1360
246k
    next_char = is.peek();
1361
246k
  }
1362
1363
  // Finished reading the part preceding any '.' or 'p'.
1364
1365
21.1k
  bits_written = false;
1366
717k
  while (seen_dot && !seen_p) {
1367
    // Handle only fractional parts now.
1368
696k
    if (next_char == 'p') {
1369
9.68k
      seen_p = true;
1370
687k
    } else if (::isxdigit(next_char)) {
1371
687k
      int number = get_nibble_from_character(next_char);
1372
3.43M
      for (int i = 0; i < 4; ++i, number <<= 1) {
1373
2.74M
        uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
1374
2.74M
        bits_written |= write_bit != 0;
1375
2.74M
        if ((!has_integer_part) && !bits_written) {
1376
          // Handle modifying the exponent here this way we can handle
1377
          // an arbitrary number of hex values without overflowing our
1378
          // integer.
1379
623k
          if (!detail::saturated_dec(exponent)) {
1380
            // Overflow failure
1381
2
            is.setstate(std::ios::failbit);
1382
2
            return is;
1383
2
          }
1384
2.12M
        } else {
1385
2.12M
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1386
2.12M
                                                          fraction_index);
1387
          // Increment the fraction index. If the input has bizarrely many
1388
          // significant digits, then silently drop them.
1389
2.12M
          detail::saturated_inc(fraction_index);
1390
2.12M
        }
1391
2.74M
      }
1392
687k
    } else {
1393
      // We still have not found our 'p' exponent yet, so this is not a valid
1394
      // hex-float.
1395
82
      is.setstate(std::ios::failbit);
1396
82
      return is;
1397
82
    }
1398
696k
    is.get();
1399
696k
    next_char = is.peek();
1400
696k
  }
1401
1402
  // Finished reading the part preceding 'p'.
1403
  // In hex floats syntax, the binary exponent is required.
1404
1405
21.0k
  bool seen_exponent_sign = false;
1406
21.0k
  int8_t exponent_sign = 1;
1407
21.0k
  bool seen_written_exponent_digits = false;
1408
  // The magnitude of the exponent, as written, or the sentinel value to signal
1409
  // overflow.
1410
21.0k
  int_type written_exponent = 0;
1411
  // A sentinel value signalling overflow of the magnitude of the written
1412
  // exponent.  We'll assume that -written_exponent_overflow is valid for the
1413
  // type. Later we may add 1 or subtract 1 from the adjusted exponent, so leave
1414
  // room for an extra 1.
1415
21.0k
  const int_type written_exponent_overflow =
1416
21.0k
      std::numeric_limits<int_type>::max() - 1;
1417
143k
  while (true) {
1418
143k
    if (!seen_written_exponent_digits &&
1419
37.0k
        (next_char == '-' || next_char == '+')) {
1420
15.9k
      if (seen_exponent_sign) {
1421
4
        is.setstate(std::ios::failbit);
1422
4
        return is;
1423
4
      }
1424
15.9k
      seen_exponent_sign = true;
1425
15.9k
      exponent_sign = (next_char == '-') ? -1 : 1;
1426
127k
    } else if (::isdigit(next_char)) {
1427
106k
      seen_written_exponent_digits = true;
1428
      // Hex-floats express their exponent as decimal.
1429
106k
      int_type digit =
1430
106k
          static_cast<int_type>(static_cast<int_type>(next_char) - '0');
1431
106k
      if (written_exponent >= (written_exponent_overflow - digit) / 10) {
1432
        // The exponent is very big. Saturate rather than overflow the exponent.
1433
        // signed integer, which would be undefined behaviour.
1434
53.5k
        written_exponent = written_exponent_overflow;
1435
53.5k
      } else {
1436
53.0k
        written_exponent = static_cast<int_type>(
1437
53.0k
            static_cast<int_type>(written_exponent * 10) + digit);
1438
53.0k
      }
1439
106k
    } else {
1440
21.0k
      break;
1441
21.0k
    }
1442
122k
    is.get();
1443
122k
    next_char = is.peek();
1444
122k
  }
1445
21.0k
  if (!seen_written_exponent_digits) {
1446
    // Binary exponent had no digits.
1447
24
    is.setstate(std::ios::failbit);
1448
24
    return is;
1449
24
  }
1450
1451
21.0k
  written_exponent = static_cast<int_type>(written_exponent * exponent_sign);
1452
  // Now fold in the exponent bias into the written exponent, updating exponent.
1453
  // But avoid undefined behaviour that would result from overflowing int_type.
1454
21.0k
  if (written_exponent >= 0 && exponent >= 0) {
1455
    // Saturate up to written_exponent_overflow.
1456
10.3k
    if (written_exponent_overflow - exponent > written_exponent) {
1457
7.00k
      exponent = static_cast<int_type>(written_exponent + exponent);
1458
7.00k
    } else {
1459
3.30k
      exponent = written_exponent_overflow;
1460
3.30k
    }
1461
10.7k
  } else if (written_exponent < 0 && exponent < 0) {
1462
    // Saturate down to -written_exponent_overflow.
1463
1.12k
    if (written_exponent_overflow + exponent > -written_exponent) {
1464
865
      exponent = static_cast<int_type>(written_exponent + exponent);
1465
865
    } else {
1466
262
      exponent = static_cast<int_type>(-written_exponent_overflow);
1467
262
    }
1468
9.62k
  } else {
1469
    // They're of opposing sign, so it's safe to add.
1470
9.62k
    exponent = static_cast<int_type>(written_exponent + exponent);
1471
9.62k
  }
1472
1473
21.0k
  bool is_zero = (!has_integer_part) && (fraction == 0);
1474
21.0k
  if ((!has_integer_part) && !is_zero) {
1475
8.45k
    fraction = static_cast<uint_type>(fraction << 1);
1476
8.45k
    exponent = static_cast<int_type>(exponent - 1);
1477
12.6k
  } else if (is_zero) {
1478
3.52k
    exponent = 0;
1479
3.52k
  }
1480
1481
21.0k
  if (exponent <= 0 && !is_zero) {
1482
3.88k
    fraction = static_cast<uint_type>(fraction >> 1);
1483
3.88k
    fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
1484
3.88k
  }
1485
1486
21.0k
  fraction = (fraction >> HF::fraction_right_shift) & HF::fraction_encode_mask;
1487
1488
21.0k
  const int_type max_exponent =
1489
21.0k
      SetBits<uint_type, 0, HF::num_exponent_bits>::get;
1490
1491
  // Handle denorm numbers
1492
47.3k
  while (exponent < 0 && !is_zero) {
1493
26.3k
    fraction = static_cast<uint_type>(fraction >> 1);
1494
26.3k
    exponent = static_cast<int_type>(exponent + 1);
1495
1496
26.3k
    fraction &= HF::fraction_encode_mask;
1497
26.3k
    if (fraction == 0) {
1498
      // We have underflowed our fraction. We should clamp to zero.
1499
3.58k
      is_zero = true;
1500
3.58k
      exponent = 0;
1501
3.58k
    }
1502
26.3k
  }
1503
1504
  // We have overflowed so we should be inf/-inf.
1505
21.0k
  if (exponent > max_exponent) {
1506
1.48k
    exponent = max_exponent;
1507
1.48k
    fraction = 0;
1508
1.48k
  }
1509
1510
21.0k
  uint_type output_bits = static_cast<uint_type>(
1511
21.0k
      static_cast<uint_type>(negate_value ? 1 : 0) << HF::top_bit_left_shift);
1512
21.0k
  output_bits |= fraction;
1513
1514
21.0k
  uint_type shifted_exponent = static_cast<uint_type>(
1515
21.0k
      static_cast<uint_type>(exponent << HF::exponent_left_shift) &
1516
21.0k
      HF::exponent_mask);
1517
21.0k
  output_bits |= shifted_exponent;
1518
1519
21.0k
  T output_float(output_bits);
1520
21.0k
  value.set_value(output_float);
1521
1522
21.0k
  return is;
1523
21.0k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::operator>><spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<spvtools::utils::Float16>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<spvtools::utils::Float16> > >&)
Line
Count
Source
1258
35.8k
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
1259
35.8k
  using HF = HexFloat<T, Traits>;
1260
35.8k
  using uint_type = typename HF::uint_type;
1261
35.8k
  using int_type = typename HF::int_type;
1262
1263
35.8k
  value.set_value(static_cast<typename HF::native_type>(0.f));
1264
1265
35.8k
  if (is.flags() & std::ios::skipws) {
1266
    // If the user wants to skip whitespace , then we should obey that.
1267
39.1k
    while (std::isspace(is.peek())) {
1268
3.23k
      is.get();
1269
3.23k
    }
1270
35.8k
  }
1271
1272
35.8k
  auto next_char = is.peek();
1273
35.8k
  bool negate_value = false;
1274
1275
35.8k
  if (next_char != '-' && next_char != '0') {
1276
9.17k
    return ParseNormalFloat(is, negate_value, value);
1277
9.17k
  }
1278
1279
26.7k
  if (next_char == '-') {
1280
4.90k
    negate_value = true;
1281
4.90k
    is.get();
1282
4.90k
    next_char = is.peek();
1283
4.90k
  }
1284
1285
26.7k
  if (next_char == '0') {
1286
24.4k
    is.get();  // We may have to unget this.
1287
24.4k
    auto maybe_hex_start = is.peek();
1288
24.4k
    if (maybe_hex_start != 'x' && maybe_hex_start != 'X') {
1289
4.14k
      is.unget();
1290
4.14k
      return ParseNormalFloat(is, negate_value, value);
1291
20.3k
    } else {
1292
20.3k
      is.get();  // Throw away the 'x';
1293
20.3k
    }
1294
24.4k
  } else {
1295
2.26k
    return ParseNormalFloat(is, negate_value, value);
1296
2.26k
  }
1297
1298
  // This "looks" like a hex-float so treat it as one.
1299
20.3k
  bool seen_p = false;
1300
20.3k
  bool seen_dot = false;
1301
1302
  // The mantissa bits, without the most significant 1 bit, and with the
1303
  // the most recently read bits in the least significant positions.
1304
20.3k
  uint_type fraction = 0;
1305
  // The number of mantissa bits that have been read, including the leading 1
1306
  // bit that is not written into 'fraction'.
1307
20.3k
  uint_type fraction_index = 0;
1308
1309
  // TODO(dneto): handle overflow and underflow
1310
20.3k
  int_type exponent = HF::exponent_bias;
1311
1312
  // Strip off leading zeros so we don't have to special-case them later.
1313
53.0k
  while ((next_char = is.peek()) == '0') {
1314
32.7k
    is.get();
1315
32.7k
  }
1316
1317
  // Does the mantissa, as written, have non-zero digits to the left of
1318
  // the decimal point.  Assume no until proven otherwise.
1319
20.3k
  bool has_integer_part = false;
1320
20.3k
  bool bits_written = false;  // Stays false until we write a bit.
1321
1322
  // Scan the mantissa hex digits until we see a '.' or the 'p' that
1323
  // starts the exponent.
1324
161k
  while (!seen_p && !seen_dot) {
1325
    // Handle characters that are left of the fractional part.
1326
141k
    if (next_char == '.') {
1327
11.0k
      seen_dot = true;
1328
129k
    } else if (next_char == 'p') {
1329
9.16k
      seen_p = true;
1330
120k
    } else if (::isxdigit(next_char)) {
1331
      // We have stripped all leading zeroes and we have not yet seen a ".".
1332
120k
      has_integer_part = true;
1333
120k
      int number = get_nibble_from_character(next_char);
1334
603k
      for (int i = 0; i < 4; ++i, number <<= 1) {
1335
482k
        uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
1336
482k
        if (bits_written) {
1337
          // If we are here the bits represented belong in the fractional
1338
          // part of the float, and we have to adjust the exponent accordingly.
1339
465k
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1340
465k
                                                          fraction_index);
1341
          // Increment the fraction index. If the input has bizarrely many
1342
          // significant digits, then silently drop them.
1343
465k
          detail::saturated_inc(fraction_index);
1344
465k
          if (!detail::saturated_inc(exponent)) {
1345
            // Overflow failure
1346
2
            is.setstate(std::ios::failbit);
1347
2
            return is;
1348
2
          }
1349
465k
        }
1350
        // Since this updated after setting fraction bits, this effectively
1351
        // drops the leading 1 bit.
1352
482k
        bits_written |= write_bit != 0;
1353
482k
      }
1354
120k
    } else {
1355
      // We have not found our exponent yet, so we have to fail.
1356
122
      is.setstate(std::ios::failbit);
1357
122
      return is;
1358
122
    }
1359
140k
    is.get();
1360
140k
    next_char = is.peek();
1361
140k
  }
1362
1363
  // Finished reading the part preceding any '.' or 'p'.
1364
1365
20.1k
  bits_written = false;
1366
1.11M
  while (seen_dot && !seen_p) {
1367
    // Handle only fractional parts now.
1368
1.09M
    if (next_char == 'p') {
1369
10.9k
      seen_p = true;
1370
1.08M
    } else if (::isxdigit(next_char)) {
1371
1.08M
      int number = get_nibble_from_character(next_char);
1372
5.41M
      for (int i = 0; i < 4; ++i, number <<= 1) {
1373
4.32M
        uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
1374
4.32M
        bits_written |= write_bit != 0;
1375
4.32M
        if ((!has_integer_part) && !bits_written) {
1376
          // Handle modifying the exponent here this way we can handle
1377
          // an arbitrary number of hex values without overflowing our
1378
          // integer.
1379
1.79M
          if (!detail::saturated_dec(exponent)) {
1380
            // Overflow failure
1381
2
            is.setstate(std::ios::failbit);
1382
2
            return is;
1383
2
          }
1384
2.53M
        } else {
1385
2.53M
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1386
2.53M
                                                          fraction_index);
1387
          // Increment the fraction index. If the input has bizarrely many
1388
          // significant digits, then silently drop them.
1389
2.53M
          detail::saturated_inc(fraction_index);
1390
2.53M
        }
1391
4.32M
      }
1392
1.08M
    } else {
1393
      // We still have not found our 'p' exponent yet, so this is not a valid
1394
      // hex-float.
1395
98
      is.setstate(std::ios::failbit);
1396
98
      return is;
1397
98
    }
1398
1.09M
    is.get();
1399
1.09M
    next_char = is.peek();
1400
1.09M
  }
1401
1402
  // Finished reading the part preceding 'p'.
1403
  // In hex floats syntax, the binary exponent is required.
1404
1405
20.0k
  bool seen_exponent_sign = false;
1406
20.0k
  int8_t exponent_sign = 1;
1407
20.0k
  bool seen_written_exponent_digits = false;
1408
  // The magnitude of the exponent, as written, or the sentinel value to signal
1409
  // overflow.
1410
20.0k
  int_type written_exponent = 0;
1411
  // A sentinel value signalling overflow of the magnitude of the written
1412
  // exponent.  We'll assume that -written_exponent_overflow is valid for the
1413
  // type. Later we may add 1 or subtract 1 from the adjusted exponent, so leave
1414
  // room for an extra 1.
1415
20.0k
  const int_type written_exponent_overflow =
1416
20.0k
      std::numeric_limits<int_type>::max() - 1;
1417
137k
  while (true) {
1418
137k
    if (!seen_written_exponent_digits &&
1419
34.6k
        (next_char == '-' || next_char == '+')) {
1420
14.5k
      if (seen_exponent_sign) {
1421
4
        is.setstate(std::ios::failbit);
1422
4
        return is;
1423
4
      }
1424
14.5k
      seen_exponent_sign = true;
1425
14.5k
      exponent_sign = (next_char == '-') ? -1 : 1;
1426
122k
    } else if (::isdigit(next_char)) {
1427
102k
      seen_written_exponent_digits = true;
1428
      // Hex-floats express their exponent as decimal.
1429
102k
      int_type digit =
1430
102k
          static_cast<int_type>(static_cast<int_type>(next_char) - '0');
1431
102k
      if (written_exponent >= (written_exponent_overflow - digit) / 10) {
1432
        // The exponent is very big. Saturate rather than overflow the exponent.
1433
        // signed integer, which would be undefined behaviour.
1434
35.8k
        written_exponent = written_exponent_overflow;
1435
66.8k
      } else {
1436
66.8k
        written_exponent = static_cast<int_type>(
1437
66.8k
            static_cast<int_type>(written_exponent * 10) + digit);
1438
66.8k
      }
1439
102k
    } else {
1440
20.0k
      break;
1441
20.0k
    }
1442
117k
    is.get();
1443
117k
    next_char = is.peek();
1444
117k
  }
1445
20.0k
  if (!seen_written_exponent_digits) {
1446
    // Binary exponent had no digits.
1447
28
    is.setstate(std::ios::failbit);
1448
28
    return is;
1449
28
  }
1450
1451
20.0k
  written_exponent = static_cast<int_type>(written_exponent * exponent_sign);
1452
  // Now fold in the exponent bias into the written exponent, updating exponent.
1453
  // But avoid undefined behaviour that would result from overflowing int_type.
1454
20.0k
  if (written_exponent >= 0 && exponent >= 0) {
1455
    // Saturate up to written_exponent_overflow.
1456
8.74k
    if (written_exponent_overflow - exponent > written_exponent) {
1457
6.27k
      exponent = static_cast<int_type>(written_exponent + exponent);
1458
6.27k
    } else {
1459
2.46k
      exponent = written_exponent_overflow;
1460
2.46k
    }
1461
11.3k
  } else if (written_exponent < 0 && exponent < 0) {
1462
    // Saturate down to -written_exponent_overflow.
1463
5.26k
    if (written_exponent_overflow + exponent > -written_exponent) {
1464
3.71k
      exponent = static_cast<int_type>(written_exponent + exponent);
1465
3.71k
    } else {
1466
1.54k
      exponent = static_cast<int_type>(-written_exponent_overflow);
1467
1.54k
    }
1468
6.06k
  } else {
1469
    // They're of opposing sign, so it's safe to add.
1470
6.06k
    exponent = static_cast<int_type>(written_exponent + exponent);
1471
6.06k
  }
1472
1473
20.0k
  bool is_zero = (!has_integer_part) && (fraction == 0);
1474
20.0k
  if ((!has_integer_part) && !is_zero) {
1475
8.20k
    fraction = static_cast<uint_type>(fraction << 1);
1476
8.20k
    exponent = static_cast<int_type>(exponent - 1);
1477
11.8k
  } else if (is_zero) {
1478
4.06k
    exponent = 0;
1479
4.06k
  }
1480
1481
20.0k
  if (exponent <= 0 && !is_zero) {
1482
8.40k
    fraction = static_cast<uint_type>(fraction >> 1);
1483
8.40k
    fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
1484
8.40k
  }
1485
1486
20.0k
  fraction = (fraction >> HF::fraction_right_shift) & HF::fraction_encode_mask;
1487
1488
20.0k
  const int_type max_exponent =
1489
20.0k
      SetBits<uint_type, 0, HF::num_exponent_bits>::get;
1490
1491
  // Handle denorm numbers
1492
95.8k
  while (exponent < 0 && !is_zero) {
1493
75.7k
    fraction = static_cast<uint_type>(fraction >> 1);
1494
75.7k
    exponent = static_cast<int_type>(exponent + 1);
1495
1496
75.7k
    fraction &= HF::fraction_encode_mask;
1497
75.7k
    if (fraction == 0) {
1498
      // We have underflowed our fraction. We should clamp to zero.
1499
6.95k
      is_zero = true;
1500
6.95k
      exponent = 0;
1501
6.95k
    }
1502
75.7k
  }
1503
1504
  // We have overflowed so we should be inf/-inf.
1505
20.0k
  if (exponent > max_exponent) {
1506
5.16k
    exponent = max_exponent;
1507
5.16k
    fraction = 0;
1508
5.16k
  }
1509
1510
20.0k
  uint_type output_bits = static_cast<uint_type>(
1511
20.0k
      static_cast<uint_type>(negate_value ? 1 : 0) << HF::top_bit_left_shift);
1512
20.0k
  output_bits |= fraction;
1513
1514
20.0k
  uint_type shifted_exponent = static_cast<uint_type>(
1515
20.0k
      static_cast<uint_type>(exponent << HF::exponent_left_shift) &
1516
20.0k
      HF::exponent_mask);
1517
20.0k
  output_bits |= shifted_exponent;
1518
1519
20.0k
  T output_float(output_bits);
1520
20.0k
  value.set_value(output_float);
1521
1522
20.0k
  return is;
1523
20.0k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::operator>><spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<float>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<float> > >&)
Line
Count
Source
1258
26.7k
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
1259
26.7k
  using HF = HexFloat<T, Traits>;
1260
26.7k
  using uint_type = typename HF::uint_type;
1261
26.7k
  using int_type = typename HF::int_type;
1262
1263
26.7k
  value.set_value(static_cast<typename HF::native_type>(0.f));
1264
1265
26.7k
  if (is.flags() & std::ios::skipws) {
1266
    // If the user wants to skip whitespace , then we should obey that.
1267
27.8k
    while (std::isspace(is.peek())) {
1268
1.06k
      is.get();
1269
1.06k
    }
1270
26.7k
  }
1271
1272
26.7k
  auto next_char = is.peek();
1273
26.7k
  bool negate_value = false;
1274
1275
26.7k
  if (next_char != '-' && next_char != '0') {
1276
7.03k
    return ParseNormalFloat(is, negate_value, value);
1277
7.03k
  }
1278
1279
19.7k
  if (next_char == '-') {
1280
2.97k
    negate_value = true;
1281
2.97k
    is.get();
1282
2.97k
    next_char = is.peek();
1283
2.97k
  }
1284
1285
19.7k
  if (next_char == '0') {
1286
17.7k
    is.get();  // We may have to unget this.
1287
17.7k
    auto maybe_hex_start = is.peek();
1288
17.7k
    if (maybe_hex_start != 'x' && maybe_hex_start != 'X') {
1289
1.80k
      is.unget();
1290
1.80k
      return ParseNormalFloat(is, negate_value, value);
1291
15.9k
    } else {
1292
15.9k
      is.get();  // Throw away the 'x';
1293
15.9k
    }
1294
17.7k
  } else {
1295
1.91k
    return ParseNormalFloat(is, negate_value, value);
1296
1.91k
  }
1297
1298
  // This "looks" like a hex-float so treat it as one.
1299
15.9k
  bool seen_p = false;
1300
15.9k
  bool seen_dot = false;
1301
1302
  // The mantissa bits, without the most significant 1 bit, and with the
1303
  // the most recently read bits in the least significant positions.
1304
15.9k
  uint_type fraction = 0;
1305
  // The number of mantissa bits that have been read, including the leading 1
1306
  // bit that is not written into 'fraction'.
1307
15.9k
  uint_type fraction_index = 0;
1308
1309
  // TODO(dneto): handle overflow and underflow
1310
15.9k
  int_type exponent = HF::exponent_bias;
1311
1312
  // Strip off leading zeros so we don't have to special-case them later.
1313
24.8k
  while ((next_char = is.peek()) == '0') {
1314
8.82k
    is.get();
1315
8.82k
  }
1316
1317
  // Does the mantissa, as written, have non-zero digits to the left of
1318
  // the decimal point.  Assume no until proven otherwise.
1319
15.9k
  bool has_integer_part = false;
1320
15.9k
  bool bits_written = false;  // Stays false until we write a bit.
1321
1322
  // Scan the mantissa hex digits until we see a '.' or the 'p' that
1323
  // starts the exponent.
1324
5.66M
  while (!seen_p && !seen_dot) {
1325
    // Handle characters that are left of the fractional part.
1326
5.65M
    if (next_char == '.') {
1327
15.1k
      seen_dot = true;
1328
5.63M
    } else if (next_char == 'p') {
1329
806
      seen_p = true;
1330
5.63M
    } else if (::isxdigit(next_char)) {
1331
      // We have stripped all leading zeroes and we have not yet seen a ".".
1332
5.63M
      has_integer_part = true;
1333
5.63M
      int number = get_nibble_from_character(next_char);
1334
28.1M
      for (int i = 0; i < 4; ++i, number <<= 1) {
1335
22.5M
        uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
1336
22.5M
        if (bits_written) {
1337
          // If we are here the bits represented belong in the fractional
1338
          // part of the float, and we have to adjust the exponent accordingly.
1339
22.5M
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1340
22.5M
                                                          fraction_index);
1341
          // Increment the fraction index. If the input has bizarrely many
1342
          // significant digits, then silently drop them.
1343
22.5M
          detail::saturated_inc(fraction_index);
1344
22.5M
          if (!detail::saturated_inc(exponent)) {
1345
            // Overflow failure
1346
0
            is.setstate(std::ios::failbit);
1347
0
            return is;
1348
0
          }
1349
22.5M
        }
1350
        // Since this updated after setting fraction bits, this effectively
1351
        // drops the leading 1 bit.
1352
22.5M
        bits_written |= write_bit != 0;
1353
22.5M
      }
1354
5.63M
    } else {
1355
      // We have not found our exponent yet, so we have to fail.
1356
50
      is.setstate(std::ios::failbit);
1357
50
      return is;
1358
50
    }
1359
5.65M
    is.get();
1360
5.65M
    next_char = is.peek();
1361
5.65M
  }
1362
1363
  // Finished reading the part preceding any '.' or 'p'.
1364
1365
15.9k
  bits_written = false;
1366
6.02M
  while (seen_dot && !seen_p) {
1367
    // Handle only fractional parts now.
1368
6.00M
    if (next_char == 'p') {
1369
14.9k
      seen_p = true;
1370
5.99M
    } else if (::isxdigit(next_char)) {
1371
5.99M
      int number = get_nibble_from_character(next_char);
1372
29.9M
      for (int i = 0; i < 4; ++i, number <<= 1) {
1373
23.9M
        uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
1374
23.9M
        bits_written |= write_bit != 0;
1375
23.9M
        if ((!has_integer_part) && !bits_written) {
1376
          // Handle modifying the exponent here this way we can handle
1377
          // an arbitrary number of hex values without overflowing our
1378
          // integer.
1379
18.7M
          if (!detail::saturated_dec(exponent)) {
1380
            // Overflow failure
1381
0
            is.setstate(std::ios::failbit);
1382
0
            return is;
1383
0
          }
1384
18.7M
        } else {
1385
5.22M
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1386
5.22M
                                                          fraction_index);
1387
          // Increment the fraction index. If the input has bizarrely many
1388
          // significant digits, then silently drop them.
1389
5.22M
          detail::saturated_inc(fraction_index);
1390
5.22M
        }
1391
23.9M
      }
1392
5.99M
    } else {
1393
      // We still have not found our 'p' exponent yet, so this is not a valid
1394
      // hex-float.
1395
236
      is.setstate(std::ios::failbit);
1396
236
      return is;
1397
236
    }
1398
6.00M
    is.get();
1399
6.00M
    next_char = is.peek();
1400
6.00M
  }
1401
1402
  // Finished reading the part preceding 'p'.
1403
  // In hex floats syntax, the binary exponent is required.
1404
1405
15.7k
  bool seen_exponent_sign = false;
1406
15.7k
  int8_t exponent_sign = 1;
1407
15.7k
  bool seen_written_exponent_digits = false;
1408
  // The magnitude of the exponent, as written, or the sentinel value to signal
1409
  // overflow.
1410
15.7k
  int_type written_exponent = 0;
1411
  // A sentinel value signalling overflow of the magnitude of the written
1412
  // exponent.  We'll assume that -written_exponent_overflow is valid for the
1413
  // type. Later we may add 1 or subtract 1 from the adjusted exponent, so leave
1414
  // room for an extra 1.
1415
15.7k
  const int_type written_exponent_overflow =
1416
15.7k
      std::numeric_limits<int_type>::max() - 1;
1417
118k
  while (true) {
1418
118k
    if (!seen_written_exponent_digits &&
1419
25.3k
        (next_char == '-' || next_char == '+')) {
1420
9.66k
      if (seen_exponent_sign) {
1421
4
        is.setstate(std::ios::failbit);
1422
4
        return is;
1423
4
      }
1424
9.65k
      seen_exponent_sign = true;
1425
9.65k
      exponent_sign = (next_char == '-') ? -1 : 1;
1426
108k
    } else if (::isdigit(next_char)) {
1427
92.9k
      seen_written_exponent_digits = true;
1428
      // Hex-floats express their exponent as decimal.
1429
92.9k
      int_type digit =
1430
92.9k
          static_cast<int_type>(static_cast<int_type>(next_char) - '0');
1431
92.9k
      if (written_exponent >= (written_exponent_overflow - digit) / 10) {
1432
        // The exponent is very big. Saturate rather than overflow the exponent.
1433
        // signed integer, which would be undefined behaviour.
1434
9.99k
        written_exponent = written_exponent_overflow;
1435
82.9k
      } else {
1436
82.9k
        written_exponent = static_cast<int_type>(
1437
82.9k
            static_cast<int_type>(written_exponent * 10) + digit);
1438
82.9k
      }
1439
92.9k
    } else {
1440
15.7k
      break;
1441
15.7k
    }
1442
102k
    is.get();
1443
102k
    next_char = is.peek();
1444
102k
  }
1445
15.7k
  if (!seen_written_exponent_digits) {
1446
    // Binary exponent had no digits.
1447
42
    is.setstate(std::ios::failbit);
1448
42
    return is;
1449
42
  }
1450
1451
15.6k
  written_exponent = static_cast<int_type>(written_exponent * exponent_sign);
1452
  // Now fold in the exponent bias into the written exponent, updating exponent.
1453
  // But avoid undefined behaviour that would result from overflowing int_type.
1454
15.6k
  if (written_exponent >= 0 && exponent >= 0) {
1455
    // Saturate up to written_exponent_overflow.
1456
9.36k
    if (written_exponent_overflow - exponent > written_exponent) {
1457
7.91k
      exponent = static_cast<int_type>(written_exponent + exponent);
1458
7.91k
    } else {
1459
1.44k
      exponent = written_exponent_overflow;
1460
1.44k
    }
1461
9.36k
  } else if (written_exponent < 0 && exponent < 0) {
1462
    // Saturate down to -written_exponent_overflow.
1463
1.01k
    if (written_exponent_overflow + exponent > -written_exponent) {
1464
782
      exponent = static_cast<int_type>(written_exponent + exponent);
1465
782
    } else {
1466
234
      exponent = static_cast<int_type>(-written_exponent_overflow);
1467
234
    }
1468
5.28k
  } else {
1469
    // They're of opposing sign, so it's safe to add.
1470
5.28k
    exponent = static_cast<int_type>(written_exponent + exponent);
1471
5.28k
  }
1472
1473
15.6k
  bool is_zero = (!has_integer_part) && (fraction == 0);
1474
15.6k
  if ((!has_integer_part) && !is_zero) {
1475
5.90k
    fraction = static_cast<uint_type>(fraction << 1);
1476
5.90k
    exponent = static_cast<int_type>(exponent - 1);
1477
9.75k
  } else if (is_zero) {
1478
5.06k
    exponent = 0;
1479
5.06k
  }
1480
1481
15.6k
  if (exponent <= 0 && !is_zero) {
1482
3.83k
    fraction = static_cast<uint_type>(fraction >> 1);
1483
3.83k
    fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
1484
3.83k
  }
1485
1486
15.6k
  fraction = (fraction >> HF::fraction_right_shift) & HF::fraction_encode_mask;
1487
1488
15.6k
  const int_type max_exponent =
1489
15.6k
      SetBits<uint_type, 0, HF::num_exponent_bits>::get;
1490
1491
  // Handle denorm numbers
1492
96.7k
  while (exponent < 0 && !is_zero) {
1493
81.1k
    fraction = static_cast<uint_type>(fraction >> 1);
1494
81.1k
    exponent = static_cast<int_type>(exponent + 1);
1495
1496
81.1k
    fraction &= HF::fraction_encode_mask;
1497
81.1k
    if (fraction == 0) {
1498
      // We have underflowed our fraction. We should clamp to zero.
1499
3.34k
      is_zero = true;
1500
3.34k
      exponent = 0;
1501
3.34k
    }
1502
81.1k
  }
1503
1504
  // We have overflowed so we should be inf/-inf.
1505
15.6k
  if (exponent > max_exponent) {
1506
2.18k
    exponent = max_exponent;
1507
2.18k
    fraction = 0;
1508
2.18k
  }
1509
1510
15.6k
  uint_type output_bits = static_cast<uint_type>(
1511
15.6k
      static_cast<uint_type>(negate_value ? 1 : 0) << HF::top_bit_left_shift);
1512
15.6k
  output_bits |= fraction;
1513
1514
15.6k
  uint_type shifted_exponent = static_cast<uint_type>(
1515
15.6k
      static_cast<uint_type>(exponent << HF::exponent_left_shift) &
1516
15.6k
      HF::exponent_mask);
1517
15.6k
  output_bits |= shifted_exponent;
1518
1519
15.6k
  T output_float(output_bits);
1520
15.6k
  value.set_value(output_float);
1521
1522
15.6k
  return is;
1523
15.7k
}
std::__1::basic_istream<char, std::__1::char_traits<char> >& spvtools::utils::operator>><spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >(std::__1::basic_istream<char, std::__1::char_traits<char> >&, spvtools::utils::HexFloat<spvtools::utils::FloatProxy<double>, spvtools::utils::HexFloatTraits<spvtools::utils::FloatProxy<double> > >&)
Line
Count
Source
1258
23.5k
std::istream& operator>>(std::istream& is, HexFloat<T, Traits>& value) {
1259
23.5k
  using HF = HexFloat<T, Traits>;
1260
23.5k
  using uint_type = typename HF::uint_type;
1261
23.5k
  using int_type = typename HF::int_type;
1262
1263
23.5k
  value.set_value(static_cast<typename HF::native_type>(0.f));
1264
1265
23.5k
  if (is.flags() & std::ios::skipws) {
1266
    // If the user wants to skip whitespace , then we should obey that.
1267
25.8k
    while (std::isspace(is.peek())) {
1268
2.30k
      is.get();
1269
2.30k
    }
1270
23.5k
  }
1271
1272
23.5k
  auto next_char = is.peek();
1273
23.5k
  bool negate_value = false;
1274
1275
23.5k
  if (next_char != '-' && next_char != '0') {
1276
1.54k
    return ParseNormalFloat(is, negate_value, value);
1277
1.54k
  }
1278
1279
22.0k
  if (next_char == '-') {
1280
2.28k
    negate_value = true;
1281
2.28k
    is.get();
1282
2.28k
    next_char = is.peek();
1283
2.28k
  }
1284
1285
22.0k
  if (next_char == '0') {
1286
20.7k
    is.get();  // We may have to unget this.
1287
20.7k
    auto maybe_hex_start = is.peek();
1288
20.7k
    if (maybe_hex_start != 'x' && maybe_hex_start != 'X') {
1289
2.42k
      is.unget();
1290
2.42k
      return ParseNormalFloat(is, negate_value, value);
1291
18.2k
    } else {
1292
18.2k
      is.get();  // Throw away the 'x';
1293
18.2k
    }
1294
20.7k
  } else {
1295
1.33k
    return ParseNormalFloat(is, negate_value, value);
1296
1.33k
  }
1297
1298
  // This "looks" like a hex-float so treat it as one.
1299
18.2k
  bool seen_p = false;
1300
18.2k
  bool seen_dot = false;
1301
1302
  // The mantissa bits, without the most significant 1 bit, and with the
1303
  // the most recently read bits in the least significant positions.
1304
18.2k
  uint_type fraction = 0;
1305
  // The number of mantissa bits that have been read, including the leading 1
1306
  // bit that is not written into 'fraction'.
1307
18.2k
  uint_type fraction_index = 0;
1308
1309
  // TODO(dneto): handle overflow and underflow
1310
18.2k
  int_type exponent = HF::exponent_bias;
1311
1312
  // Strip off leading zeros so we don't have to special-case them later.
1313
31.0k
  while ((next_char = is.peek()) == '0') {
1314
12.7k
    is.get();
1315
12.7k
  }
1316
1317
  // Does the mantissa, as written, have non-zero digits to the left of
1318
  // the decimal point.  Assume no until proven otherwise.
1319
18.2k
  bool has_integer_part = false;
1320
18.2k
  bool bits_written = false;  // Stays false until we write a bit.
1321
1322
  // Scan the mantissa hex digits until we see a '.' or the 'p' that
1323
  // starts the exponent.
1324
25.2M
  while (!seen_p && !seen_dot) {
1325
    // Handle characters that are left of the fractional part.
1326
25.2M
    if (next_char == '.') {
1327
8.44k
      seen_dot = true;
1328
25.1M
    } else if (next_char == 'p') {
1329
9.68k
      seen_p = true;
1330
25.1M
    } else if (::isxdigit(next_char)) {
1331
      // We have stripped all leading zeroes and we have not yet seen a ".".
1332
25.1M
      has_integer_part = true;
1333
25.1M
      int number = get_nibble_from_character(next_char);
1334
125M
      for (int i = 0; i < 4; ++i, number <<= 1) {
1335
100M
        uint_type write_bit = (number & 0x8) ? 0x1 : 0x0;
1336
100M
        if (bits_written) {
1337
          // If we are here the bits represented belong in the fractional
1338
          // part of the float, and we have to adjust the exponent accordingly.
1339
100M
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1340
100M
                                                          fraction_index);
1341
          // Increment the fraction index. If the input has bizarrely many
1342
          // significant digits, then silently drop them.
1343
100M
          detail::saturated_inc(fraction_index);
1344
100M
          if (!detail::saturated_inc(exponent)) {
1345
            // Overflow failure
1346
0
            is.setstate(std::ios::failbit);
1347
0
            return is;
1348
0
          }
1349
100M
        }
1350
        // Since this updated after setting fraction bits, this effectively
1351
        // drops the leading 1 bit.
1352
100M
        bits_written |= write_bit != 0;
1353
100M
      }
1354
25.1M
    } else {
1355
      // We have not found our exponent yet, so we have to fail.
1356
156
      is.setstate(std::ios::failbit);
1357
156
      return is;
1358
156
    }
1359
25.2M
    is.get();
1360
25.2M
    next_char = is.peek();
1361
25.2M
  }
1362
1363
  // Finished reading the part preceding any '.' or 'p'.
1364
1365
18.1k
  bits_written = false;
1366
7.58M
  while (seen_dot && !seen_p) {
1367
    // Handle only fractional parts now.
1368
7.57M
    if (next_char == 'p') {
1369
8.33k
      seen_p = true;
1370
7.56M
    } else if (::isxdigit(next_char)) {
1371
7.56M
      int number = get_nibble_from_character(next_char);
1372
37.8M
      for (int i = 0; i < 4; ++i, number <<= 1) {
1373
30.2M
        uint_type write_bit = (number & 0x8) ? 0x01 : 0x00;
1374
30.2M
        bits_written |= write_bit != 0;
1375
30.2M
        if ((!has_integer_part) && !bits_written) {
1376
          // Handle modifying the exponent here this way we can handle
1377
          // an arbitrary number of hex values without overflowing our
1378
          // integer.
1379
26.0M
          if (!detail::saturated_dec(exponent)) {
1380
            // Overflow failure
1381
0
            is.setstate(std::ios::failbit);
1382
0
            return is;
1383
0
          }
1384
26.0M
        } else {
1385
4.20M
          fraction = detail::set_nth_most_significant_bit(fraction, write_bit,
1386
4.20M
                                                          fraction_index);
1387
          // Increment the fraction index. If the input has bizarrely many
1388
          // significant digits, then silently drop them.
1389
4.20M
          detail::saturated_inc(fraction_index);
1390
4.20M
        }
1391
30.2M
      }
1392
7.56M
    } else {
1393
      // We still have not found our 'p' exponent yet, so this is not a valid
1394
      // hex-float.
1395
108
      is.setstate(std::ios::failbit);
1396
108
      return is;
1397
108
    }
1398
7.57M
    is.get();
1399
7.57M
    next_char = is.peek();
1400
7.57M
  }
1401
1402
  // Finished reading the part preceding 'p'.
1403
  // In hex floats syntax, the binary exponent is required.
1404
1405
18.0k
  bool seen_exponent_sign = false;
1406
18.0k
  int8_t exponent_sign = 1;
1407
18.0k
  bool seen_written_exponent_digits = false;
1408
  // The magnitude of the exponent, as written, or the sentinel value to signal
1409
  // overflow.
1410
18.0k
  int_type written_exponent = 0;
1411
  // A sentinel value signalling overflow of the magnitude of the written
1412
  // exponent.  We'll assume that -written_exponent_overflow is valid for the
1413
  // type. Later we may add 1 or subtract 1 from the adjusted exponent, so leave
1414
  // room for an extra 1.
1415
18.0k
  const int_type written_exponent_overflow =
1416
18.0k
      std::numeric_limits<int_type>::max() - 1;
1417
176k
  while (true) {
1418
176k
    if (!seen_written_exponent_digits &&
1419
29.3k
        (next_char == '-' || next_char == '+')) {
1420
11.3k
      if (seen_exponent_sign) {
1421
6
        is.setstate(std::ios::failbit);
1422
6
        return is;
1423
6
      }
1424
11.3k
      seen_exponent_sign = true;
1425
11.3k
      exponent_sign = (next_char == '-') ? -1 : 1;
1426
165k
    } else if (::isdigit(next_char)) {
1427
147k
      seen_written_exponent_digits = true;
1428
      // Hex-floats express their exponent as decimal.
1429
147k
      int_type digit =
1430
147k
          static_cast<int_type>(static_cast<int_type>(next_char) - '0');
1431
147k
      if (written_exponent >= (written_exponent_overflow - digit) / 10) {
1432
        // The exponent is very big. Saturate rather than overflow the exponent.
1433
        // signed integer, which would be undefined behaviour.
1434
7.74k
        written_exponent = written_exponent_overflow;
1435
139k
      } else {
1436
139k
        written_exponent = static_cast<int_type>(
1437
139k
            static_cast<int_type>(written_exponent * 10) + digit);
1438
139k
      }
1439
147k
    } else {
1440
18.0k
      break;
1441
18.0k
    }
1442
158k
    is.get();
1443
158k
    next_char = is.peek();
1444
158k
  }
1445
18.0k
  if (!seen_written_exponent_digits) {
1446
    // Binary exponent had no digits.
1447
30
    is.setstate(std::ios::failbit);
1448
30
    return is;
1449
30
  }
1450
1451
17.9k
  written_exponent = static_cast<int_type>(written_exponent * exponent_sign);
1452
  // Now fold in the exponent bias into the written exponent, updating exponent.
1453
  // But avoid undefined behaviour that would result from overflowing int_type.
1454
17.9k
  if (written_exponent >= 0 && exponent >= 0) {
1455
    // Saturate up to written_exponent_overflow.
1456
10.2k
    if (written_exponent_overflow - exponent > written_exponent) {
1457
8.12k
      exponent = static_cast<int_type>(written_exponent + exponent);
1458
8.12k
    } else {
1459
2.13k
      exponent = written_exponent_overflow;
1460
2.13k
    }
1461
10.2k
  } else if (written_exponent < 0 && exponent < 0) {
1462
    // Saturate down to -written_exponent_overflow.
1463
707
    if (written_exponent_overflow + exponent > -written_exponent) {
1464
507
      exponent = static_cast<int_type>(written_exponent + exponent);
1465
507
    } else {
1466
200
      exponent = static_cast<int_type>(-written_exponent_overflow);
1467
200
    }
1468
7.02k
  } else {
1469
    // They're of opposing sign, so it's safe to add.
1470
7.02k
    exponent = static_cast<int_type>(written_exponent + exponent);
1471
7.02k
  }
1472
1473
17.9k
  bool is_zero = (!has_integer_part) && (fraction == 0);
1474
17.9k
  if ((!has_integer_part) && !is_zero) {
1475
6.40k
    fraction = static_cast<uint_type>(fraction << 1);
1476
6.40k
    exponent = static_cast<int_type>(exponent - 1);
1477
11.5k
  } else if (is_zero) {
1478
4.75k
    exponent = 0;
1479
4.75k
  }
1480
1481
17.9k
  if (exponent <= 0 && !is_zero) {
1482
2.03k
    fraction = static_cast<uint_type>(fraction >> 1);
1483
2.03k
    fraction |= static_cast<uint_type>(1) << HF::top_bit_left_shift;
1484
2.03k
  }
1485
1486
17.9k
  fraction = (fraction >> HF::fraction_right_shift) & HF::fraction_encode_mask;
1487
1488
17.9k
  const int_type max_exponent =
1489
17.9k
      SetBits<uint_type, 0, HF::num_exponent_bits>::get;
1490
1491
  // Handle denorm numbers
1492
114k
  while (exponent < 0 && !is_zero) {
1493
96.0k
    fraction = static_cast<uint_type>(fraction >> 1);
1494
96.0k
    exponent = static_cast<int_type>(exponent + 1);
1495
1496
96.0k
    fraction &= HF::fraction_encode_mask;
1497
96.0k
    if (fraction == 0) {
1498
      // We have underflowed our fraction. We should clamp to zero.
1499
1.71k
      is_zero = true;
1500
1.71k
      exponent = 0;
1501
1.71k
    }
1502
96.0k
  }
1503
1504
  // We have overflowed so we should be inf/-inf.
1505
17.9k
  if (exponent > max_exponent) {
1506
1.30k
    exponent = max_exponent;
1507
1.30k
    fraction = 0;
1508
1.30k
  }
1509
1510
17.9k
  uint_type output_bits = static_cast<uint_type>(
1511
17.9k
      static_cast<uint_type>(negate_value ? 1 : 0) << HF::top_bit_left_shift);
1512
17.9k
  output_bits |= fraction;
1513
1514
17.9k
  uint_type shifted_exponent = static_cast<uint_type>(
1515
17.9k
      static_cast<uint_type>(exponent << HF::exponent_left_shift) &
1516
17.9k
      HF::exponent_mask);
1517
17.9k
  output_bits |= shifted_exponent;
1518
1519
17.9k
  T output_float(output_bits);
1520
17.9k
  value.set_value(output_float);
1521
1522
17.9k
  return is;
1523
18.0k
}
1524
1525
// Writes a FloatProxy value to a stream.
1526
// Zero and normal numbers are printed in the usual notation, but with
1527
// enough digits to fully reproduce the value.  Other values (subnormal,
1528
// NaN, and infinity) are printed as a hex float.
1529
template <typename T>
1530
332k
std::ostream& operator<<(std::ostream& os, const FloatProxy<T>& value) {
1531
332k
  auto float_val = value.getAsFloat();
1532
332k
  switch (std::fpclassify(float_val)) {
1533
24.8k
    case FP_ZERO:
1534
176k
    case FP_NORMAL: {
1535
176k
      auto saved_precision = os.precision();
1536
176k
      os.precision(std::numeric_limits<T>::max_digits10);
1537
176k
      os << float_val;
1538
176k
      os.precision(saved_precision);
1539
176k
    } break;
1540
156k
    default:
1541
156k
      os << HexFloat<FloatProxy<T>>(value);
1542
156k
      break;
1543
332k
  }
1544
332k
  return os;
1545
332k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& spvtools::utils::operator<< <float>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, spvtools::utils::FloatProxy<float> const&)
Line
Count
Source
1530
305k
std::ostream& operator<<(std::ostream& os, const FloatProxy<T>& value) {
1531
305k
  auto float_val = value.getAsFloat();
1532
305k
  switch (std::fpclassify(float_val)) {
1533
24.5k
    case FP_ZERO:
1534
175k
    case FP_NORMAL: {
1535
175k
      auto saved_precision = os.precision();
1536
175k
      os.precision(std::numeric_limits<T>::max_digits10);
1537
175k
      os << float_val;
1538
175k
      os.precision(saved_precision);
1539
175k
    } break;
1540
130k
    default:
1541
130k
      os << HexFloat<FloatProxy<T>>(value);
1542
130k
      break;
1543
305k
  }
1544
305k
  return os;
1545
305k
}
std::__1::basic_ostream<char, std::__1::char_traits<char> >& spvtools::utils::operator<< <double>(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, spvtools::utils::FloatProxy<double> const&)
Line
Count
Source
1530
26.3k
std::ostream& operator<<(std::ostream& os, const FloatProxy<T>& value) {
1531
26.3k
  auto float_val = value.getAsFloat();
1532
26.3k
  switch (std::fpclassify(float_val)) {
1533
351
    case FP_ZERO:
1534
981
    case FP_NORMAL: {
1535
981
      auto saved_precision = os.precision();
1536
981
      os.precision(std::numeric_limits<T>::max_digits10);
1537
981
      os << float_val;
1538
981
      os.precision(saved_precision);
1539
981
    } break;
1540
25.3k
    default:
1541
25.3k
      os << HexFloat<FloatProxy<T>>(value);
1542
25.3k
      break;
1543
26.3k
  }
1544
26.3k
  return os;
1545
26.3k
}
1546
1547
template <>
1548
inline std::ostream& operator<<<Float16>(std::ostream& os,
1549
124k
                                         const FloatProxy<Float16>& value) {
1550
124k
  os << HexFloat<FloatProxy<Float16>>(value);
1551
124k
  return os;
1552
124k
}
1553
1554
template <>
1555
inline std::ostream& operator<< <BFloat16>(std::ostream& os,
1556
94.4k
                                           const FloatProxy<BFloat16>& value) {
1557
94.4k
  os << HexFloat<FloatProxy<BFloat16>>(value);
1558
94.4k
  return os;
1559
94.4k
}
1560
1561
template <>
1562
inline std::ostream& operator<< <Float8_E4M3>(
1563
77.7k
    std::ostream& os, const FloatProxy<Float8_E4M3>& value) {
1564
77.7k
  os << HexFloat<FloatProxy<Float8_E4M3>>(value);
1565
77.7k
  return os;
1566
77.7k
}
1567
1568
template <>
1569
inline std::ostream& operator<< <Float8_E5M2>(
1570
58.6k
    std::ostream& os, const FloatProxy<Float8_E5M2>& value) {
1571
58.6k
  os << HexFloat<FloatProxy<Float8_E5M2>>(value);
1572
58.6k
  return os;
1573
58.6k
}
1574
1575
}  // namespace utils
1576
}  // namespace spvtools
1577
1578
#endif  // SOURCE_UTIL_HEX_FLOAT_H_