1 // Copyright 2015, VIXL authors
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of ARM Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #ifndef VIXL_UTILS_H
28 #define VIXL_UTILS_H
29
30 #include "mozilla/FloatingPoint.h"
31
32 #include <cmath>
33 #include <cstring>
34 #include <limits>
35 #include <vector>
36
37 #include "jit/arm64/vixl/CompilerIntrinsics-vixl.h"
38 #include "jit/arm64/vixl/Globals-vixl.h"
39
40 namespace vixl {
41
42 // Macros for compile-time format checking.
43 #if GCC_VERSION_OR_NEWER(4, 4, 0)
44 #define PRINTF_CHECK(format_index, varargs_index) \
45 __attribute__((format(gnu_printf, format_index, varargs_index)))
46 #else
47 #define PRINTF_CHECK(format_index, varargs_index)
48 #endif
49
50 #ifdef __GNUC__
51 #define VIXL_HAS_DEPRECATED_WITH_MSG
52 #elif defined(__clang__)
53 #ifdef __has_extension
54 #define VIXL_HAS_DEPRECATED_WITH_MSG
55 #endif
56 #endif
57
58 #ifdef VIXL_HAS_DEPRECATED_WITH_MSG
59 #define VIXL_DEPRECATED(replaced_by, declarator) \
60 __attribute__((deprecated("Use \"" replaced_by "\" instead"))) declarator
61 #else
62 #define VIXL_DEPRECATED(replaced_by, declarator) declarator
63 #endif
64
65 #ifdef VIXL_DEBUG
66 #define VIXL_UNREACHABLE_OR_FALLTHROUGH() VIXL_UNREACHABLE()
67 #else
68 #define VIXL_UNREACHABLE_OR_FALLTHROUGH() VIXL_FALLTHROUGH()
69 #endif
70
71 template <typename T, size_t n>
ArrayLength(const T (&)[n])72 size_t ArrayLength(const T (&)[n]) {
73 return n;
74 }
75
76 // Check number width.
77 // TODO: Refactor these using templates.
IsIntN(unsigned n,uint32_t x)78 inline bool IsIntN(unsigned n, uint32_t x) {
79 VIXL_ASSERT((0 < n) && (n < 32));
80 uint32_t limit = UINT32_C(1) << (n - 1);
81 return x < limit;
82 }
IsIntN(unsigned n,int32_t x)83 inline bool IsIntN(unsigned n, int32_t x) {
84 VIXL_ASSERT((0 < n) && (n < 32));
85 int32_t limit = INT32_C(1) << (n - 1);
86 return (-limit <= x) && (x < limit);
87 }
IsIntN(unsigned n,uint64_t x)88 inline bool IsIntN(unsigned n, uint64_t x) {
89 VIXL_ASSERT((0 < n) && (n < 64));
90 uint64_t limit = UINT64_C(1) << (n - 1);
91 return x < limit;
92 }
IsIntN(unsigned n,int64_t x)93 inline bool IsIntN(unsigned n, int64_t x) {
94 VIXL_ASSERT((0 < n) && (n < 64));
95 int64_t limit = INT64_C(1) << (n - 1);
96 return (-limit <= x) && (x < limit);
97 }
is_intn(unsigned n,int64_t x)98 VIXL_DEPRECATED("IsIntN", inline bool is_intn(unsigned n, int64_t x)) {
99 return IsIntN(n, x);
100 }
101
IsUintN(unsigned n,uint32_t x)102 inline bool IsUintN(unsigned n, uint32_t x) {
103 VIXL_ASSERT((0 < n) && (n < 32));
104 return !(x >> n);
105 }
IsUintN(unsigned n,int32_t x)106 inline bool IsUintN(unsigned n, int32_t x) {
107 VIXL_ASSERT((0 < n) && (n < 32));
108 // Convert to an unsigned integer to avoid implementation-defined behavior.
109 return !(static_cast<uint32_t>(x) >> n);
110 }
IsUintN(unsigned n,uint64_t x)111 inline bool IsUintN(unsigned n, uint64_t x) {
112 VIXL_ASSERT((0 < n) && (n < 64));
113 return !(x >> n);
114 }
IsUintN(unsigned n,int64_t x)115 inline bool IsUintN(unsigned n, int64_t x) {
116 VIXL_ASSERT((0 < n) && (n < 64));
117 // Convert to an unsigned integer to avoid implementation-defined behavior.
118 return !(static_cast<uint64_t>(x) >> n);
119 }
is_uintn(unsigned n,int64_t x)120 VIXL_DEPRECATED("IsUintN", inline bool is_uintn(unsigned n, int64_t x)) {
121 return IsUintN(n, x);
122 }
123
TruncateToUintN(unsigned n,uint64_t x)124 inline uint64_t TruncateToUintN(unsigned n, uint64_t x) {
125 VIXL_ASSERT((0 < n) && (n < 64));
126 return static_cast<uint64_t>(x) & ((UINT64_C(1) << n) - 1);
127 }
128 VIXL_DEPRECATED("TruncateToUintN",
129 inline uint64_t truncate_to_intn(unsigned n, int64_t x)) {
130 return TruncateToUintN(n, x);
131 }
132
133 // clang-format off
134 #define INT_1_TO_32_LIST(V) \
135 V(1) V(2) V(3) V(4) V(5) V(6) V(7) V(8) \
136 V(9) V(10) V(11) V(12) V(13) V(14) V(15) V(16) \
137 V(17) V(18) V(19) V(20) V(21) V(22) V(23) V(24) \
138 V(25) V(26) V(27) V(28) V(29) V(30) V(31) V(32)
139
140 #define INT_33_TO_63_LIST(V) \
141 V(33) V(34) V(35) V(36) V(37) V(38) V(39) V(40) \
142 V(41) V(42) V(43) V(44) V(45) V(46) V(47) V(48) \
143 V(49) V(50) V(51) V(52) V(53) V(54) V(55) V(56) \
144 V(57) V(58) V(59) V(60) V(61) V(62) V(63)
145
146 #define INT_1_TO_63_LIST(V) INT_1_TO_32_LIST(V) INT_33_TO_63_LIST(V)
147
148 // clang-format on
149
150 #define DECLARE_IS_INT_N(N) \
151 inline bool IsInt##N(int64_t x) { return IsIntN(N, x); } \
152 VIXL_DEPRECATED("IsInt" #N, inline bool is_int##N(int64_t x)) { \
153 return IsIntN(N, x); \
154 }
155
156 #define DECLARE_IS_UINT_N(N) \
157 inline bool IsUint##N(int64_t x) { return IsUintN(N, x); } \
158 VIXL_DEPRECATED("IsUint" #N, inline bool is_uint##N(int64_t x)) { \
159 return IsUintN(N, x); \
160 }
161
162 #define DECLARE_TRUNCATE_TO_UINT_32(N) \
163 inline uint32_t TruncateToUint##N(uint64_t x) { \
164 return static_cast<uint32_t>(TruncateToUintN(N, x)); \
165 } \
166 VIXL_DEPRECATED("TruncateToUint" #N, \
167 inline uint32_t truncate_to_int##N(int64_t x)) { \
168 return TruncateToUint##N(x); \
169 }
170
171 INT_1_TO_63_LIST(DECLARE_IS_INT_N)
INT_1_TO_63_LIST(DECLARE_IS_UINT_N)172 INT_1_TO_63_LIST(DECLARE_IS_UINT_N)
173 INT_1_TO_32_LIST(DECLARE_TRUNCATE_TO_UINT_32)
174
175 #undef DECLARE_IS_INT_N
176 #undef DECLARE_IS_UINT_N
177 #undef DECLARE_TRUNCATE_TO_INT_N
178
179 // Bit field extraction.
180 inline uint64_t ExtractUnsignedBitfield64(int msb, int lsb, uint64_t x) {
181 VIXL_ASSERT((static_cast<size_t>(msb) < sizeof(x) * 8) && (lsb >= 0) &&
182 (msb >= lsb));
183 if ((msb == 63) && (lsb == 0)) return x;
184 return (x >> lsb) & ((static_cast<uint64_t>(1) << (1 + msb - lsb)) - 1);
185 }
186
187
ExtractUnsignedBitfield32(int msb,int lsb,uint32_t x)188 inline uint32_t ExtractUnsignedBitfield32(int msb, int lsb, uint32_t x) {
189 VIXL_ASSERT((static_cast<size_t>(msb) < sizeof(x) * 8) && (lsb >= 0) &&
190 (msb >= lsb));
191 return TruncateToUint32(ExtractUnsignedBitfield64(msb, lsb, x));
192 }
193
194
ExtractSignedBitfield64(int msb,int lsb,int64_t x)195 inline int64_t ExtractSignedBitfield64(int msb, int lsb, int64_t x) {
196 VIXL_ASSERT((static_cast<size_t>(msb) < sizeof(x) * 8) && (lsb >= 0) &&
197 (msb >= lsb));
198 uint64_t temp = ExtractUnsignedBitfield64(msb, lsb, x);
199 // If the highest extracted bit is set, sign extend.
200 if ((temp >> (msb - lsb)) == 1) {
201 temp |= ~UINT64_C(0) << (msb - lsb);
202 }
203 int64_t result;
204 memcpy(&result, &temp, sizeof(result));
205 return result;
206 }
207
208
ExtractSignedBitfield32(int msb,int lsb,int32_t x)209 inline int32_t ExtractSignedBitfield32(int msb, int lsb, int32_t x) {
210 VIXL_ASSERT((static_cast<size_t>(msb) < sizeof(x) * 8) && (lsb >= 0) &&
211 (msb >= lsb));
212 uint32_t temp = TruncateToUint32(ExtractSignedBitfield64(msb, lsb, x));
213 int32_t result;
214 memcpy(&result, &temp, sizeof(result));
215 return result;
216 }
217
218
RotateRight(uint64_t value,unsigned int rotate,unsigned int width)219 inline uint64_t RotateRight(uint64_t value,
220 unsigned int rotate,
221 unsigned int width) {
222 VIXL_ASSERT((width > 0) && (width <= 64));
223 uint64_t width_mask = ~UINT64_C(0) >> (64 - width);
224 rotate &= 63;
225 if (rotate > 0) {
226 value &= width_mask;
227 value = (value << (width - rotate)) | (value >> rotate);
228 }
229 return value & width_mask;
230 }
231
232
233 // Wrapper class for passing FP16 values through the assembler.
234 // This is purely to aid with type checking/casting.
235 class Float16 {
236 public:
237 explicit Float16(double dvalue);
Float16()238 Float16() : rawbits_(0x0) {}
239 friend uint16_t Float16ToRawbits(Float16 value);
240 friend Float16 RawbitsToFloat16(uint16_t bits);
241
242 protected:
243 uint16_t rawbits_;
244 };
245
246 // Floating point representation.
247 uint16_t Float16ToRawbits(Float16 value);
248
249
250 uint32_t FloatToRawbits(float value);
251 VIXL_DEPRECATED("FloatToRawbits",
252 inline uint32_t float_to_rawbits(float value)) {
253 return FloatToRawbits(value);
254 }
255
256 uint64_t DoubleToRawbits(double value);
257 VIXL_DEPRECATED("DoubleToRawbits",
258 inline uint64_t double_to_rawbits(double value)) {
259 return DoubleToRawbits(value);
260 }
261
262 Float16 RawbitsToFloat16(uint16_t bits);
263
264 float RawbitsToFloat(uint32_t bits);
265 VIXL_DEPRECATED("RawbitsToFloat",
rawbits_to_float(uint32_t bits)266 inline float rawbits_to_float(uint32_t bits)) {
267 return RawbitsToFloat(bits);
268 }
269
270 double RawbitsToDouble(uint64_t bits);
271 VIXL_DEPRECATED("RawbitsToDouble",
rawbits_to_double(uint64_t bits)272 inline double rawbits_to_double(uint64_t bits)) {
273 return RawbitsToDouble(bits);
274 }
275
276 namespace internal {
277
278 // Internal simulation class used solely by the simulator to
279 // provide an abstraction layer for any half-precision arithmetic.
280 class SimFloat16 : public Float16 {
281 public:
282 // TODO: We should investigate making this constructor explicit.
283 // This is currently difficult to do due to a number of templated
284 // functions in the simulator which rely on returning double values.
SimFloat16(double dvalue)285 SimFloat16(double dvalue) : Float16(dvalue) {} // NOLINT(runtime/explicit)
SimFloat16(Float16 f)286 SimFloat16(Float16 f) { // NOLINT(runtime/explicit)
287 this->rawbits_ = Float16ToRawbits(f);
288 }
SimFloat16()289 SimFloat16() : Float16() {}
290 SimFloat16 operator-() const;
291 SimFloat16 operator+(SimFloat16 rhs) const;
292 SimFloat16 operator-(SimFloat16 rhs) const;
293 SimFloat16 operator*(SimFloat16 rhs) const;
294 SimFloat16 operator/(SimFloat16 rhs) const;
295 bool operator<(SimFloat16 rhs) const;
296 bool operator>(SimFloat16 rhs) const;
297 bool operator==(SimFloat16 rhs) const;
298 bool operator!=(SimFloat16 rhs) const;
299 // This is necessary for conversions peformed in (macro asm) Fmov.
300 bool operator==(double rhs) const;
301 operator double() const;
302 };
303 } // namespace internal
304
305 uint32_t Float16Sign(internal::SimFloat16 value);
306
307 uint32_t Float16Exp(internal::SimFloat16 value);
308
309 uint32_t Float16Mantissa(internal::SimFloat16 value);
310
311 uint32_t FloatSign(float value);
312 VIXL_DEPRECATED("FloatSign", inline uint32_t float_sign(float value)) {
313 return FloatSign(value);
314 }
315
316 uint32_t FloatExp(float value);
317 VIXL_DEPRECATED("FloatExp", inline uint32_t float_exp(float value)) {
318 return FloatExp(value);
319 }
320
321 uint32_t FloatMantissa(float value);
322 VIXL_DEPRECATED("FloatMantissa", inline uint32_t float_mantissa(float value)) {
323 return FloatMantissa(value);
324 }
325
326 uint32_t DoubleSign(double value);
327 VIXL_DEPRECATED("DoubleSign", inline uint32_t double_sign(double value)) {
328 return DoubleSign(value);
329 }
330
331 uint32_t DoubleExp(double value);
332 VIXL_DEPRECATED("DoubleExp", inline uint32_t double_exp(double value)) {
333 return DoubleExp(value);
334 }
335
336 uint64_t DoubleMantissa(double value);
337 VIXL_DEPRECATED("DoubleMantissa",
338 inline uint64_t double_mantissa(double value)) {
339 return DoubleMantissa(value);
340 }
341
342 internal::SimFloat16 Float16Pack(uint16_t sign,
343 uint16_t exp,
344 uint16_t mantissa);
345
346 float FloatPack(uint32_t sign, uint32_t exp, uint32_t mantissa);
347 VIXL_DEPRECATED("FloatPack",
float_pack(uint32_t sign,uint32_t exp,uint32_t mantissa)348 inline float float_pack(uint32_t sign,
349 uint32_t exp,
350 uint32_t mantissa)) {
351 return FloatPack(sign, exp, mantissa);
352 }
353
354 double DoublePack(uint64_t sign, uint64_t exp, uint64_t mantissa);
355 VIXL_DEPRECATED("DoublePack",
double_pack(uint32_t sign,uint32_t exp,uint64_t mantissa)356 inline double double_pack(uint32_t sign,
357 uint32_t exp,
358 uint64_t mantissa)) {
359 return DoublePack(sign, exp, mantissa);
360 }
361
362 // An fpclassify() function for 16-bit half-precision floats.
363 int Float16Classify(Float16 value);
float16classify(uint16_t value)364 VIXL_DEPRECATED("Float16Classify", inline int float16classify(uint16_t value)) {
365 return Float16Classify(RawbitsToFloat16(value));
366 }
367
368 bool IsZero(Float16 value);
369
IsNaN(float value)370 inline bool IsNaN(float value) { return std::isnan(value); }
371
IsNaN(double value)372 inline bool IsNaN(double value) { return std::isnan(value); }
373
IsNaN(Float16 value)374 inline bool IsNaN(Float16 value) { return Float16Classify(value) == FP_NAN; }
375
IsInf(float value)376 inline bool IsInf(float value) { return std::isinf(value); }
377
IsInf(double value)378 inline bool IsInf(double value) { return std::isinf(value); }
379
IsInf(Float16 value)380 inline bool IsInf(Float16 value) {
381 return Float16Classify(value) == FP_INFINITE;
382 }
383
384
385 // NaN tests.
IsSignallingNaN(double num)386 inline bool IsSignallingNaN(double num) {
387 const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000);
388 uint64_t raw = DoubleToRawbits(num);
389 if (IsNaN(num) && ((raw & kFP64QuietNaNMask) == 0)) {
390 return true;
391 }
392 return false;
393 }
394
395
IsSignallingNaN(float num)396 inline bool IsSignallingNaN(float num) {
397 const uint32_t kFP32QuietNaNMask = 0x00400000;
398 uint32_t raw = FloatToRawbits(num);
399 if (IsNaN(num) && ((raw & kFP32QuietNaNMask) == 0)) {
400 return true;
401 }
402 return false;
403 }
404
405
IsSignallingNaN(Float16 num)406 inline bool IsSignallingNaN(Float16 num) {
407 const uint16_t kFP16QuietNaNMask = 0x0200;
408 return IsNaN(num) && ((Float16ToRawbits(num) & kFP16QuietNaNMask) == 0);
409 }
410
411
412 template <typename T>
IsQuietNaN(T num)413 inline bool IsQuietNaN(T num) {
414 return IsNaN(num) && !IsSignallingNaN(num);
415 }
416
417
418 // Convert the NaN in 'num' to a quiet NaN.
ToQuietNaN(double num)419 inline double ToQuietNaN(double num) {
420 const uint64_t kFP64QuietNaNMask = UINT64_C(0x0008000000000000);
421 VIXL_ASSERT(IsNaN(num));
422 return RawbitsToDouble(DoubleToRawbits(num) | kFP64QuietNaNMask);
423 }
424
425
ToQuietNaN(float num)426 inline float ToQuietNaN(float num) {
427 const uint32_t kFP32QuietNaNMask = 0x00400000;
428 VIXL_ASSERT(IsNaN(num));
429 return RawbitsToFloat(FloatToRawbits(num) | kFP32QuietNaNMask);
430 }
431
432
ToQuietNaN(internal::SimFloat16 num)433 inline internal::SimFloat16 ToQuietNaN(internal::SimFloat16 num) {
434 const uint16_t kFP16QuietNaNMask = 0x0200;
435 VIXL_ASSERT(IsNaN(num));
436 return internal::SimFloat16(
437 RawbitsToFloat16(Float16ToRawbits(num) | kFP16QuietNaNMask));
438 }
439
440
441 // Fused multiply-add.
FusedMultiplyAdd(double op1,double op2,double a)442 inline double FusedMultiplyAdd(double op1, double op2, double a) {
443 return fma(op1, op2, a);
444 }
445
446
FusedMultiplyAdd(float op1,float op2,float a)447 inline float FusedMultiplyAdd(float op1, float op2, float a) {
448 return fmaf(op1, op2, a);
449 }
450
451
LowestSetBit(uint64_t value)452 inline uint64_t LowestSetBit(uint64_t value) { return value & -value; }
453
454
455 template <typename T>
HighestSetBitPosition(T value)456 inline int HighestSetBitPosition(T value) {
457 VIXL_ASSERT(value != 0);
458 return (sizeof(value) * 8 - 1) - CountLeadingZeros(value);
459 }
460
461
462 template <typename V>
WhichPowerOf2(V value)463 inline int WhichPowerOf2(V value) {
464 VIXL_ASSERT(IsPowerOf2(value));
465 return CountTrailingZeros(value);
466 }
467
468
469 unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size);
470
471
472 int BitCount(uint64_t value);
473
474
475 template <typename T>
ReverseBits(T value)476 T ReverseBits(T value) {
477 VIXL_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
478 (sizeof(value) == 4) || (sizeof(value) == 8));
479 T result = 0;
480 for (unsigned i = 0; i < (sizeof(value) * 8); i++) {
481 result = (result << 1) | (value & 1);
482 value >>= 1;
483 }
484 return result;
485 }
486
487
488 template <typename T>
SignExtend(T val,int bitSize)489 inline T SignExtend(T val, int bitSize) {
490 VIXL_ASSERT(bitSize > 0);
491 T mask = (T(2) << (bitSize - 1)) - T(1);
492 val &= mask;
493 T sign_bits = -((val >> (bitSize - 1)) << bitSize);
494 val |= sign_bits;
495 return val;
496 }
497
498
499 template <typename T>
ReverseBytes(T value,int block_bytes_log2)500 T ReverseBytes(T value, int block_bytes_log2) {
501 VIXL_ASSERT((sizeof(value) == 4) || (sizeof(value) == 8));
502 VIXL_ASSERT((1U << block_bytes_log2) <= sizeof(value));
503 // Split the 64-bit value into an 8-bit array, where b[0] is the least
504 // significant byte, and b[7] is the most significant.
505 uint8_t bytes[8];
506 uint64_t mask = UINT64_C(0xff00000000000000);
507 for (int i = 7; i >= 0; i--) {
508 bytes[i] = (static_cast<uint64_t>(value) & mask) >> (i * 8);
509 mask >>= 8;
510 }
511
512 // Permutation tables for REV instructions.
513 // permute_table[0] is used by REV16_x, REV16_w
514 // permute_table[1] is used by REV32_x, REV_w
515 // permute_table[2] is used by REV_x
516 VIXL_ASSERT((0 < block_bytes_log2) && (block_bytes_log2 < 4));
517 static const uint8_t permute_table[3][8] = {{6, 7, 4, 5, 2, 3, 0, 1},
518 {4, 5, 6, 7, 0, 1, 2, 3},
519 {0, 1, 2, 3, 4, 5, 6, 7}};
520 uint64_t temp = 0;
521 for (int i = 0; i < 8; i++) {
522 temp <<= 8;
523 temp |= bytes[permute_table[block_bytes_log2 - 1][i]];
524 }
525
526 T result;
527 VIXL_STATIC_ASSERT(sizeof(result) <= sizeof(temp));
528 memcpy(&result, &temp, sizeof(result));
529 return result;
530 }
531
532 template <unsigned MULTIPLE, typename T>
IsMultiple(T value)533 inline bool IsMultiple(T value) {
534 VIXL_ASSERT(IsPowerOf2(MULTIPLE));
535 return (value & (MULTIPLE - 1)) == 0;
536 }
537
538 template <typename T>
IsMultiple(T value,unsigned multiple)539 inline bool IsMultiple(T value, unsigned multiple) {
540 VIXL_ASSERT(IsPowerOf2(multiple));
541 return (value & (multiple - 1)) == 0;
542 }
543
544 template <typename T>
IsAligned(T pointer,int alignment)545 inline bool IsAligned(T pointer, int alignment) {
546 VIXL_ASSERT(IsPowerOf2(alignment));
547 return (pointer & (alignment - 1)) == 0;
548 }
549
550 // Pointer alignment
551 // TODO: rename/refactor to make it specific to instructions.
552 template <unsigned ALIGN, typename T>
IsAligned(T pointer)553 inline bool IsAligned(T pointer) {
554 VIXL_ASSERT(sizeof(pointer) == sizeof(intptr_t)); // NOLINT(runtime/sizeof)
555 // Use C-style casts to get static_cast behaviour for integral types (T), and
556 // reinterpret_cast behaviour for other types.
557 return IsAligned((intptr_t)(pointer), ALIGN);
558 }
559
560 template <typename T>
IsWordAligned(T pointer)561 bool IsWordAligned(T pointer) {
562 return IsAligned<4>(pointer);
563 }
564
565 // Increment a pointer until it has the specified alignment. The alignment must
566 // be a power of two.
567 template <class T>
AlignUp(T pointer,typename Unsigned<sizeof (T)* kBitsPerByte>::type alignment)568 T AlignUp(T pointer,
569 typename Unsigned<sizeof(T) * kBitsPerByte>::type alignment) {
570 VIXL_ASSERT(IsPowerOf2(alignment));
571 // Use C-style casts to get static_cast behaviour for integral types (T), and
572 // reinterpret_cast behaviour for other types.
573
574 typename Unsigned<sizeof(T)* kBitsPerByte>::type pointer_raw =
575 (typename Unsigned<sizeof(T) * kBitsPerByte>::type)pointer;
576 VIXL_STATIC_ASSERT(sizeof(pointer) <= sizeof(pointer_raw));
577
578 size_t mask = alignment - 1;
579 T result = (T)((pointer_raw + mask) & ~mask);
580 VIXL_ASSERT(result >= pointer);
581
582 return result;
583 }
584
585 // Decrement a pointer until it has the specified alignment. The alignment must
586 // be a power of two.
587 template <class T>
AlignDown(T pointer,typename Unsigned<sizeof (T)* kBitsPerByte>::type alignment)588 T AlignDown(T pointer,
589 typename Unsigned<sizeof(T) * kBitsPerByte>::type alignment) {
590 VIXL_ASSERT(IsPowerOf2(alignment));
591 // Use C-style casts to get static_cast behaviour for integral types (T), and
592 // reinterpret_cast behaviour for other types.
593
594 typename Unsigned<sizeof(T)* kBitsPerByte>::type pointer_raw =
595 (typename Unsigned<sizeof(T) * kBitsPerByte>::type)pointer;
596 VIXL_STATIC_ASSERT(sizeof(pointer) <= sizeof(pointer_raw));
597
598 size_t mask = alignment - 1;
599 return (T)(pointer_raw & ~mask);
600 }
601
602
603 template <typename T>
ExtractBit(T value,unsigned bit)604 inline T ExtractBit(T value, unsigned bit) {
605 return (value >> bit) & T(1);
606 }
607
608 template <typename Ts, typename Td>
ExtractBits(Ts value,int least_significant_bit,Td mask)609 inline Td ExtractBits(Ts value, int least_significant_bit, Td mask) {
610 return Td((value >> least_significant_bit) & Ts(mask));
611 }
612
613 template <typename Ts, typename Td>
AssignBit(Td & dst,int bit,Ts value)614 inline void AssignBit(Td& dst, // NOLINT(runtime/references)
615 int bit,
616 Ts value) {
617 VIXL_ASSERT((value == Ts(0)) || (value == Ts(1)));
618 VIXL_ASSERT(bit >= 0);
619 VIXL_ASSERT(bit < static_cast<int>(sizeof(Td) * 8));
620 Td mask(1);
621 dst &= ~(mask << bit);
622 dst |= Td(value) << bit;
623 }
624
625 template <typename Td, typename Ts>
AssignBits(Td & dst,int least_significant_bit,Ts mask,Ts value)626 inline void AssignBits(Td& dst, // NOLINT(runtime/references)
627 int least_significant_bit,
628 Ts mask,
629 Ts value) {
630 VIXL_ASSERT(least_significant_bit >= 0);
631 VIXL_ASSERT(least_significant_bit < static_cast<int>(sizeof(Td) * 8));
632 VIXL_ASSERT(((Td(mask) << least_significant_bit) >> least_significant_bit) ==
633 Td(mask));
634 VIXL_ASSERT((value & mask) == value);
635 dst &= ~(Td(mask) << least_significant_bit);
636 dst |= Td(value) << least_significant_bit;
637 }
638
639 class VFP {
640 public:
FP32ToImm8(float imm)641 static uint32_t FP32ToImm8(float imm) {
642 // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
643 uint32_t bits = FloatToRawbits(imm);
644 // bit7: a000.0000
645 uint32_t bit7 = ((bits >> 31) & 0x1) << 7;
646 // bit6: 0b00.0000
647 uint32_t bit6 = ((bits >> 29) & 0x1) << 6;
648 // bit5_to_0: 00cd.efgh
649 uint32_t bit5_to_0 = (bits >> 19) & 0x3f;
650 return static_cast<uint32_t>(bit7 | bit6 | bit5_to_0);
651 }
FP64ToImm8(double imm)652 static uint32_t FP64ToImm8(double imm) {
653 // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
654 // 0000.0000.0000.0000.0000.0000.0000.0000
655 uint64_t bits = DoubleToRawbits(imm);
656 // bit7: a000.0000
657 uint64_t bit7 = ((bits >> 63) & 0x1) << 7;
658 // bit6: 0b00.0000
659 uint64_t bit6 = ((bits >> 61) & 0x1) << 6;
660 // bit5_to_0: 00cd.efgh
661 uint64_t bit5_to_0 = (bits >> 48) & 0x3f;
662
663 return static_cast<uint32_t>(bit7 | bit6 | bit5_to_0);
664 }
Imm8ToFP32(uint32_t imm8)665 static float Imm8ToFP32(uint32_t imm8) {
666 // Imm8: abcdefgh (8 bits)
667 // Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits)
668 // where B is b ^ 1
669 uint32_t bits = imm8;
670 uint32_t bit7 = (bits >> 7) & 0x1;
671 uint32_t bit6 = (bits >> 6) & 0x1;
672 uint32_t bit5_to_0 = bits & 0x3f;
673 uint32_t result = (bit7 << 31) | ((32 - bit6) << 25) | (bit5_to_0 << 19);
674
675 return RawbitsToFloat(result);
676 }
Imm8ToFP64(uint32_t imm8)677 static double Imm8ToFP64(uint32_t imm8) {
678 // Imm8: abcdefgh (8 bits)
679 // Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
680 // 0000.0000.0000.0000.0000.0000.0000.0000 (64 bits)
681 // where B is b ^ 1
682 uint32_t bits = imm8;
683 uint64_t bit7 = (bits >> 7) & 0x1;
684 uint64_t bit6 = (bits >> 6) & 0x1;
685 uint64_t bit5_to_0 = bits & 0x3f;
686 uint64_t result = (bit7 << 63) | ((256 - bit6) << 54) | (bit5_to_0 << 48);
687 return RawbitsToDouble(result);
688 }
IsImmFP32(float imm)689 static bool IsImmFP32(float imm) {
690 // Valid values will have the form:
691 // aBbb.bbbc.defg.h000.0000.0000.0000.0000
692 uint32_t bits = FloatToRawbits(imm);
693 // bits[19..0] are cleared.
694 if ((bits & 0x7ffff) != 0) {
695 return false;
696 }
697
698
699 // bits[29..25] are all set or all cleared.
700 uint32_t b_pattern = (bits >> 16) & 0x3e00;
701 if (b_pattern != 0 && b_pattern != 0x3e00) {
702 return false;
703 }
704 // bit[30] and bit[29] are opposite.
705 if (((bits ^ (bits << 1)) & 0x40000000) == 0) {
706 return false;
707 }
708 return true;
709 }
IsImmFP64(double imm)710 static bool IsImmFP64(double imm) {
711 // Valid values will have the form:
712 // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
713 // 0000.0000.0000.0000.0000.0000.0000.0000
714 uint64_t bits = DoubleToRawbits(imm);
715 // bits[47..0] are cleared.
716 if ((bits & 0x0000ffffffffffff) != 0) {
717 return false;
718 }
719 // bits[61..54] are all set or all cleared.
720 uint32_t b_pattern = (bits >> 48) & 0x3fc0;
721 if ((b_pattern != 0) && (b_pattern != 0x3fc0)) {
722 return false;
723 }
724 // bit[62] and bit[61] are opposite.
725 if (((bits ^ (bits << 1)) & (UINT64_C(1) << 62)) == 0) {
726 return false;
727 }
728 return true;
729 }
730 };
731
732 class BitField {
733 // ForEachBitHelper is a functor that will call
734 // bool ForEachBitHelper::execute(ElementType id) const
735 // and expects a boolean in return whether to continue (if true)
736 // or stop (if false)
737 // check_set will check if the bits are on (true) or off(false)
738 template <typename ForEachBitHelper, bool check_set>
ForEachBit(const ForEachBitHelper & helper)739 bool ForEachBit(const ForEachBitHelper& helper) {
740 for (int i = 0; static_cast<size_t>(i) < bitfield_.size(); i++) {
741 if (bitfield_[i] == check_set)
742 if (!helper.execute(i)) return false;
743 }
744 return true;
745 }
746
747 public:
BitField(unsigned size)748 explicit BitField(unsigned size) : bitfield_(size, 0) {}
749
Set(int i)750 void Set(int i) {
751 VIXL_ASSERT((i >= 0) && (static_cast<size_t>(i) < bitfield_.size()));
752 bitfield_[i] = true;
753 }
754
Unset(int i)755 void Unset(int i) {
756 VIXL_ASSERT((i >= 0) && (static_cast<size_t>(i) < bitfield_.size()));
757 bitfield_[i] = true;
758 }
759
IsSet(int i)760 bool IsSet(int i) const { return bitfield_[i]; }
761
762 // For each bit not set in the bitfield call the execute functor
763 // execute.
764 // ForEachBitSetHelper::execute returns true if the iteration through
765 // the bits can continue, otherwise it will stop.
766 // struct ForEachBitSetHelper {
767 // bool execute(int /*id*/) { return false; }
768 // };
769 template <typename ForEachBitNotSetHelper>
ForEachBitNotSet(const ForEachBitNotSetHelper & helper)770 bool ForEachBitNotSet(const ForEachBitNotSetHelper& helper) {
771 return ForEachBit<ForEachBitNotSetHelper, false>(helper);
772 }
773
774 // For each bit set in the bitfield call the execute functor
775 // execute.
776 template <typename ForEachBitSetHelper>
ForEachBitSet(const ForEachBitSetHelper & helper)777 bool ForEachBitSet(const ForEachBitSetHelper& helper) {
778 return ForEachBit<ForEachBitSetHelper, true>(helper);
779 }
780
781 private:
782 std::vector<bool> bitfield_;
783 };
784
785 namespace internal {
786
787 typedef int64_t Int64;
788 class Uint64;
789 class Uint128;
790
791 class Uint32 {
792 uint32_t data_;
793
794 public:
795 // Unlike uint32_t, Uint32 has a default constructor.
Uint32()796 Uint32() { data_ = 0; }
Uint32(uint32_t data)797 explicit Uint32(uint32_t data) : data_(data) {}
798 inline explicit Uint32(Uint64 data);
Get()799 uint32_t Get() const { return data_; }
800 template <int N>
GetSigned()801 int32_t GetSigned() const {
802 return ExtractSignedBitfield32(N - 1, 0, data_);
803 }
GetSigned()804 int32_t GetSigned() const { return data_; }
805 Uint32 operator~() const { return Uint32(~data_); }
806 Uint32 operator-() const { return Uint32(-data_); }
807 bool operator==(Uint32 value) const { return data_ == value.data_; }
808 bool operator!=(Uint32 value) const { return data_ != value.data_; }
809 bool operator>(Uint32 value) const { return data_ > value.data_; }
810 Uint32 operator+(Uint32 value) const { return Uint32(data_ + value.data_); }
811 Uint32 operator-(Uint32 value) const { return Uint32(data_ - value.data_); }
812 Uint32 operator&(Uint32 value) const { return Uint32(data_ & value.data_); }
813 Uint32 operator&=(Uint32 value) {
814 data_ &= value.data_;
815 return *this;
816 }
817 Uint32 operator^(Uint32 value) const { return Uint32(data_ ^ value.data_); }
818 Uint32 operator^=(Uint32 value) {
819 data_ ^= value.data_;
820 return *this;
821 }
822 Uint32 operator|(Uint32 value) const { return Uint32(data_ | value.data_); }
823 Uint32 operator|=(Uint32 value) {
824 data_ |= value.data_;
825 return *this;
826 }
827 // Unlike uint32_t, the shift functions can accept negative shift and
828 // return 0 when the shift is too big.
829 Uint32 operator>>(int shift) const {
830 if (shift == 0) return *this;
831 if (shift < 0) {
832 int tmp = -shift;
833 if (tmp >= 32) return Uint32(0);
834 return Uint32(data_ << tmp);
835 }
836 int tmp = shift;
837 if (tmp >= 32) return Uint32(0);
838 return Uint32(data_ >> tmp);
839 }
840 Uint32 operator<<(int shift) const {
841 if (shift == 0) return *this;
842 if (shift < 0) {
843 int tmp = -shift;
844 if (tmp >= 32) return Uint32(0);
845 return Uint32(data_ >> tmp);
846 }
847 int tmp = shift;
848 if (tmp >= 32) return Uint32(0);
849 return Uint32(data_ << tmp);
850 }
851 };
852
853 class Uint64 {
854 uint64_t data_;
855
856 public:
857 // Unlike uint64_t, Uint64 has a default constructor.
Uint64()858 Uint64() { data_ = 0; }
Uint64(uint64_t data)859 explicit Uint64(uint64_t data) : data_(data) {}
Uint64(Uint32 data)860 explicit Uint64(Uint32 data) : data_(data.Get()) {}
861 inline explicit Uint64(Uint128 data);
Get()862 uint64_t Get() const { return data_; }
GetSigned(int N)863 int64_t GetSigned(int N) const {
864 return ExtractSignedBitfield64(N - 1, 0, data_);
865 }
GetSigned()866 int64_t GetSigned() const { return data_; }
ToUint32()867 Uint32 ToUint32() const {
868 VIXL_ASSERT((data_ >> 32) == 0);
869 return Uint32(static_cast<uint32_t>(data_));
870 }
GetHigh32()871 Uint32 GetHigh32() const { return Uint32(data_ >> 32); }
GetLow32()872 Uint32 GetLow32() const { return Uint32(data_ & 0xffffffff); }
873 Uint64 operator~() const { return Uint64(~data_); }
874 Uint64 operator-() const { return Uint64(-data_); }
875 bool operator==(Uint64 value) const { return data_ == value.data_; }
876 bool operator!=(Uint64 value) const { return data_ != value.data_; }
877 Uint64 operator+(Uint64 value) const { return Uint64(data_ + value.data_); }
878 Uint64 operator-(Uint64 value) const { return Uint64(data_ - value.data_); }
879 Uint64 operator&(Uint64 value) const { return Uint64(data_ & value.data_); }
880 Uint64 operator&=(Uint64 value) {
881 data_ &= value.data_;
882 return *this;
883 }
884 Uint64 operator^(Uint64 value) const { return Uint64(data_ ^ value.data_); }
885 Uint64 operator^=(Uint64 value) {
886 data_ ^= value.data_;
887 return *this;
888 }
889 Uint64 operator|(Uint64 value) const { return Uint64(data_ | value.data_); }
890 Uint64 operator|=(Uint64 value) {
891 data_ |= value.data_;
892 return *this;
893 }
894 // Unlike uint64_t, the shift functions can accept negative shift and
895 // return 0 when the shift is too big.
896 Uint64 operator>>(int shift) const {
897 if (shift == 0) return *this;
898 if (shift < 0) {
899 int tmp = -shift;
900 if (tmp >= 64) return Uint64(0);
901 return Uint64(data_ << tmp);
902 }
903 int tmp = shift;
904 if (tmp >= 64) return Uint64(0);
905 return Uint64(data_ >> tmp);
906 }
907 Uint64 operator<<(int shift) const {
908 if (shift == 0) return *this;
909 if (shift < 0) {
910 int tmp = -shift;
911 if (tmp >= 64) return Uint64(0);
912 return Uint64(data_ >> tmp);
913 }
914 int tmp = shift;
915 if (tmp >= 64) return Uint64(0);
916 return Uint64(data_ << tmp);
917 }
918 };
919
920 class Uint128 {
921 uint64_t data_high_;
922 uint64_t data_low_;
923
924 public:
Uint128()925 Uint128() : data_high_(0), data_low_(0) {}
Uint128(uint64_t data_low)926 explicit Uint128(uint64_t data_low) : data_high_(0), data_low_(data_low) {}
Uint128(Uint64 data_low)927 explicit Uint128(Uint64 data_low)
928 : data_high_(0), data_low_(data_low.Get()) {}
Uint128(uint64_t data_high,uint64_t data_low)929 Uint128(uint64_t data_high, uint64_t data_low)
930 : data_high_(data_high), data_low_(data_low) {}
ToUint64()931 Uint64 ToUint64() const {
932 VIXL_ASSERT(data_high_ == 0);
933 return Uint64(data_low_);
934 }
GetHigh64()935 Uint64 GetHigh64() const { return Uint64(data_high_); }
GetLow64()936 Uint64 GetLow64() const { return Uint64(data_low_); }
937 Uint128 operator~() const { return Uint128(~data_high_, ~data_low_); }
938 bool operator==(Uint128 value) const {
939 return (data_high_ == value.data_high_) && (data_low_ == value.data_low_);
940 }
941 Uint128 operator&(Uint128 value) const {
942 return Uint128(data_high_ & value.data_high_, data_low_ & value.data_low_);
943 }
944 Uint128 operator&=(Uint128 value) {
945 data_high_ &= value.data_high_;
946 data_low_ &= value.data_low_;
947 return *this;
948 }
949 Uint128 operator|=(Uint128 value) {
950 data_high_ |= value.data_high_;
951 data_low_ |= value.data_low_;
952 return *this;
953 }
954 Uint128 operator>>(int shift) const {
955 VIXL_ASSERT((shift >= 0) && (shift < 128));
956 if (shift == 0) return *this;
957 if (shift >= 64) {
958 return Uint128(0, data_high_ >> (shift - 64));
959 }
960 uint64_t tmp = (data_high_ << (64 - shift)) | (data_low_ >> shift);
961 return Uint128(data_high_ >> shift, tmp);
962 }
963 Uint128 operator<<(int shift) const {
964 VIXL_ASSERT((shift >= 0) && (shift < 128));
965 if (shift == 0) return *this;
966 if (shift >= 64) {
967 return Uint128(data_low_ << (shift - 64), 0);
968 }
969 uint64_t tmp = (data_high_ << shift) | (data_low_ >> (64 - shift));
970 return Uint128(tmp, data_low_ << shift);
971 }
972 };
973
Uint32(Uint64 data)974 Uint32::Uint32(Uint64 data) : data_(data.ToUint32().Get()) {}
Uint64(Uint128 data)975 Uint64::Uint64(Uint128 data) : data_(data.ToUint64().Get()) {}
976
977 Int64 BitCount(Uint32 value);
978
979 } // namespace internal
980
981 // The default NaN values (for FPCR.DN=1).
982 extern const double kFP64DefaultNaN;
983 extern const float kFP32DefaultNaN;
984 extern const Float16 kFP16DefaultNaN;
985
986 // Floating-point infinity values.
987 extern const Float16 kFP16PositiveInfinity;
988 extern const Float16 kFP16NegativeInfinity;
989 extern const float kFP32PositiveInfinity;
990 extern const float kFP32NegativeInfinity;
991 extern const double kFP64PositiveInfinity;
992 extern const double kFP64NegativeInfinity;
993
994 // Floating-point zero values.
995 extern const Float16 kFP16PositiveZero;
996 extern const Float16 kFP16NegativeZero;
997
998 // AArch64 floating-point specifics. These match IEEE-754.
999 const unsigned kDoubleMantissaBits = 52;
1000 const unsigned kDoubleExponentBits = 11;
1001 const unsigned kFloatMantissaBits = 23;
1002 const unsigned kFloatExponentBits = 8;
1003 const unsigned kFloat16MantissaBits = 10;
1004 const unsigned kFloat16ExponentBits = 5;
1005
1006 enum FPRounding {
1007 // The first four values are encodable directly by FPCR<RMode>.
1008 FPTieEven = 0x0,
1009 FPPositiveInfinity = 0x1,
1010 FPNegativeInfinity = 0x2,
1011 FPZero = 0x3,
1012
1013 // The final rounding modes are only available when explicitly specified by
1014 // the instruction (such as with fcvta). It cannot be set in FPCR.
1015 FPTieAway,
1016 FPRoundOdd
1017 };
1018
1019 enum UseDefaultNaN { kUseDefaultNaN, kIgnoreDefaultNaN };
1020
1021 // Assemble the specified IEEE-754 components into the target type and apply
1022 // appropriate rounding.
1023 // sign: 0 = positive, 1 = negative
1024 // exponent: Unbiased IEEE-754 exponent.
1025 // mantissa: The mantissa of the input. The top bit (which is not encoded for
1026 // normal IEEE-754 values) must not be omitted. This bit has the
1027 // value 'pow(2, exponent)'.
1028 //
1029 // The input value is assumed to be a normalized value. That is, the input may
1030 // not be infinity or NaN. If the source value is subnormal, it must be
1031 // normalized before calling this function such that the highest set bit in the
1032 // mantissa has the value 'pow(2, exponent)'.
1033 //
1034 // Callers should use FPRoundToFloat or FPRoundToDouble directly, rather than
1035 // calling a templated FPRound.
1036 template <class T, int ebits, int mbits>
FPRound(int64_t sign,int64_t exponent,uint64_t mantissa,FPRounding round_mode)1037 T FPRound(int64_t sign,
1038 int64_t exponent,
1039 uint64_t mantissa,
1040 FPRounding round_mode) {
1041 VIXL_ASSERT((sign == 0) || (sign == 1));
1042
1043 // Only FPTieEven and FPRoundOdd rounding modes are implemented.
1044 VIXL_ASSERT((round_mode == FPTieEven) || (round_mode == FPRoundOdd));
1045
1046 // Rounding can promote subnormals to normals, and normals to infinities. For
1047 // example, a double with exponent 127 (FLT_MAX_EXP) would appear to be
1048 // encodable as a float, but rounding based on the low-order mantissa bits
1049 // could make it overflow. With ties-to-even rounding, this value would become
1050 // an infinity.
1051
1052 // ---- Rounding Method ----
1053 //
1054 // The exponent is irrelevant in the rounding operation, so we treat the
1055 // lowest-order bit that will fit into the result ('onebit') as having
1056 // the value '1'. Similarly, the highest-order bit that won't fit into
1057 // the result ('halfbit') has the value '0.5'. The 'point' sits between
1058 // 'onebit' and 'halfbit':
1059 //
1060 // These bits fit into the result.
1061 // |---------------------|
1062 // mantissa = 0bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
1063 // ||
1064 // / |
1065 // / halfbit
1066 // onebit
1067 //
1068 // For subnormal outputs, the range of representable bits is smaller and
1069 // the position of onebit and halfbit depends on the exponent of the
1070 // input, but the method is otherwise similar.
1071 //
1072 // onebit(frac)
1073 // |
1074 // | halfbit(frac) halfbit(adjusted)
1075 // | / /
1076 // | | |
1077 // 0b00.0 (exact) -> 0b00.0 (exact) -> 0b00
1078 // 0b00.0... -> 0b00.0... -> 0b00
1079 // 0b00.1 (exact) -> 0b00.0111..111 -> 0b00
1080 // 0b00.1... -> 0b00.1... -> 0b01
1081 // 0b01.0 (exact) -> 0b01.0 (exact) -> 0b01
1082 // 0b01.0... -> 0b01.0... -> 0b01
1083 // 0b01.1 (exact) -> 0b01.1 (exact) -> 0b10
1084 // 0b01.1... -> 0b01.1... -> 0b10
1085 // 0b10.0 (exact) -> 0b10.0 (exact) -> 0b10
1086 // 0b10.0... -> 0b10.0... -> 0b10
1087 // 0b10.1 (exact) -> 0b10.0111..111 -> 0b10
1088 // 0b10.1... -> 0b10.1... -> 0b11
1089 // 0b11.0 (exact) -> 0b11.0 (exact) -> 0b11
1090 // ... / | / |
1091 // / | / |
1092 // / |
1093 // adjusted = frac - (halfbit(mantissa) & ~onebit(frac)); / |
1094 //
1095 // mantissa = (mantissa >> shift) + halfbit(adjusted);
1096
1097 static const int mantissa_offset = 0;
1098 static const int exponent_offset = mantissa_offset + mbits;
1099 static const int sign_offset = exponent_offset + ebits;
1100 VIXL_ASSERT(sign_offset == (sizeof(T) * 8 - 1));
1101
1102 // Bail out early for zero inputs.
1103 if (mantissa == 0) {
1104 return static_cast<T>(sign << sign_offset);
1105 }
1106
1107 // If all bits in the exponent are set, the value is infinite or NaN.
1108 // This is true for all binary IEEE-754 formats.
1109 static const int infinite_exponent = (1 << ebits) - 1;
1110 static const int max_normal_exponent = infinite_exponent - 1;
1111
1112 // Apply the exponent bias to encode it for the result. Doing this early makes
1113 // it easy to detect values that will be infinite or subnormal.
1114 exponent += max_normal_exponent >> 1;
1115
1116 if (exponent > max_normal_exponent) {
1117 // Overflow: the input is too large for the result type to represent.
1118 if (round_mode == FPTieEven) {
1119 // FPTieEven rounding mode handles overflows using infinities.
1120 exponent = infinite_exponent;
1121 mantissa = 0;
1122 } else {
1123 VIXL_ASSERT(round_mode == FPRoundOdd);
1124 // FPRoundOdd rounding mode handles overflows using the largest magnitude
1125 // normal number.
1126 exponent = max_normal_exponent;
1127 mantissa = (UINT64_C(1) << exponent_offset) - 1;
1128 }
1129 return static_cast<T>((sign << sign_offset) |
1130 (exponent << exponent_offset) |
1131 (mantissa << mantissa_offset));
1132 }
1133
1134 // Calculate the shift required to move the top mantissa bit to the proper
1135 // place in the destination type.
1136 const int highest_significant_bit = 63 - CountLeadingZeros(mantissa);
1137 int shift = highest_significant_bit - mbits;
1138
1139 if (exponent <= 0) {
1140 // The output will be subnormal (before rounding).
1141 // For subnormal outputs, the shift must be adjusted by the exponent. The +1
1142 // is necessary because the exponent of a subnormal value (encoded as 0) is
1143 // the same as the exponent of the smallest normal value (encoded as 1).
1144 shift += -exponent + 1;
1145
1146 // Handle inputs that would produce a zero output.
1147 //
1148 // Shifts higher than highest_significant_bit+1 will always produce a zero
1149 // result. A shift of exactly highest_significant_bit+1 might produce a
1150 // non-zero result after rounding.
1151 if (shift > (highest_significant_bit + 1)) {
1152 if (round_mode == FPTieEven) {
1153 // The result will always be +/-0.0.
1154 return static_cast<T>(sign << sign_offset);
1155 } else {
1156 VIXL_ASSERT(round_mode == FPRoundOdd);
1157 VIXL_ASSERT(mantissa != 0);
1158 // For FPRoundOdd, if the mantissa is too small to represent and
1159 // non-zero return the next "odd" value.
1160 return static_cast<T>((sign << sign_offset) | 1);
1161 }
1162 }
1163
1164 // Properly encode the exponent for a subnormal output.
1165 exponent = 0;
1166 } else {
1167 // Clear the topmost mantissa bit, since this is not encoded in IEEE-754
1168 // normal values.
1169 mantissa &= ~(UINT64_C(1) << highest_significant_bit);
1170 }
1171
1172 // The casts below are only well-defined for unsigned integers.
1173 VIXL_STATIC_ASSERT(std::numeric_limits<T>::is_integer);
1174 VIXL_STATIC_ASSERT(!std::numeric_limits<T>::is_signed);
1175
1176 if (shift > 0) {
1177 if (round_mode == FPTieEven) {
1178 // We have to shift the mantissa to the right. Some precision is lost, so
1179 // we need to apply rounding.
1180 uint64_t onebit_mantissa = (mantissa >> (shift)) & 1;
1181 uint64_t halfbit_mantissa = (mantissa >> (shift - 1)) & 1;
1182 uint64_t adjustment = (halfbit_mantissa & ~onebit_mantissa);
1183 uint64_t adjusted = mantissa - adjustment;
1184 T halfbit_adjusted = (adjusted >> (shift - 1)) & 1;
1185
1186 T result =
1187 static_cast<T>((sign << sign_offset) | (exponent << exponent_offset) |
1188 ((mantissa >> shift) << mantissa_offset));
1189
1190 // A very large mantissa can overflow during rounding. If this happens,
1191 // the exponent should be incremented and the mantissa set to 1.0
1192 // (encoded as 0). Applying halfbit_adjusted after assembling the float
1193 // has the nice side-effect that this case is handled for free.
1194 //
1195 // This also handles cases where a very large finite value overflows to
1196 // infinity, or where a very large subnormal value overflows to become
1197 // normal.
1198 return result + halfbit_adjusted;
1199 } else {
1200 VIXL_ASSERT(round_mode == FPRoundOdd);
1201 // If any bits at position halfbit or below are set, onebit (ie. the
1202 // bottom bit of the resulting mantissa) must be set.
1203 uint64_t fractional_bits = mantissa & ((UINT64_C(1) << shift) - 1);
1204 if (fractional_bits != 0) {
1205 mantissa |= UINT64_C(1) << shift;
1206 }
1207
1208 return static_cast<T>((sign << sign_offset) |
1209 (exponent << exponent_offset) |
1210 ((mantissa >> shift) << mantissa_offset));
1211 }
1212 } else {
1213 // We have to shift the mantissa to the left (or not at all). The input
1214 // mantissa is exactly representable in the output mantissa, so apply no
1215 // rounding correction.
1216 return static_cast<T>((sign << sign_offset) |
1217 (exponent << exponent_offset) |
1218 ((mantissa << -shift) << mantissa_offset));
1219 }
1220 }
1221
1222
1223 // See FPRound for a description of this function.
FPRoundToDouble(int64_t sign,int64_t exponent,uint64_t mantissa,FPRounding round_mode)1224 inline double FPRoundToDouble(int64_t sign,
1225 int64_t exponent,
1226 uint64_t mantissa,
1227 FPRounding round_mode) {
1228 uint64_t bits =
1229 FPRound<uint64_t, kDoubleExponentBits, kDoubleMantissaBits>(sign,
1230 exponent,
1231 mantissa,
1232 round_mode);
1233 return RawbitsToDouble(bits);
1234 }
1235
1236
1237 // See FPRound for a description of this function.
FPRoundToFloat16(int64_t sign,int64_t exponent,uint64_t mantissa,FPRounding round_mode)1238 inline Float16 FPRoundToFloat16(int64_t sign,
1239 int64_t exponent,
1240 uint64_t mantissa,
1241 FPRounding round_mode) {
1242 return RawbitsToFloat16(
1243 FPRound<uint16_t,
1244 kFloat16ExponentBits,
1245 kFloat16MantissaBits>(sign, exponent, mantissa, round_mode));
1246 }
1247
1248
1249 // See FPRound for a description of this function.
FPRoundToFloat(int64_t sign,int64_t exponent,uint64_t mantissa,FPRounding round_mode)1250 static inline float FPRoundToFloat(int64_t sign,
1251 int64_t exponent,
1252 uint64_t mantissa,
1253 FPRounding round_mode) {
1254 uint32_t bits =
1255 FPRound<uint32_t, kFloatExponentBits, kFloatMantissaBits>(sign,
1256 exponent,
1257 mantissa,
1258 round_mode);
1259 return RawbitsToFloat(bits);
1260 }
1261
1262
1263 float FPToFloat(Float16 value, UseDefaultNaN DN, bool* exception = NULL);
1264 float FPToFloat(double value,
1265 FPRounding round_mode,
1266 UseDefaultNaN DN,
1267 bool* exception = NULL);
1268
1269 double FPToDouble(Float16 value, UseDefaultNaN DN, bool* exception = NULL);
1270 double FPToDouble(float value, UseDefaultNaN DN, bool* exception = NULL);
1271
1272 Float16 FPToFloat16(float value,
1273 FPRounding round_mode,
1274 UseDefaultNaN DN,
1275 bool* exception = NULL);
1276
1277 Float16 FPToFloat16(double value,
1278 FPRounding round_mode,
1279 UseDefaultNaN DN,
1280 bool* exception = NULL);
1281 } // namespace vixl
1282
1283 #endif // VIXL_UTILS_H
1284