Skip to content

Commit 9c0a8c7

Browse files
authored
fix: Fix stringify min values for i8 and i16 in itoa_buffered (#2140)
1 parent 3819b5d commit 9c0a8c7

34 files changed

+4739
-65838
lines changed

Diff for: std/assembly/util/number.ts

+66-34
Original file line numberDiff line numberDiff line change
@@ -374,23 +374,23 @@ export function itoa32(value: i32, radix: i32): String {
374374
}
375375
if (!value) return "0";
376376

377-
var sign = value >>> 31;
377+
var sign = (value >>> 31) << 1;
378378
if (sign) value = -value;
379379
var out: String;
380380

381381
if (radix == 10) {
382-
let decimals = decimalCount32(value) + sign;
383-
out = changetype<String>(__new(decimals << 1, idof<String>()));
384-
utoa32_dec_core(changetype<usize>(out), value, decimals);
382+
let decimals = decimalCount32(value);
383+
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
384+
utoa32_dec_core(changetype<usize>(out) + sign, value, decimals);
385385
} else if (radix == 16) {
386-
let decimals = (31 - clz(value) >> 2) + 1 + sign;
387-
out = changetype<String>(__new(decimals << 1, idof<String>()));
388-
utoa32_hex_core(changetype<usize>(out), value, decimals);
386+
let decimals = (31 - clz(value) >> 2) + 1;
387+
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
388+
utoa32_hex_core(changetype<usize>(out) + sign, value, decimals);
389389
} else {
390390
let val32 = u32(value);
391-
let decimals = ulog_base(val32, radix) + sign;
392-
out = changetype<String>(__new(decimals << 1, idof<String>()));
393-
utoa64_any_core(changetype<usize>(out), val32, decimals, radix);
391+
let decimals = ulog_base(val32, radix);
392+
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
393+
utoa64_any_core(changetype<usize>(out) + sign, val32, decimals, radix);
394394
}
395395
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
396396
return out;
@@ -432,29 +432,29 @@ export function itoa64(value: i64, radix: i32): String {
432432
}
433433
if (!value) return "0";
434434

435-
var sign = u32(value >>> 63);
435+
var sign = u32(value >>> 63) << 1;
436436
if (sign) value = -value;
437437
var out: String;
438438

439439
if (radix == 10) {
440440
if (<u64>value <= <u64>u32.MAX_VALUE) {
441441
let val32 = <u32>value;
442-
let decimals = decimalCount32(val32) + sign;
443-
out = changetype<String>(__new(decimals << 1, idof<String>()));
444-
utoa32_dec_core(changetype<usize>(out), val32, decimals);
442+
let decimals = decimalCount32(val32);
443+
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
444+
utoa32_dec_core(changetype<usize>(out) + sign, val32, decimals);
445445
} else {
446-
let decimals = decimalCount64High(value) + sign;
447-
out = changetype<String>(__new(decimals << 1, idof<String>()));
448-
utoa64_dec_core(changetype<usize>(out), value, decimals);
446+
let decimals = decimalCount64High(value);
447+
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
448+
utoa64_dec_core(changetype<usize>(out) + sign, value, decimals);
449449
}
450450
} else if (radix == 16) {
451-
let decimals = (63 - u32(clz(value)) >> 2) + 1 + sign;
452-
out = changetype<String>(__new(decimals << 1, idof<String>()));
453-
utoa64_hex_core(changetype<usize>(out), value, decimals);
451+
let decimals = (63 - u32(clz(value)) >> 2) + 1;
452+
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
453+
utoa64_hex_core(changetype<usize>(out) + sign, value, decimals);
454454
} else {
455-
let decimals = ulog_base(value, radix) + sign;
456-
out = changetype<String>(__new(decimals << 1, idof<String>()));
457-
utoa64_any_core(changetype<usize>(out), value, decimals, radix);
455+
let decimals = ulog_base(value, radix);
456+
out = changetype<String>(__new((decimals << 1) + sign, idof<String>()));
457+
utoa64_any_core(changetype<usize>(out) + sign, value, decimals, radix);
458458
}
459459
if (sign) store<u16>(changetype<usize>(out), CharCode.MINUS);
460460
return out;
@@ -748,20 +748,50 @@ export function itoa_buffered<T extends number>(buffer: usize, value: T): u32 {
748748
if (isSigned<T>()) {
749749
sign = u32(value < 0);
750750
if (sign) {
751-
value = changetype<T>(-value);
751+
if (sizeof<T>() == 1) {
752+
if (value == -0x80) {
753+
// -0x80 -> -128
754+
store<u64>(buffer,
755+
<u64>CharCode.MINUS |
756+
<u64>(CharCode._0 + 1) << 16 |
757+
<u64>(CharCode._0 + 2) << 32 |
758+
<u64>(CharCode._0 + 8) << 48
759+
);
760+
return 4;
761+
}
762+
}
763+
if (sizeof<T>() == 2) {
764+
if (value == -0x8000) {
765+
// -0x8000 -> -32768
766+
store<u64>(buffer,
767+
<u64>CharCode.MINUS |
768+
<u64>(CharCode._0 + 3) << 16 |
769+
<u64>(CharCode._0 + 2) << 32 |
770+
<u64>(CharCode._0 + 7) << 48
771+
); // -327
772+
store<u32>(buffer + 8,
773+
(CharCode._0 + 6) << 0 |
774+
(CharCode._0 + 8) << 16
775+
); // 68
776+
return 6;
777+
}
778+
}
752779
store<u16>(buffer, CharCode.MINUS);
780+
// @ts-ignore
781+
value = -value;
753782
}
754783
}
784+
var dest = buffer + (sign << 1);
755785
if (ASC_SHRINK_LEVEL <= 1) {
756786
if (isSigned<T>()) {
757787
if (sizeof<T>() <= 4) {
758788
if (<u32>value < 10) {
759-
store<u16>(buffer + (sign << 1), value | CharCode._0);
789+
store<u16>(dest, value | CharCode._0);
760790
return 1 + sign;
761791
}
762792
} else {
763793
if (<u64>value < 10) {
764-
store<u16>(buffer + (sign << 1), value | CharCode._0);
794+
store<u16>(dest, value | CharCode._0);
765795
return 1 + sign;
766796
}
767797
}
@@ -772,21 +802,23 @@ export function itoa_buffered<T extends number>(buffer: usize, value: T): u32 {
772802
}
773803
}
774804
}
775-
var decimals = sign;
805+
var decimals: u32 = 0;
776806
if (sizeof<T>() <= 4) {
777-
decimals += decimalCount32(value);
778-
utoa32_dec_core(buffer, value, decimals);
807+
let val32 = <u32>value;
808+
decimals = decimalCount32(val32);
809+
utoa32_dec_core(dest, val32, decimals);
779810
} else {
780811
if (<u64>value <= <u64>u32.MAX_VALUE) {
781812
let val32 = <u32>value;
782-
decimals += decimalCount32(val32);
783-
utoa32_dec_core(buffer, val32, decimals);
813+
decimals = decimalCount32(val32);
814+
utoa32_dec_core(dest, val32, decimals);
784815
} else {
785-
decimals += decimalCount64High(value);
786-
utoa64_dec_core(buffer, value, decimals);
816+
let val64 = <u64>value;
817+
decimals = decimalCount64High(val64);
818+
utoa64_dec_core(dest, val64, decimals);
787819
}
788820
}
789-
return decimals;
821+
return sign + decimals;
790822
}
791823

792824
export function dtoa_buffered(buffer: usize, value: f64): u32 {

Diff for: tests/compiler/number.debug.wat

+14-6
Original file line numberDiff line numberDiff line change
@@ -5026,6 +5026,8 @@
50265026
local.get $0
50275027
i32.const 31
50285028
i32.shr_u
5029+
i32.const 1
5030+
i32.shl
50295031
local.set $2
50305032
local.get $2
50315033
if
@@ -5040,18 +5042,20 @@
50405042
if
50415043
local.get $0
50425044
call $~lib/util/number/decimalCount32
5043-
local.get $2
5044-
i32.add
50455045
local.set $4
50465046
global.get $~lib/memory/__stack_pointer
50475047
local.get $4
50485048
i32.const 1
50495049
i32.shl
5050+
local.get $2
5051+
i32.add
50505052
i32.const 1
50515053
call $~lib/rt/itcms/__new
50525054
local.tee $3
50535055
i32.store
50545056
local.get $3
5057+
local.get $2
5058+
i32.add
50555059
local.set $7
50565060
local.get $0
50575061
local.set $6
@@ -5078,18 +5082,20 @@
50785082
i32.shr_s
50795083
i32.const 1
50805084
i32.add
5081-
local.get $2
5082-
i32.add
50835085
local.set $4
50845086
global.get $~lib/memory/__stack_pointer
50855087
local.get $4
50865088
i32.const 1
50875089
i32.shl
5090+
local.get $2
5091+
i32.add
50885092
i32.const 1
50895093
call $~lib/rt/itcms/__new
50905094
local.tee $3
50915095
i32.store
50925096
local.get $3
5097+
local.get $2
5098+
i32.add
50935099
local.set $7
50945100
local.get $0
50955101
local.set $6
@@ -5111,18 +5117,20 @@
51115117
i64.extend_i32_u
51125118
local.get $1
51135119
call $~lib/util/number/ulog_base
5114-
local.get $2
5115-
i32.add
51165120
local.set $7
51175121
global.get $~lib/memory/__stack_pointer
51185122
local.get $7
51195123
i32.const 1
51205124
i32.shl
5125+
local.get $2
5126+
i32.add
51215127
i32.const 1
51225128
call $~lib/rt/itcms/__new
51235129
local.tee $3
51245130
i32.store
51255131
local.get $3
5132+
local.get $2
5133+
i32.add
51265134
local.get $4
51275135
i64.extend_i32_u
51285136
local.get $7

Diff for: tests/compiler/number.release.wat

+18-14
Original file line numberDiff line numberDiff line change
@@ -1560,67 +1560,71 @@
15601560
local.get $0
15611561
i32.const 31
15621562
i32.shr_u
1563-
local.tee $2
1564-
select
1563+
i32.const 1
1564+
i32.shl
15651565
local.tee $1
1566+
select
1567+
local.tee $3
15661568
i32.const 100000
15671569
i32.lt_u
15681570
if (result i32)
1569-
local.get $1
1571+
local.get $3
15701572
i32.const 100
15711573
i32.lt_u
15721574
if (result i32)
1573-
local.get $1
1575+
local.get $3
15741576
i32.const 10
15751577
i32.ge_u
15761578
i32.const 1
15771579
i32.add
15781580
else
1579-
local.get $1
1581+
local.get $3
15801582
i32.const 10000
15811583
i32.ge_u
15821584
i32.const 3
15831585
i32.add
1584-
local.get $1
1586+
local.get $3
15851587
i32.const 1000
15861588
i32.ge_u
15871589
i32.add
15881590
end
15891591
else
1590-
local.get $1
1592+
local.get $3
15911593
i32.const 10000000
15921594
i32.lt_u
15931595
if (result i32)
1594-
local.get $1
1596+
local.get $3
15951597
i32.const 1000000
15961598
i32.ge_u
15971599
i32.const 6
15981600
i32.add
15991601
else
1600-
local.get $1
1602+
local.get $3
16011603
i32.const 1000000000
16021604
i32.ge_u
16031605
i32.const 8
16041606
i32.add
1605-
local.get $1
1607+
local.get $3
16061608
i32.const 100000000
16071609
i32.ge_u
16081610
i32.add
16091611
end
16101612
end
1611-
local.get $2
1612-
i32.add
1613-
local.tee $3
1613+
local.tee $2
16141614
i32.const 1
16151615
i32.shl
1616+
local.get $1
1617+
i32.add
16161618
call $~lib/rt/itcms/__new
16171619
local.tee $0
16181620
i32.store
16191621
local.get $0
16201622
local.get $1
1623+
i32.add
16211624
local.get $3
1622-
call $~lib/util/number/utoa32_dec_lut
16231625
local.get $2
1626+
call $~lib/util/number/utoa32_dec_lut
1627+
local.get $1
16241628
if
16251629
local.get $0
16261630
i32.const 45

0 commit comments

Comments
 (0)