Bug 1882714 [wpt PR 44850] - Update wpt metadata, a=testonly
[gecko.git] / third_party / wasm2c / src / literal.cc
blob7076630f666b301707eebb80ba83cc9aabfd3881
1 /*
2 * Copyright 2016 WebAssembly Community Group participants
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "wabt/literal.h"
19 #include <cassert>
20 #include <cerrno>
21 #include <cinttypes>
22 #include <cmath>
23 #include <cstdlib>
24 #include <cstring>
25 #include <limits>
26 #include <type_traits>
28 namespace wabt {
30 namespace {
32 template <typename T>
33 struct FloatTraitsBase {};
35 // The "PlusOne" values are used because normal IEEE floats have an implicit
36 // leading one, so they have an additional bit of precision.
38 template <>
39 struct FloatTraitsBase<float> {
40 using Uint = uint32_t;
41 static constexpr int kBits = sizeof(Uint) * 8;
42 static constexpr int kSigBits = 23;
43 static constexpr float kHugeVal = HUGE_VALF;
44 static constexpr int kMaxHexBufferSize = WABT_MAX_FLOAT_HEX;
46 static float Strto(const char* s, char** endptr) { return strtof(s, endptr); }
49 template <>
50 struct FloatTraitsBase<double> {
51 using Uint = uint64_t;
52 static constexpr int kBits = sizeof(Uint) * 8;
53 static constexpr int kSigBits = 52;
54 static constexpr float kHugeVal = HUGE_VAL;
55 static constexpr int kMaxHexBufferSize = WABT_MAX_DOUBLE_HEX;
57 static double Strto(const char* s, char** endptr) {
58 return strtod(s, endptr);
62 template <typename T>
63 struct FloatTraits : FloatTraitsBase<T> {
64 using Uint = typename FloatTraitsBase<T>::Uint;
65 using FloatTraitsBase<T>::kBits;
66 using FloatTraitsBase<T>::kSigBits;
68 static constexpr int kExpBits = kBits - kSigBits - 1;
69 static constexpr int kSignShift = kBits - 1;
70 static constexpr Uint kSigMask = (Uint(1) << kSigBits) - 1;
71 static constexpr int kSigPlusOneBits = kSigBits + 1;
72 static constexpr Uint kSigPlusOneMask = (Uint(1) << kSigPlusOneBits) - 1;
73 static constexpr int kExpMask = (1 << kExpBits) - 1;
74 static constexpr int kMaxExp = 1 << (kExpBits - 1);
75 static constexpr int kMinExp = -kMaxExp + 1;
76 static constexpr int kExpBias = -kMinExp;
77 static constexpr Uint kQuietNanTag = Uint(1) << (kSigBits - 1);
80 template <typename T>
81 class FloatParser {
82 public:
83 using Traits = FloatTraits<T>;
84 using Uint = typename Traits::Uint;
85 using Float = T;
87 static Result Parse(LiteralType,
88 const char* s,
89 const char* end,
90 Uint* out_bits);
92 private:
93 static bool StringStartsWith(const char* start,
94 const char* end,
95 const char* prefix);
96 static Uint Make(bool sign, int exp, Uint sig);
97 static Uint ShiftAndRoundToNearest(Uint significand,
98 int shift,
99 bool seen_trailing_non_zero);
101 static Result ParseFloat(const char* s, const char* end, Uint* out_bits);
102 static Result ParseNan(const char* s, const char* end, Uint* out_bits);
103 static Result ParseHex(const char* s, const char* end, Uint* out_bits);
104 static void ParseInfinity(const char* s, const char* end, Uint* out_bits);
107 template <typename T>
108 class FloatWriter {
109 public:
110 using Traits = FloatTraits<T>;
111 using Uint = typename Traits::Uint;
113 static void WriteHex(char* out, size_t size, Uint bits);
116 // Return 1 if the non-NULL-terminated string starting with |start| and ending
117 // with |end| starts with the NULL-terminated string |prefix|.
118 template <typename T>
119 // static
120 bool FloatParser<T>::StringStartsWith(const char* start,
121 const char* end,
122 const char* prefix) {
123 while (start < end && *prefix) {
124 if (*start != *prefix) {
125 return false;
127 start++;
128 prefix++;
130 return *prefix == 0;
133 // static
134 template <typename T>
135 Result FloatParser<T>::ParseFloat(const char* s,
136 const char* end,
137 Uint* out_bits) {
138 // Here is the normal behavior for strtof/strtod:
140 // input | errno | output |
141 // ---------------------------------
142 // overflow | ERANGE | +-HUGE_VAL |
143 // underflow | ERANGE | 0.0 |
144 // otherwise | 0 | value |
146 // So normally we need to clear errno before calling strto{f,d}, and check
147 // afterward whether it was set to ERANGE.
149 // glibc seems to have a bug where
150 // strtof("340282356779733661637539395458142568448") will return HUGE_VAL,
151 // but will not set errno to ERANGE. Since this function is only called when
152 // we know that we have parsed a "normal" number (i.e. not "inf"), we know
153 // that if we ever get HUGE_VAL, it must be overflow.
155 // The WebAssembly spec also ignores underflow, so we don't need to check for
156 // ERANGE at all.
158 // WebAssembly floats can contain underscores, but strto* can't parse those,
159 // so remove them first.
160 assert(s <= end);
161 const size_t kBufferSize = end - s + 1; // +1 for \0.
162 char* buffer = static_cast<char*>(alloca(kBufferSize));
163 auto buffer_end =
164 std::copy_if(s, end, buffer, [](char c) -> bool { return c != '_'; });
165 assert(buffer_end < buffer + kBufferSize);
166 *buffer_end = 0;
168 char* endptr;
169 Float value = Traits::Strto(buffer, &endptr);
170 if (endptr != buffer_end ||
171 (value == Traits::kHugeVal || value == -Traits::kHugeVal)) {
172 return Result::Error;
175 memcpy(out_bits, &value, sizeof(value));
176 return Result::Ok;
179 // static
180 template <typename T>
181 typename FloatParser<T>::Uint FloatParser<T>::Make(bool sign,
182 int exp,
183 Uint sig) {
184 assert(exp >= Traits::kMinExp && exp <= Traits::kMaxExp);
185 assert(sig <= Traits::kSigMask);
186 return (Uint(sign) << Traits::kSignShift) |
187 (Uint(exp + Traits::kExpBias) << Traits::kSigBits) | sig;
190 // static
191 template <typename T>
192 typename FloatParser<T>::Uint FloatParser<T>::ShiftAndRoundToNearest(
193 Uint significand,
194 int shift,
195 bool seen_trailing_non_zero) {
196 assert(shift > 0);
197 // Round ties to even.
198 if ((significand & (Uint(1) << shift)) || seen_trailing_non_zero) {
199 significand += Uint(1) << (shift - 1);
201 significand >>= shift;
202 return significand;
205 // static
206 template <typename T>
207 Result FloatParser<T>::ParseNan(const char* s,
208 const char* end,
209 Uint* out_bits) {
210 bool is_neg = false;
211 if (*s == '-') {
212 is_neg = true;
213 s++;
214 } else if (*s == '+') {
215 s++;
217 assert(StringStartsWith(s, end, "nan"));
218 s += 3;
220 Uint tag;
221 if (s != end) {
222 tag = 0;
223 assert(StringStartsWith(s, end, ":0x"));
224 s += 3;
226 for (; s < end; ++s) {
227 if (*s == '_') {
228 continue;
230 uint32_t digit;
231 CHECK_RESULT(ParseHexdigit(*s, &digit));
232 tag = tag * 16 + digit;
233 // Check for overflow.
234 if (tag > Traits::kSigMask) {
235 return Result::Error;
239 // NaN cannot have a zero tag, that is reserved for infinity.
240 if (tag == 0) {
241 return Result::Error;
243 } else {
244 tag = Traits::kQuietNanTag;
247 *out_bits = Make(is_neg, Traits::kMaxExp, tag);
248 return Result::Ok;
251 // static
252 template <typename T>
253 Result FloatParser<T>::ParseHex(const char* s,
254 const char* end,
255 Uint* out_bits) {
256 bool is_neg = false;
257 if (*s == '-') {
258 is_neg = true;
259 s++;
260 } else if (*s == '+') {
261 s++;
263 assert(StringStartsWith(s, end, "0x"));
264 s += 2;
266 // Loop over the significand; everything up to the 'p'.
267 // This code is a bit nasty because we want to support extra zeroes anywhere
268 // without having to use many significand bits.
269 // e.g.
270 // 0x00000001.0p0 => significand = 1, significand_exponent = 0
271 // 0x10000000.0p0 => significand = 1, significand_exponent = 28
272 // 0x0.000001p0 => significand = 1, significand_exponent = -24
273 bool seen_dot = false;
274 bool seen_trailing_non_zero = false;
275 Uint significand = 0;
276 int significand_exponent = 0; // Exponent adjustment due to dot placement.
277 for (; s < end; ++s) {
278 uint32_t digit;
279 if (*s == '_') {
280 continue;
281 } else if (*s == '.') {
282 seen_dot = true;
283 } else if (Succeeded(ParseHexdigit(*s, &digit))) {
284 if (Traits::kBits - Clz(significand) <= Traits::kSigPlusOneBits) {
285 significand = (significand << 4) + digit;
286 if (seen_dot) {
287 significand_exponent -= 4;
289 } else {
290 if (!seen_trailing_non_zero && digit != 0) {
291 seen_trailing_non_zero = true;
293 if (!seen_dot) {
294 significand_exponent += 4;
297 } else {
298 break;
302 if (significand == 0) {
303 // 0 or -0.
304 *out_bits = Make(is_neg, Traits::kMinExp, 0);
305 return Result::Ok;
308 int exponent = 0;
309 bool exponent_is_neg = false;
310 if (s < end) {
311 assert(*s == 'p' || *s == 'P');
312 s++;
313 // Exponent is always positive, but significand_exponent is signed.
314 // significand_exponent_add is negated if exponent will be negative, so it
315 // can be easily summed to see if the exponent is too large (see below).
316 int significand_exponent_add = 0;
317 if (*s == '-') {
318 exponent_is_neg = true;
319 significand_exponent_add = -significand_exponent;
320 s++;
321 } else if (*s == '+') {
322 s++;
323 significand_exponent_add = significand_exponent;
326 for (; s < end; ++s) {
327 if (*s == '_') {
328 continue;
331 uint32_t digit = (*s - '0');
332 assert(digit <= 9);
333 exponent = exponent * 10 + digit;
334 if (exponent + significand_exponent_add >= Traits::kMaxExp) {
335 break;
340 if (exponent_is_neg) {
341 exponent = -exponent;
344 int significand_bits = Traits::kBits - Clz(significand);
345 // -1 for the implicit 1 bit of the significand.
346 exponent += significand_exponent + significand_bits - 1;
348 if (exponent <= Traits::kMinExp) {
349 // Maybe subnormal.
350 auto update_seen_trailing_non_zero = [&](int shift) {
351 assert(shift > 0);
352 auto mask = (Uint(1) << (shift - 1)) - 1;
353 seen_trailing_non_zero |= (significand & mask) != 0;
356 // Normalize significand.
357 if (significand_bits > Traits::kSigBits) {
358 int shift = significand_bits - Traits::kSigBits;
359 update_seen_trailing_non_zero(shift);
360 significand >>= shift;
361 } else if (significand_bits < Traits::kSigBits) {
362 significand <<= (Traits::kSigBits - significand_bits);
365 int shift = Traits::kMinExp - exponent;
366 if (shift <= Traits::kSigBits) {
367 if (shift) {
368 update_seen_trailing_non_zero(shift);
369 significand =
370 ShiftAndRoundToNearest(significand, shift, seen_trailing_non_zero) &
371 Traits::kSigMask;
373 exponent = Traits::kMinExp;
375 if (significand != 0) {
376 *out_bits = Make(is_neg, exponent, significand);
377 return Result::Ok;
381 // Not subnormal, too small; return 0 or -0.
382 *out_bits = Make(is_neg, Traits::kMinExp, 0);
383 } else {
384 // Maybe Normal value.
385 if (significand_bits > Traits::kSigPlusOneBits) {
386 significand = ShiftAndRoundToNearest(
387 significand, significand_bits - Traits::kSigPlusOneBits,
388 seen_trailing_non_zero);
389 if (significand > Traits::kSigPlusOneMask) {
390 exponent++;
392 } else if (significand_bits < Traits::kSigPlusOneBits) {
393 significand <<= (Traits::kSigPlusOneBits - significand_bits);
396 if (exponent >= Traits::kMaxExp) {
397 // Would be inf or -inf, but the spec doesn't allow rounding hex-floats to
398 // infinity.
399 return Result::Error;
402 *out_bits = Make(is_neg, exponent, significand & Traits::kSigMask);
405 return Result::Ok;
408 // static
409 template <typename T>
410 void FloatParser<T>::ParseInfinity(const char* s,
411 const char* end,
412 Uint* out_bits) {
413 bool is_neg = false;
414 if (*s == '-') {
415 is_neg = true;
416 s++;
417 } else if (*s == '+') {
418 s++;
420 assert(StringStartsWith(s, end, "inf"));
421 *out_bits = Make(is_neg, Traits::kMaxExp, 0);
424 // static
425 template <typename T>
426 Result FloatParser<T>::Parse(LiteralType literal_type,
427 const char* s,
428 const char* end,
429 Uint* out_bits) {
430 #if COMPILER_IS_MSVC
431 if (literal_type == LiteralType::Int && StringStartsWith(s, end, "0x")) {
432 // Some MSVC crt implementation of strtof doesn't support hex strings
433 literal_type = LiteralType::Hexfloat;
435 #endif
436 switch (literal_type) {
437 case LiteralType::Int:
438 case LiteralType::Float:
439 return ParseFloat(s, end, out_bits);
441 case LiteralType::Hexfloat:
442 return ParseHex(s, end, out_bits);
444 case LiteralType::Infinity:
445 ParseInfinity(s, end, out_bits);
446 return Result::Ok;
448 case LiteralType::Nan:
449 return ParseNan(s, end, out_bits);
452 WABT_UNREACHABLE;
455 // static
456 template <typename T>
457 void FloatWriter<T>::WriteHex(char* out, size_t size, Uint bits) {
458 static constexpr int kNumNybbles = Traits::kBits / 4;
459 static constexpr int kTopNybbleShift = Traits::kBits - 4;
460 static constexpr Uint kTopNybble = Uint(0xf) << kTopNybbleShift;
461 static const char s_hex_digits[] = "0123456789abcdef";
463 char buffer[Traits::kMaxHexBufferSize];
464 char* p = buffer;
465 bool is_neg = (bits >> Traits::kSignShift);
466 int exp = ((bits >> Traits::kSigBits) & Traits::kExpMask) - Traits::kExpBias;
467 Uint sig = bits & Traits::kSigMask;
469 if (is_neg) {
470 *p++ = '-';
472 if (exp == Traits::kMaxExp) {
473 // Infinity or nan.
474 if (sig == 0) {
475 strcpy(p, "inf");
476 p += 3;
477 } else {
478 strcpy(p, "nan");
479 p += 3;
480 if (sig != Traits::kQuietNanTag) {
481 strcpy(p, ":0x");
482 p += 3;
483 // Skip leading zeroes.
484 int num_nybbles = kNumNybbles;
485 while ((sig & kTopNybble) == 0) {
486 sig <<= 4;
487 num_nybbles--;
489 while (num_nybbles) {
490 Uint nybble = (sig >> kTopNybbleShift) & 0xf;
491 *p++ = s_hex_digits[nybble];
492 sig <<= 4;
493 --num_nybbles;
497 } else {
498 bool is_zero = sig == 0 && exp == Traits::kMinExp;
499 strcpy(p, "0x");
500 p += 2;
501 *p++ = is_zero ? '0' : '1';
503 // Shift sig up so the top 4-bits are at the top of the Uint.
504 sig <<= Traits::kBits - Traits::kSigBits;
506 if (sig) {
507 if (exp == Traits::kMinExp) {
508 // Subnormal; shift the significand up, and shift out the implicit 1.
509 Uint leading_zeroes = Clz(sig);
510 if (leading_zeroes < Traits::kSignShift) {
511 sig <<= leading_zeroes + 1;
512 } else {
513 sig = 0;
515 exp -= leading_zeroes;
518 *p++ = '.';
519 while (sig) {
520 int nybble = (sig >> kTopNybbleShift) & 0xf;
521 *p++ = s_hex_digits[nybble];
522 sig <<= 4;
525 *p++ = 'p';
526 if (is_zero) {
527 strcpy(p, "+0");
528 p += 2;
529 } else {
530 if (exp < 0) {
531 *p++ = '-';
532 exp = -exp;
533 } else {
534 *p++ = '+';
536 if (exp >= 1000) {
537 *p++ = '1';
539 if (exp >= 100) {
540 *p++ = '0' + (exp / 100) % 10;
542 if (exp >= 10) {
543 *p++ = '0' + (exp / 10) % 10;
545 *p++ = '0' + exp % 10;
549 size_t len = p - buffer;
550 if (len >= size) {
551 len = size - 1;
553 memcpy(out, buffer, len);
554 out[len] = '\0';
557 } // end anonymous namespace
559 Result ParseHexdigit(char c, uint32_t* out) {
560 if (static_cast<unsigned int>(c - '0') <= 9) {
561 *out = c - '0';
562 return Result::Ok;
563 } else if (static_cast<unsigned int>(c - 'a') < 6) {
564 *out = 10 + (c - 'a');
565 return Result::Ok;
566 } else if (static_cast<unsigned int>(c - 'A') < 6) {
567 *out = 10 + (c - 'A');
568 return Result::Ok;
570 return Result::Error;
573 Result ParseUint64(const char* s, const char* end, uint64_t* out) {
574 if (s == end) {
575 return Result::Error;
577 uint64_t value = 0;
578 if (*s == '0' && s + 1 < end && s[1] == 'x') {
579 s += 2;
580 if (s == end) {
581 return Result::Error;
583 constexpr uint64_t kMaxDiv16 = UINT64_MAX / 16;
584 constexpr uint64_t kMaxMod16 = UINT64_MAX % 16;
585 for (; s < end; ++s) {
586 uint32_t digit;
587 if (*s == '_') {
588 continue;
590 CHECK_RESULT(ParseHexdigit(*s, &digit));
591 // Check for overflow.
592 if (value > kMaxDiv16 || (value == kMaxDiv16 && digit > kMaxMod16)) {
593 return Result::Error;
595 value = value * 16 + digit;
597 } else {
598 constexpr uint64_t kMaxDiv10 = UINT64_MAX / 10;
599 constexpr uint64_t kMaxMod10 = UINT64_MAX % 10;
600 for (; s < end; ++s) {
601 if (*s == '_') {
602 continue;
604 uint32_t digit = (*s - '0');
605 if (digit > 9) {
606 return Result::Error;
608 // Check for overflow.
609 if (value > kMaxDiv10 || (value == kMaxDiv10 && digit > kMaxMod10)) {
610 return Result::Error;
612 value = value * 10 + digit;
615 if (s != end) {
616 return Result::Error;
618 *out = value;
619 return Result::Ok;
622 Result ParseInt64(const char* s,
623 const char* end,
624 uint64_t* out,
625 ParseIntType parse_type) {
626 bool has_sign = false;
627 if (*s == '-' || *s == '+') {
628 if (parse_type == ParseIntType::UnsignedOnly) {
629 return Result::Error;
631 if (*s == '-') {
632 has_sign = true;
634 s++;
636 uint64_t value = 0;
637 Result result = ParseUint64(s, end, &value);
638 if (has_sign) {
639 // abs(INT64_MIN) == INT64_MAX + 1.
640 if (value > static_cast<uint64_t>(INT64_MAX) + 1) {
641 return Result::Error;
643 value = UINT64_MAX - value + 1;
645 *out = value;
646 return result;
649 namespace {
650 uint32_t AddWithCarry(uint32_t x, uint32_t y, uint32_t* carry) {
651 // Increments *carry if the addition overflows, otherwise leaves carry alone.
652 if ((0xffffffff - x) < y) {
653 ++*carry;
655 return x + y;
658 void Mul10(v128* v) {
659 // Multiply-by-10 decomposes into (x << 3) + (x << 1). We implement those
660 // operations with carrying from smaller quads of the v128 to the larger
661 // quads.
663 constexpr uint32_t kTopThreeBits = 0xe0000000;
664 constexpr uint32_t kTopBit = 0x80000000;
666 uint32_t carry_into_v1 =
667 ((v->u32(0) & kTopThreeBits) >> 29) + ((v->u32(0) & kTopBit) >> 31);
668 v->set_u32(0, AddWithCarry(v->u32(0) << 3, v->u32(0) << 1, &carry_into_v1));
669 uint32_t carry_into_v2 =
670 ((v->u32(1) & kTopThreeBits) >> 29) + ((v->u32(1) & kTopBit) >> 31);
671 v->set_u32(1, AddWithCarry(v->u32(1) << 3, v->u32(1) << 1, &carry_into_v2));
672 v->set_u32(1, AddWithCarry(v->u32(1), carry_into_v1, &carry_into_v2));
673 uint32_t carry_into_v3 =
674 ((v->u32(2) & kTopThreeBits) >> 29) + ((v->u32(2) & kTopBit) >> 31);
675 v->set_u32(2, AddWithCarry(v->u32(2) << 3, v->u32(2) << 1, &carry_into_v3));
676 v->set_u32(2, AddWithCarry(v->u32(2), carry_into_v2, &carry_into_v3));
677 v->set_u32(3, v->u32(3) * 10 + carry_into_v3);
679 } // namespace
681 Result ParseUint128(const char* s, const char* end, v128* out) {
682 if (s == end) {
683 return Result::Error;
686 out->set_zero();
688 while (true) {
689 uint32_t digit = (*s - '0');
690 if (digit > 9) {
691 return Result::Error;
694 uint32_t carry_into_v1 = 0;
695 uint32_t carry_into_v2 = 0;
696 uint32_t carry_into_v3 = 0;
697 uint32_t overflow = 0;
698 out->set_u32(0, AddWithCarry(out->u32(0), digit, &carry_into_v1));
699 out->set_u32(1, AddWithCarry(out->u32(1), carry_into_v1, &carry_into_v2));
700 out->set_u32(2, AddWithCarry(out->u32(2), carry_into_v2, &carry_into_v3));
701 out->set_u32(3, AddWithCarry(out->u32(3), carry_into_v3, &overflow));
702 if (overflow) {
703 return Result::Error;
706 ++s;
708 if (s == end) {
709 break;
712 Mul10(out);
714 return Result::Ok;
717 template <typename U>
718 Result ParseInt(const char* s,
719 const char* end,
720 U* out,
721 ParseIntType parse_type) {
722 using S = typename std::make_signed<U>::type;
723 uint64_t value;
724 bool has_sign = false;
725 if (*s == '-' || *s == '+') {
726 if (parse_type == ParseIntType::UnsignedOnly) {
727 return Result::Error;
729 if (*s == '-') {
730 has_sign = true;
732 s++;
734 CHECK_RESULT(ParseUint64(s, end, &value));
736 if (has_sign) {
737 // abs(INTN_MIN) == INTN_MAX + 1.
738 if (value > static_cast<uint64_t>(std::numeric_limits<S>::max()) + 1) {
739 return Result::Error;
741 value = std::numeric_limits<U>::max() - value + 1;
742 } else {
743 if (value > static_cast<uint64_t>(std::numeric_limits<U>::max())) {
744 return Result::Error;
747 *out = static_cast<U>(value);
748 return Result::Ok;
751 Result ParseInt8(const char* s,
752 const char* end,
753 uint8_t* out,
754 ParseIntType parse_type) {
755 return ParseInt(s, end, out, parse_type);
758 Result ParseInt16(const char* s,
759 const char* end,
760 uint16_t* out,
761 ParseIntType parse_type) {
762 return ParseInt(s, end, out, parse_type);
765 Result ParseInt32(const char* s,
766 const char* end,
767 uint32_t* out,
768 ParseIntType parse_type) {
769 return ParseInt(s, end, out, parse_type);
772 Result ParseFloat(LiteralType literal_type,
773 const char* s,
774 const char* end,
775 uint32_t* out_bits) {
776 return FloatParser<float>::Parse(literal_type, s, end, out_bits);
779 Result ParseDouble(LiteralType literal_type,
780 const char* s,
781 const char* end,
782 uint64_t* out_bits) {
783 return FloatParser<double>::Parse(literal_type, s, end, out_bits);
786 void WriteFloatHex(char* buffer, size_t size, uint32_t bits) {
787 return FloatWriter<float>::WriteHex(buffer, size, bits);
790 void WriteDoubleHex(char* buffer, size_t size, uint64_t bits) {
791 return FloatWriter<double>::WriteHex(buffer, size, bits);
794 void WriteUint128(char* buffer, size_t size, v128 bits) {
795 uint64_t digits;
796 uint64_t remainder;
797 char reversed_buffer[40];
798 size_t len = 0;
799 do {
800 remainder = bits.u32(3);
802 for (int i = 3; i != 0; --i) {
803 digits = remainder / 10;
804 remainder = ((remainder - digits * 10) << 32) + bits.u32(i - 1);
805 bits.set_u32(i, digits);
808 digits = remainder / 10;
809 remainder = remainder - digits * 10;
810 bits.set_u32(0, digits);
812 char remainder_buffer[21];
813 snprintf(remainder_buffer, 21, "%" PRIu64, remainder);
814 int remainder_buffer_len = strlen(remainder_buffer);
815 assert(len + remainder_buffer_len < sizeof(reversed_buffer));
816 memcpy(&reversed_buffer[len], remainder_buffer, remainder_buffer_len);
817 len += remainder_buffer_len;
818 } while (!bits.is_zero());
819 size_t truncated_tail = 0;
820 if (len >= size) {
821 truncated_tail = len - size + 1;
822 len = size - 1;
824 std::reverse_copy(reversed_buffer + truncated_tail,
825 reversed_buffer + len + truncated_tail, buffer);
826 buffer[len] = '\0';
829 } // namespace wabt