Skip to content

Commit 9dfe39c

Browse files
MaxGraeydcodeIO
authored andcommitted
Concretize decimal counting in itoa (AssemblyScript#169)
1 parent 6228233 commit 9dfe39c

File tree

3 files changed

+97
-153
lines changed

3 files changed

+97
-153
lines changed

std/assembly/internal/itoa.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,27 @@ function DIGITS(): u32[] {
6767
return table; // inlines to a constant memory offset
6868
}
6969

70-
// Count number of decimals in value
71-
export function decimalCount<T>(value: T): i32 {
72-
var v = abs<T>(value); // NOP if value is unsigned anyway
73-
var l: usize = 8 * sizeof<T>() - <usize>clz<T>(v | 10); // log2
74-
var t = l * 1233 >>> 12; // log10
70+
// Count number of decimals for u32 values
71+
// In our case input value always non-zero so we can simplify some parts
72+
function decimalCountU32(value: u32): i32 {
73+
var l: usize = 32 - <usize>clz<u32>(value); // log2
74+
var t = l * 1233 >>> 12; // log10
7575

7676
var lutbuf = <ArrayBuffer>POWERS10().buffer_;
77-
if (sizeof<T>() <= 4) {
78-
let power = loadUnsafe<u32,T>(lutbuf, t);
79-
t -= <usize>(v < power);
80-
} else { // sizeof<T>() == 8
81-
let le10 = t <= 10;
82-
let offset = select<usize>(0, 10, le10); // offset = t <= 10 ? 0 : 10
83-
let factor = select< T >(1, 10000000000, le10); // factor = t <= 10 ? 1 : 10 ^ 10
84-
let power = loadUnsafe<u32,T>(lutbuf, t - offset);
85-
t -= <usize>(v < factor * power);
86-
}
77+
var power = loadUnsafe<u32,u32>(lutbuf, t);
78+
t -= <usize>(value < power);
79+
return t + 1;
80+
}
81+
82+
// Count number of decimals for u64 values
83+
// In our case input value always greater than 2^32-1 so we can skip some parts
84+
function decimalCountU64(value: u64): i32 {
85+
var l: usize = 64 - <usize>clz<u64>(value); // log2
86+
var t = l * 1233 >>> 12; // log10
87+
88+
var lutbuf = <ArrayBuffer>POWERS10().buffer_;
89+
var power = loadUnsafe<u32,u64>(lutbuf, t - 10);
90+
t -= <usize>(value < 10000000000 * power);
8791
return t + 1;
8892
}
8993

@@ -189,7 +193,7 @@ export function utoa64_core(buffer: usize, num: u64, offset: u32): void {
189193
export function utoa32(value: u32): string {
190194
if (!value) return "0";
191195

192-
var decimals = decimalCount<u32>(value);
196+
var decimals = decimalCountU32(value);
193197
var buffer = allocateString(decimals);
194198

195199
utoa32_core(changetype<usize>(buffer), value, decimals);
@@ -202,7 +206,7 @@ export function itoa32(value: i32): string {
202206
var isneg = value < 0;
203207
if (isneg) value = -value;
204208

205-
var decimals = decimalCount<u32>(value) + <i32>isneg;
209+
var decimals = decimalCountU32(value) + <i32>isneg;
206210
var buffer = allocateString(decimals);
207211

208212
utoa32_core(changetype<usize>(buffer), value, decimals);
@@ -217,11 +221,11 @@ export function utoa64(value: u64): string {
217221
var buffer: String;
218222
if (value <= u32.MAX_VALUE) {
219223
let value32 = <u32>value;
220-
let decimals = decimalCount<u32>(value32);
224+
let decimals = decimalCountU32(value32);
221225
buffer = allocateString(decimals);
222226
utoa32_core(changetype<usize>(buffer), value32, decimals);
223227
} else {
224-
let decimals = decimalCount<u64>(value);
228+
let decimals = decimalCountU64(value);
225229
buffer = allocateString(decimals);
226230
utoa64_core(changetype<usize>(buffer), value, decimals);
227231
}
@@ -238,11 +242,11 @@ export function itoa64(value: i64): string {
238242
var buffer: String;
239243
if (<u64>value <= <u64>u32.MAX_VALUE) {
240244
let value32 = <u32>value;
241-
let decimals = decimalCount<u32>(value32) + <i32>isneg;
245+
let decimals = decimalCountU32(value32) + <i32>isneg;
242246
buffer = allocateString(decimals);
243247
utoa32_core(changetype<usize>(buffer), value32, decimals);
244248
} else {
245-
let decimals = decimalCount<u64>(value) + <i32>isneg;
249+
let decimals = decimalCountU64(value) + <i32>isneg;
246250
buffer = allocateString(decimals);
247251
utoa64_core(changetype<usize>(buffer), value, decimals);
248252
}

tests/compiler/std/string.optimized.wat

Lines changed: 33 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3734,7 +3734,7 @@
37343734
)
37353735
(get_local $4)
37363736
)
3737-
(func $~lib/internal/itoa/decimalCount<u32> (; 27 ;) (type $ii) (param $0 i32) (result i32)
3737+
(func $~lib/internal/itoa/decimalCountU32 (; 27 ;) (type $ii) (param $0 i32) (result i32)
37383738
(local $1 i32)
37393739
(local $2 i32)
37403740
(set_local $2
@@ -3750,10 +3750,7 @@
37503750
(i32.sub
37513751
(i32.const 32)
37523752
(i32.clz
3753-
(i32.or
3754-
(get_local $0)
3755-
(i32.const 10)
3756-
)
3753+
(get_local $0)
37573754
)
37583755
)
37593756
(i32.const 1233)
@@ -3969,7 +3966,7 @@
39693966
(call $~lib/internal/string/allocate
39703967
(tee_local $3
39713968
(i32.add
3972-
(call $~lib/internal/itoa/decimalCount<u32>
3969+
(call $~lib/internal/itoa/decimalCountU32
39733970
(get_local $0)
39743971
)
39753972
(get_local $1)
@@ -4004,7 +4001,7 @@
40044001
(tee_local $2
40054002
(call $~lib/internal/string/allocate
40064003
(tee_local $1
4007-
(call $~lib/internal/itoa/decimalCount<u32>
4004+
(call $~lib/internal/itoa/decimalCountU32
40084005
(get_local $0)
40094006
)
40104007
)
@@ -4015,31 +4012,38 @@
40154012
)
40164013
(get_local $2)
40174014
)
4018-
(func $~lib/internal/itoa/decimalCount<u64> (; 31 ;) (type $Ii) (param $0 i64) (result i32)
4015+
(func $~lib/internal/itoa/decimalCountU64 (; 31 ;) (type $Ii) (param $0 i64) (result i32)
40194016
(local $1 i32)
4020-
(local $2 i32)
4017+
(local $2 i64)
40214018
(set_local $2
4022-
(i32.le_u
4023-
(tee_local $1
4024-
(i32.shr_u
4025-
(i32.mul
4026-
(i32.sub
4027-
(i32.const 64)
4028-
(i32.wrap/i64
4029-
(i64.clz
4030-
(i64.or
4031-
(get_local $0)
4032-
(i64.const 10)
4019+
(i64.load32_u offset=8
4020+
(i32.add
4021+
(i32.load
4022+
(i32.const 1400)
4023+
)
4024+
(i32.shl
4025+
(i32.sub
4026+
(tee_local $1
4027+
(i32.shr_u
4028+
(i32.mul
4029+
(i32.sub
4030+
(i32.const 64)
4031+
(i32.wrap/i64
4032+
(i64.clz
4033+
(get_local $0)
4034+
)
4035+
)
40334036
)
4037+
(i32.const 1233)
40344038
)
4039+
(i32.const 12)
40354040
)
40364041
)
4037-
(i32.const 1233)
4042+
(i32.const 10)
40384043
)
4039-
(i32.const 12)
4044+
(i32.const 2)
40404045
)
40414046
)
4042-
(i32.const 10)
40434047
)
40444048
)
40454049
(i32.add
@@ -4048,29 +4052,8 @@
40484052
(i64.lt_u
40494053
(get_local $0)
40504054
(i64.mul
4051-
(select
4052-
(i64.const 1)
4053-
(i64.const 10000000000)
4054-
(get_local $2)
4055-
)
4056-
(i64.load32_u offset=8
4057-
(i32.add
4058-
(i32.load
4059-
(i32.const 1400)
4060-
)
4061-
(i32.shl
4062-
(i32.sub
4063-
(get_local $1)
4064-
(select
4065-
(i32.const 0)
4066-
(i32.const 10)
4067-
(get_local $2)
4068-
)
4069-
)
4070-
(i32.const 2)
4071-
)
4072-
)
4073-
)
4055+
(get_local $2)
4056+
(i64.const 10000000000)
40744057
)
40754058
)
40764059
)
@@ -4244,7 +4227,7 @@
42444227
(tee_local $2
42454228
(call $~lib/internal/string/allocate
42464229
(tee_local $1
4247-
(call $~lib/internal/itoa/decimalCount<u32>
4230+
(call $~lib/internal/itoa/decimalCountU32
42484231
(tee_local $3
42494232
(i32.wrap/i64
42504233
(get_local $0)
@@ -4261,7 +4244,7 @@
42614244
(tee_local $2
42624245
(call $~lib/internal/string/allocate
42634246
(tee_local $1
4264-
(call $~lib/internal/itoa/decimalCount<u64>
4247+
(call $~lib/internal/itoa/decimalCountU64
42654248
(get_local $0)
42664249
)
42674250
)
@@ -4310,7 +4293,7 @@
43104293
(call $~lib/internal/string/allocate
43114294
(tee_local $2
43124295
(i32.add
4313-
(call $~lib/internal/itoa/decimalCount<u32>
4296+
(call $~lib/internal/itoa/decimalCountU32
43144297
(tee_local $4
43154298
(i32.wrap/i64
43164299
(get_local $0)
@@ -4330,7 +4313,7 @@
43304313
(call $~lib/internal/string/allocate
43314314
(tee_local $2
43324315
(i32.add
4333-
(call $~lib/internal/itoa/decimalCount<u64>
4316+
(call $~lib/internal/itoa/decimalCountU64
43344317
(get_local $0)
43354318
)
43364319
(get_local $1)

0 commit comments

Comments
 (0)