Skip to content

fix: Fix stringify min values for i8 and i16 in itoa_buffered #2140

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jun 7, 2022
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