Skip to content

Commit 660bd25

Browse files
committed
Speed up exact-integer string formatting
1 parent 84f5f2f commit 660bd25

21 files changed

Lines changed: 13029 additions & 8571 deletions

‎std/assembly/util/number.ts‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,52 @@ export function dtoa<T extends number>(value: T): String {
418418
if (isNaN(value)) return "NaN";
419419
return select<String>("-Infinity", "Infinity", value < 0);
420420
}
421+
// Exact integers in this range can be written into their final allocation.
422+
// The f32 limit matters: larger integral f32 values can have a shorter
423+
// decimal representation than their exact integer value.
424+
let exactIntegerRange = false;
425+
if (isFloat<T>()) {
426+
if (sizeof<T>() == 4) {
427+
let bits = reinterpret<u32>(<f32>value) & 0x7fffffff;
428+
exactIntegerRange = bits >= 0x3f800000 && bits <= 0x4b800000;
429+
} else {
430+
let bits = reinterpret<u64>(<f64>value) & 0x7fffffffffffffff;
431+
exactIntegerRange = bits >= 0x3ff0000000000000 && bits <= 0x41cdcd6500000000;
432+
}
433+
}
434+
if (exactIntegerRange) {
435+
let integer = <i32>value;
436+
if (value == <T>integer) {
437+
let negative = integer < 0;
438+
let magnitude = <u32>(negative ? -integer : integer);
439+
let digits = decimalCount32(magnitude);
440+
let result = changetype<String>(__new(<usize>(digits + u32(negative) + 2) << 1, idof<String>()));
441+
let out = changetype<usize>(result);
442+
if (negative) {
443+
store<u16>(out, CharCode.MINUS);
444+
out += 2;
445+
}
446+
if (magnitude < 10) {
447+
store<u16>(out, CharCode._0 + magnitude);
448+
} else if (magnitude < 100) {
449+
store<u32>(out, load<u32>(DIGITS + (<usize>magnitude << 2)));
450+
} else if (magnitude < 10000) {
451+
let high = magnitude / 100;
452+
let low = magnitude - high * 100;
453+
if (magnitude < 1000) {
454+
store<u16>(out, CharCode._0 + high);
455+
store<u32>(out + 2, load<u32>(DIGITS + (<usize>low << 2)));
456+
} else {
457+
store<u32>(out, load<u32>(DIGITS + (<usize>high << 2)));
458+
store<u32>(out + 4, load<u32>(DIGITS + (<usize>low << 2)));
459+
}
460+
} else {
461+
utoa32_dec_core(out, magnitude, digits);
462+
}
463+
store<u32>(out + (<usize>digits << 1), <u32>CharCode.DOT | (<u32>CharCode._0 << 16));
464+
return result;
465+
}
466+
}
421467
let len: u32;
422468
if (isFloat<T>() && sizeof<T>() == 4) {
423469
// @ts-ignore: type

‎tests/compiler/issues/2873.debug.wat‎

Lines changed: 5208 additions & 4609 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)