Skip to content
100 changes: 66 additions & 34 deletions std/assembly/util/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,23 +374,23 @@ export function itoa32(value: i32, radix: i32): String {
}
if (!value) return "0";

var sign = value >>> 31;
var sign = (value >>> 31) << 1;
if (sign) value = -value;
var out: String;

if (radix == 10) {
let decimals = decimalCount32(value) + sign;
out = changetype<String>(__new(decimals << 1, idof<String>()));
utoa32_dec_core(changetype<usize>(out), value, decimals);
let decimals = decimalCount32(value);
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
utoa32_dec_core(changetype<usize>(out) + sign, value, decimals);
} else if (radix == 16) {
let decimals = (31 - clz(value) >> 2) + 1 + sign;
out = changetype<String>(__new(decimals << 1, idof<String>()));
utoa32_hex_core(changetype<usize>(out), value, decimals);
let decimals = (31 - clz(value) >> 2) + 1;
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
utoa32_hex_core(changetype<usize>(out) + sign, value, decimals);
} else {
let val32 = u32(value);
let decimals = ulog_base(val32, radix) + sign;
out = changetype<String>(__new(decimals << 1, idof<String>()));
utoa64_any_core(changetype<usize>(out), val32, decimals, radix);
let decimals = ulog_base(val32, radix);
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
utoa64_any_core(changetype<usize>(out) + sign, val32, decimals, radix);
}
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
return out;
Expand Down Expand Up @@ -432,29 +432,29 @@ export function itoa64(value: i64, radix: i32): String {
}
if (!value) return "0";

var sign = u32(value >>> 63);
var sign = u32(value >>> 63) << 1;
if (sign) value = -value;
var out: String;

if (radix == 10) {
if (<u64>value <= <u64>u32.MAX_VALUE) {
let val32 = <u32>value;
let decimals = decimalCount32(val32) + sign;
out = changetype<String>(__new(decimals << 1, idof<String>()));
utoa32_dec_core(changetype<usize>(out), val32, decimals);
let decimals = decimalCount32(val32);
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
utoa32_dec_core(changetype<usize>(out) + sign, val32, decimals);
} else {
let decimals = decimalCount64High(value) + sign;
out = changetype<String>(__new(decimals << 1, idof<String>()));
utoa64_dec_core(changetype<usize>(out), value, decimals);
let decimals = decimalCount64High(value);
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
utoa64_dec_core(changetype<usize>(out) + sign, value, decimals);
}
} else if (radix == 16) {
let decimals = (63 - u32(clz(value)) >> 2) + 1 + sign;
out = changetype<String>(__new(decimals << 1, idof<String>()));
utoa64_hex_core(changetype<usize>(out), value, decimals);
let decimals = (63 - u32(clz(value)) >> 2) + 1;
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
utoa64_hex_core(changetype<usize>(out) + sign, value, decimals);
} else {
let decimals = ulog_base(value, radix) + sign;
out = changetype<String>(__new(decimals << 1, idof<String>()));
utoa64_any_core(changetype<usize>(out), value, decimals, radix);
let decimals = ulog_base(value, radix);
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
utoa64_any_core(changetype<usize>(out) + sign, value, decimals, radix);
}
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
return out;
Expand Down Expand Up @@ -748,20 +748,50 @@ export function itoa_buffered<T extends number>(buffer: usize, value: T): u32 {
if (isSigned<T>()) {
sign = u32(value < 0);
if (sign) {
value = changetype<T>(-value);
if (sizeof<T>() == 1) {
if (value == -0x80) {
// -0x80 -> -128
store<u64>(buffer,
<u64>CharCode.MINUS |
<u64>(CharCode._0 + 1) << 16 |
<u64>(CharCode._0 + 2) << 32 |
<u64>(CharCode._0 + 8) << 48
);
return 4;
}
}
if (sizeof<T>() == 2) {
if (value == -0x8000) {
// -0x8000 -> -32768
store<u64>(buffer,
<u64>CharCode.MINUS |
<u64>(CharCode._0 + 3) << 16 |
<u64>(CharCode._0 + 2) << 32 |
<u64>(CharCode._0 + 7) << 48
); // -327
store<u32>(buffer + 8,
(CharCode._0 + 6) << 0 |
(CharCode._0 + 8) << 16
); // 68
return 6;
}
}
store<u16>(buffer, CharCode.MINUS);
// @ts-ignore
value = -value;
}
}
var dest = buffer + (sign << 1);
if (ASC_SHRINK_LEVEL <= 1) {
if (isSigned<T>()) {
if (sizeof<T>() <= 4) {
if (<u32>value < 10) {
store<u16>(buffer + (sign << 1), value | CharCode._0);
store<u16>(dest, value | CharCode._0);
return 1 + sign;
}
} else {
if (<u64>value < 10) {
store<u16>(buffer + (sign << 1), value | CharCode._0);
store<u16>(dest, value | CharCode._0);
return 1 + sign;
}
}
Expand All @@ -772,21 +802,23 @@ export function itoa_buffered<T extends number>(buffer: usize, value: T): u32 {
}
}
}
var decimals = sign;
var decimals: u32 = 0;
if (sizeof<T>() <= 4) {
decimals += decimalCount32(value);
utoa32_dec_core(buffer, value, decimals);
let val32 = <u32>value;
decimals = decimalCount32(val32);
utoa32_dec_core(dest, val32, decimals);
} else {
if (<u64>value <= <u64>u32.MAX_VALUE) {
let val32 = <u32>value;
decimals += decimalCount32(val32);
utoa32_dec_core(buffer, val32, decimals);
decimals = decimalCount32(val32);
utoa32_dec_core(dest, val32, decimals);
} else {
decimals += decimalCount64High(value);
utoa64_dec_core(buffer, value, decimals);
let val64 = <u64>value;
decimals = decimalCount64High(val64);
utoa64_dec_core(dest, val64, decimals);
}
}
return decimals;
return sign + decimals;
}

export function dtoa_buffered(buffer: usize, value: f64): u32 {
Expand Down
20 changes: 14 additions & 6 deletions tests/compiler/number.debug.wat
Original file line number Diff line number Diff line change
Expand Up @@ -5026,6 +5026,8 @@
local.get $0
i32.const 31
i32.shr_u
i32.const 1
i32.shl
local.set $2
local.get $2
if
Expand All @@ -5040,18 +5042,20 @@
if
local.get $0
call $~lib/util/number/decimalCount32
local.get $2
i32.add
local.set $4
global.get $~lib/memory/__stack_pointer
local.get $4
i32.const 1
i32.shl
local.get $2
i32.add
i32.const 1
call $~lib/rt/itcms/__new
local.tee $3
i32.store
local.get $3
local.get $2
i32.add
local.set $7
local.get $0
local.set $6
Expand All @@ -5078,18 +5082,20 @@
i32.shr_s
i32.const 1
i32.add
local.get $2
i32.add
local.set $4
global.get $~lib/memory/__stack_pointer
local.get $4
i32.const 1
i32.shl
local.get $2
i32.add
i32.const 1
call $~lib/rt/itcms/__new
local.tee $3
i32.store
local.get $3
local.get $2
i32.add
local.set $7
local.get $0
local.set $6
Expand All @@ -5111,18 +5117,20 @@
i64.extend_i32_u
local.get $1
call $~lib/util/number/ulog_base
local.get $2
i32.add
local.set $7
global.get $~lib/memory/__stack_pointer
local.get $7
i32.const 1
i32.shl
local.get $2
i32.add
i32.const 1
call $~lib/rt/itcms/__new
local.tee $3
i32.store
local.get $3
local.get $2
i32.add
local.get $4
i64.extend_i32_u
local.get $7
Expand Down
32 changes: 18 additions & 14 deletions tests/compiler/number.release.wat
Original file line number Diff line number Diff line change
Expand Up @@ -1560,67 +1560,71 @@
local.get $0
i32.const 31
i32.shr_u
local.tee $2
select
i32.const 1
i32.shl
local.tee $1
select
local.tee $3
i32.const 100000
i32.lt_u
if (result i32)
local.get $1
local.get $3
i32.const 100
i32.lt_u
if (result i32)
local.get $1
local.get $3
i32.const 10
i32.ge_u
i32.const 1
i32.add
else
local.get $1
local.get $3
i32.const 10000
i32.ge_u
i32.const 3
i32.add
local.get $1
local.get $3
i32.const 1000
i32.ge_u
i32.add
end
else
local.get $1
local.get $3
i32.const 10000000
i32.lt_u
if (result i32)
local.get $1
local.get $3
i32.const 1000000
i32.ge_u
i32.const 6
i32.add
else
local.get $1
local.get $3
i32.const 1000000000
i32.ge_u
i32.const 8
i32.add
local.get $1
local.get $3
i32.const 100000000
i32.ge_u
i32.add
end
end
local.get $2
i32.add
local.tee $3
local.tee $2
i32.const 1
i32.shl
local.get $1
i32.add
call $~lib/rt/itcms/__new
local.tee $0
i32.store
local.get $0
local.get $1
i32.add
local.get $3
call $~lib/util/number/utoa32_dec_lut
local.get $2
call $~lib/util/number/utoa32_dec_lut
local.get $1
if
local.get $0
i32.const 45
Expand Down
Loading