diff --git a/std/assembly/internal/itoa.ts b/std/assembly/internal/itoa.ts index f3be8b7b..0f5d36f3 100644 --- a/std/assembly/internal/itoa.ts +++ b/std/assembly/internal/itoa.ts @@ -67,23 +67,27 @@ function DIGITS(): u32[] { return table; // inlines to a constant memory offset } -// Count number of decimals in value -export function decimalCount(value: T): i32 { - var v = abs(value); // NOP if value is unsigned anyway - var l: usize = 8 * sizeof() - clz(v | 10); // log2 - var t = l * 1233 >>> 12; // log10 +// Count number of decimals for u32 values +// In our case input value always non-zero so we can simplify some parts +function decimalCountU32(value: u32): i32 { + var l: usize = 32 - clz(value); // log2 + var t = l * 1233 >>> 12; // log10 var lutbuf = POWERS10().buffer_; - if (sizeof() <= 4) { - let power = loadUnsafe(lutbuf, t); - t -= (v < power); - } else { // sizeof() == 8 - let le10 = t <= 10; - let offset = select(0, 10, le10); // offset = t <= 10 ? 0 : 10 - let factor = select< T >(1, 10000000000, le10); // factor = t <= 10 ? 1 : 10 ^ 10 - let power = loadUnsafe(lutbuf, t - offset); - t -= (v < factor * power); - } + var power = loadUnsafe(lutbuf, t); + t -= (value < power); + return t + 1; +} + +// Count number of decimals for u64 values +// In our case input value always greater than 2^32-1 so we can skip some parts +function decimalCountU64(value: u64): i32 { + var l: usize = 64 - clz(value); // log2 + var t = l * 1233 >>> 12; // log10 + + var lutbuf = POWERS10().buffer_; + var power = loadUnsafe(lutbuf, t - 10); + t -= (value < 10000000000 * power); return t + 1; } @@ -189,7 +193,7 @@ export function utoa64_core(buffer: usize, num: u64, offset: u32): void { export function utoa32(value: u32): string { if (!value) return "0"; - var decimals = decimalCount(value); + var decimals = decimalCountU32(value); var buffer = allocateString(decimals); utoa32_core(changetype(buffer), value, decimals); @@ -202,7 +206,7 @@ export function itoa32(value: i32): string { var isneg = value < 0; if (isneg) value = -value; - var decimals = decimalCount(value) + isneg; + var decimals = decimalCountU32(value) + isneg; var buffer = allocateString(decimals); utoa32_core(changetype(buffer), value, decimals); @@ -217,11 +221,11 @@ export function utoa64(value: u64): string { var buffer: String; if (value <= u32.MAX_VALUE) { let value32 = value; - let decimals = decimalCount(value32); + let decimals = decimalCountU32(value32); buffer = allocateString(decimals); utoa32_core(changetype(buffer), value32, decimals); } else { - let decimals = decimalCount(value); + let decimals = decimalCountU64(value); buffer = allocateString(decimals); utoa64_core(changetype(buffer), value, decimals); } @@ -238,11 +242,11 @@ export function itoa64(value: i64): string { var buffer: String; if (value <= u32.MAX_VALUE) { let value32 = value; - let decimals = decimalCount(value32) + isneg; + let decimals = decimalCountU32(value32) + isneg; buffer = allocateString(decimals); utoa32_core(changetype(buffer), value32, decimals); } else { - let decimals = decimalCount(value) + isneg; + let decimals = decimalCountU64(value) + isneg; buffer = allocateString(decimals); utoa64_core(changetype(buffer), value, decimals); } diff --git a/tests/compiler/std/string.optimized.wat b/tests/compiler/std/string.optimized.wat index eadfbcbb..db2a6fe7 100644 --- a/tests/compiler/std/string.optimized.wat +++ b/tests/compiler/std/string.optimized.wat @@ -3734,7 +3734,7 @@ ) (get_local $4) ) - (func $~lib/internal/itoa/decimalCount (; 27 ;) (type $ii) (param $0 i32) (result i32) + (func $~lib/internal/itoa/decimalCountU32 (; 27 ;) (type $ii) (param $0 i32) (result i32) (local $1 i32) (local $2 i32) (set_local $2 @@ -3750,10 +3750,7 @@ (i32.sub (i32.const 32) (i32.clz - (i32.or - (get_local $0) - (i32.const 10) - ) + (get_local $0) ) ) (i32.const 1233) @@ -3969,7 +3966,7 @@ (call $~lib/internal/string/allocate (tee_local $3 (i32.add - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU32 (get_local $0) ) (get_local $1) @@ -4004,7 +4001,7 @@ (tee_local $2 (call $~lib/internal/string/allocate (tee_local $1 - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU32 (get_local $0) ) ) @@ -4015,31 +4012,38 @@ ) (get_local $2) ) - (func $~lib/internal/itoa/decimalCount (; 31 ;) (type $Ii) (param $0 i64) (result i32) + (func $~lib/internal/itoa/decimalCountU64 (; 31 ;) (type $Ii) (param $0 i64) (result i32) (local $1 i32) - (local $2 i32) + (local $2 i64) (set_local $2 - (i32.le_u - (tee_local $1 - (i32.shr_u - (i32.mul - (i32.sub - (i32.const 64) - (i32.wrap/i64 - (i64.clz - (i64.or - (get_local $0) - (i64.const 10) + (i64.load32_u offset=8 + (i32.add + (i32.load + (i32.const 1400) + ) + (i32.shl + (i32.sub + (tee_local $1 + (i32.shr_u + (i32.mul + (i32.sub + (i32.const 64) + (i32.wrap/i64 + (i64.clz + (get_local $0) + ) + ) ) + (i32.const 1233) ) + (i32.const 12) ) ) - (i32.const 1233) + (i32.const 10) ) - (i32.const 12) + (i32.const 2) ) ) - (i32.const 10) ) ) (i32.add @@ -4048,29 +4052,8 @@ (i64.lt_u (get_local $0) (i64.mul - (select - (i64.const 1) - (i64.const 10000000000) - (get_local $2) - ) - (i64.load32_u offset=8 - (i32.add - (i32.load - (i32.const 1400) - ) - (i32.shl - (i32.sub - (get_local $1) - (select - (i32.const 0) - (i32.const 10) - (get_local $2) - ) - ) - (i32.const 2) - ) - ) - ) + (get_local $2) + (i64.const 10000000000) ) ) ) @@ -4244,7 +4227,7 @@ (tee_local $2 (call $~lib/internal/string/allocate (tee_local $1 - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU32 (tee_local $3 (i32.wrap/i64 (get_local $0) @@ -4261,7 +4244,7 @@ (tee_local $2 (call $~lib/internal/string/allocate (tee_local $1 - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU64 (get_local $0) ) ) @@ -4310,7 +4293,7 @@ (call $~lib/internal/string/allocate (tee_local $2 (i32.add - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU32 (tee_local $4 (i32.wrap/i64 (get_local $0) @@ -4330,7 +4313,7 @@ (call $~lib/internal/string/allocate (tee_local $2 (i32.add - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU64 (get_local $0) ) (get_local $1) diff --git a/tests/compiler/std/string.untouched.wat b/tests/compiler/std/string.untouched.wat index de70dfc8..b34550ed 100644 --- a/tests/compiler/std/string.untouched.wat +++ b/tests/compiler/std/string.untouched.wat @@ -4448,69 +4448,59 @@ ) (get_local $4) ) - (func $~lib/internal/itoa/decimalCount (; 27 ;) (type $ii) (param $0 i32) (result i32) + (func $~lib/internal/itoa/decimalCountU32 (; 27 ;) (type $ii) (param $0 i32) (result i32) (local $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) - (local $5 i32) (set_local $1 - (get_local $0) - ) - (set_local $2 (i32.sub - (i32.mul - (i32.const 8) - (i32.const 4) - ) + (i32.const 32) (i32.clz - (i32.or - (get_local $1) - (i32.const 10) - ) + (get_local $0) ) ) ) - (set_local $3 + (set_local $2 (i32.shr_u (i32.mul - (get_local $2) + (get_local $1) (i32.const 1233) ) (i32.const 12) ) ) - (set_local $4 + (set_local $3 (i32.load (block $~lib/internal/itoa/POWERS10|inlined.0 (result i32) (i32.const 552) ) ) ) - (set_local $5 + (set_local $4 (block $~lib/internal/arraybuffer/loadUnsafe|inlined.0 (result i32) (i32.load offset=8 (i32.add - (get_local $4) + (get_local $3) (i32.shl - (get_local $3) + (get_local $2) (i32.const 2) ) ) ) ) ) - (set_local $3 + (set_local $2 (i32.sub - (get_local $3) + (get_local $2) (i32.lt_u - (get_local $1) - (get_local $5) + (get_local $0) + (get_local $4) ) ) ) (i32.add - (get_local $3) + (get_local $2) (i32.const 1) ) ) @@ -4762,7 +4752,7 @@ ) (set_local $2 (i32.add - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU32 (get_local $0) ) (get_local $1) @@ -4801,7 +4791,7 @@ ) ) (set_local $1 - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU32 (get_local $0) ) ) @@ -4819,45 +4809,32 @@ ) (get_local $2) ) - (func $~lib/internal/itoa/decimalCount (; 31 ;) (type $Ii) (param $0 i64) (result i32) - (local $1 i64) + (func $~lib/internal/itoa/decimalCountU64 (; 31 ;) (type $Ii) (param $0 i64) (result i32) + (local $1 i32) (local $2 i32) (local $3 i32) (local $4 i32) - (local $5 i32) - (local $6 i32) - (local $7 i64) - (local $8 i32) - (local $9 i64) + (local $5 i64) (set_local $1 - (get_local $0) - ) - (set_local $2 (i32.sub - (i32.mul - (i32.const 8) - (i32.const 8) - ) + (i32.const 64) (i32.wrap/i64 (i64.clz - (i64.or - (get_local $1) - (i64.const 10) - ) + (get_local $0) ) ) ) ) - (set_local $3 + (set_local $2 (i32.shr_u (i32.mul - (get_local $2) + (get_local $1) (i32.const 1233) ) (i32.const 12) ) ) - (set_local $4 + (set_local $3 (i32.load (block $~lib/internal/itoa/POWERS10|inlined.1 (result i32) (i32.const 1400) @@ -4865,58 +4842,38 @@ ) ) (set_local $5 - (i32.le_u - (get_local $3) - (i32.const 10) - ) - ) - (set_local $6 - (select - (i32.const 0) - (i32.const 10) - (get_local $5) - ) - ) - (set_local $7 - (select - (i64.const 1) - (i64.const 10000000000) - (get_local $5) - ) - ) - (set_local $9 (block $~lib/internal/arraybuffer/loadUnsafe|inlined.2 (result i64) - (set_local $8 + (set_local $4 (i32.sub - (get_local $3) - (get_local $6) + (get_local $2) + (i32.const 10) ) ) (i64.load32_u offset=8 (i32.add - (get_local $4) + (get_local $3) (i32.shl - (get_local $8) + (get_local $4) (i32.const 2) ) ) ) ) ) - (set_local $3 + (set_local $2 (i32.sub - (get_local $3) + (get_local $2) (i64.lt_u - (get_local $1) + (get_local $0) (i64.mul - (get_local $7) - (get_local $9) + (i64.const 10000000000) + (get_local $5) ) ) ) ) (i32.add - (get_local $3) + (get_local $2) (i32.const 1) ) ) @@ -5140,7 +5097,7 @@ ) ) (set_local $3 - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU32 (get_local $2) ) ) @@ -5159,7 +5116,7 @@ ) (block (set_local $3 - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU64 (get_local $0) ) ) @@ -5220,7 +5177,7 @@ ) (set_local $4 (i32.add - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU32 (get_local $3) ) (get_local $1) @@ -5242,7 +5199,7 @@ (block (set_local $4 (i32.add - (call $~lib/internal/itoa/decimalCount + (call $~lib/internal/itoa/decimalCountU64 (get_local $0) ) (get_local $1)