From 372062cecdc742ae7101d902c11ae38a1a444a98 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sun, 5 Aug 2018 21:16:12 +0300 Subject: [PATCH 01/12] init (WIP) --- std/assembly/math.ts | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index 3f4b56e2d5..18e0b59ee9 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2303,3 +2303,58 @@ export namespace NativeMathf { return sx ? -x : x; } } + +export function upow(base: u64, exponent: i32): u64 { + if (exponent < 0 || exponent > 64 || !(base << 32)) { + return 0; + } + + switch (exponent) { + case 0: return 1; + case 1: return base; + case 2: return base * base; + default: break; + } + + var result: u64 = 1; + var bs = 32 - clz(exponent); + + // 64 = 2 ^ 6, so need only six cases + switch (bs) { + case 6: { + if (exponent & 1) result *= base; + exponent >>= 1; + base *= base; + } + case 5: { + if (exponent & 1) result *= base; + exponent >>= 1; + base *= base; + } + case 4: { + if (exponent & 1) result *= base; + exponent >>= 1; + base *= base; + } + case 3: { + if (exponent & 1) result *= base; + exponent >>= 1; + base *= base; + } + case 2: { + if (exponent & 1) result *= base; + exponent >>= 1; + base *= base; + } + case 1: { + if (exponent & 1) result *= base; + } + default: break; + } + + return result; +} + +export function ipow(base: i64, exponent: i32): i64 { + return upow(base, exponent); +} From f2b4833c06cd3d66225319ad4a2fd5facaf10bab Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Sun, 5 Aug 2018 21:21:04 +0300 Subject: [PATCH 02/12] refactor --- std/assembly/math.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index 18e0b59ee9..4258f5ef1f 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2305,10 +2305,7 @@ export namespace NativeMathf { } export function upow(base: u64, exponent: i32): u64 { - if (exponent < 0 || exponent > 64 || !(base << 32)) { - return 0; - } - + if (exponent < 0) return 0; switch (exponent) { case 0: return 1; case 1: return base; @@ -2316,6 +2313,8 @@ export function upow(base: u64, exponent: i32): u64 { default: break; } + if (exponent > 64 || !(base << 32)) return 0; + var result: u64 = 1; var bs = 32 - clz(exponent); From 95be0cf63628f9f9e66cc6f347e1e574592c7acf Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 6 Aug 2018 00:12:08 +0300 Subject: [PATCH 03/12] update (wip) --- std/assembly/math.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index 4258f5ef1f..569a40ed22 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2313,7 +2313,8 @@ export function upow(base: u64, exponent: i32): u64 { default: break; } - if (exponent > 64 || !(base << 32)) return 0; + if (base == 1) return 1; + if (exponent >= 64 || !(base << 32)) return 0; var result: u64 = 1; var bs = 32 - clz(exponent); From 16c4a7f19b4b016fdd269e8ff9ad27feede3fab3 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 6 Aug 2018 00:35:12 +0300 Subject: [PATCH 04/12] remove redundance code for speedup --- std/assembly/math.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index 569a40ed22..dd213218e6 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2310,17 +2310,14 @@ export function upow(base: u64, exponent: i32): u64 { case 0: return 1; case 1: return base; case 2: return base * base; - default: break; } - if (base == 1) return 1; - if (exponent >= 64 || !(base << 32)) return 0; - var result: u64 = 1; var bs = 32 - clz(exponent); // 64 = 2 ^ 6, so need only six cases switch (bs) { + default: case 6: { if (exponent & 1) result *= base; exponent >>= 1; @@ -2349,7 +2346,6 @@ export function upow(base: u64, exponent: i32): u64 { case 1: { if (exponent & 1) result *= base; } - default: break; } return result; From 9e1c862bbc1fb97d80dab3837deed4356aa6129f Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 6 Aug 2018 01:11:15 +0300 Subject: [PATCH 05/12] use shorter name for identifiers --- std/assembly/math.ts | 54 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index dd213218e6..70c97d8895 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2304,53 +2304,53 @@ export namespace NativeMathf { } } -export function upow(base: u64, exponent: i32): u64 { - if (exponent < 0) return 0; - switch (exponent) { +export function upow(x: u64, e: i32): u64 { + if (e < 0) return 0; + switch (e) { case 0: return 1; - case 1: return base; - case 2: return base * base; + case 1: return x; + case 2: return x * x; } - var result: u64 = 1; - var bs = 32 - clz(exponent); + var out: u64 = 1; + var log = 32 - clz(e); // 64 = 2 ^ 6, so need only six cases - switch (bs) { + switch (log) { default: case 6: { - if (exponent & 1) result *= base; - exponent >>= 1; - base *= base; + if (e & 1) out *= x; + e >>= 1; + x *= x; } case 5: { - if (exponent & 1) result *= base; - exponent >>= 1; - base *= base; + if (e & 1) out *= x; + e >>= 1; + x *= x; } case 4: { - if (exponent & 1) result *= base; - exponent >>= 1; - base *= base; + if (e & 1) out *= x; + e >>= 1; + x *= x; } case 3: { - if (exponent & 1) result *= base; - exponent >>= 1; - base *= base; + if (e & 1) out *= x; + e >>= 1; + x *= x; } case 2: { - if (exponent & 1) result *= base; - exponent >>= 1; - base *= base; + if (e & 1) out *= x; + e >>= 1; + x *= x; } case 1: { - if (exponent & 1) result *= base; + if (e & 1) out *= x; } } - return result; + return out; } -export function ipow(base: i64, exponent: i32): i64 { - return upow(base, exponent); +export function ipow(x: i64, e: i32): i64 { + return upow(x, e); } From c32bcd2cbc83bb54eeb379ef885caebb9bc2eadb Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 6 Aug 2018 01:20:14 +0300 Subject: [PATCH 06/12] early reject overflowed results --- std/assembly/math.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index 70c97d8895..fe3ea62d11 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2314,10 +2314,10 @@ export function upow(x: u64, e: i32): u64 { var out: u64 = 1; var log = 32 - clz(e); + if (log > 6) return 0; // 64 = 2 ^ 6, so need only six cases switch (log) { - default: case 6: { if (e & 1) out *= x; e >>= 1; From 6fe1e80f96eac2ab886d837cacafb2453e5a02e7 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 6 Aug 2018 01:39:25 +0300 Subject: [PATCH 07/12] update. Make two versions ipow32 & ipow64 --- std/assembly/math.ts | 50 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index fe3ea62d11..e0d679bdfd 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2304,7 +2304,7 @@ export namespace NativeMathf { } } -export function upow(x: u64, e: i32): u64 { +export function ipow32(x: i32, e: i32): i32 { if (e < 0) return 0; switch (e) { case 0: return 1; @@ -2312,7 +2312,49 @@ export function upow(x: u64, e: i32): u64 { case 2: return x * x; } - var out: u64 = 1; + var out = 1; + var log = 32 - clz(e); + if (log > 5) return 0; + + // 32 = 2 ^ 5, so need only six cases + switch (log) { + case 5: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 4: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 3: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 2: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 1: { + if (e & 1) out *= x; + } + } + + return out; +} + +export function ipow64(x: i64, e: i32): i64 { + if (e < 0) return 0; + switch (e) { + case 0: return 1; + case 1: return x; + case 2: return x * x; + } + + var out: i64 = 1; var log = 32 - clz(e); if (log > 6) return 0; @@ -2350,7 +2392,3 @@ export function upow(x: u64, e: i32): u64 { return out; } - -export function ipow(x: i64, e: i32): i64 { - return upow(x, e); -} From 8436ff548f5e34ca9f3437346f2c8efffd3c56bd Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 6 Aug 2018 14:54:54 +0300 Subject: [PATCH 08/12] minor refactoring --- std/assembly/math.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index e0d679bdfd..fa9c87778a 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2312,11 +2312,11 @@ export function ipow32(x: i32, e: i32): i32 { case 2: return x * x; } - var out = 1; var log = 32 - clz(e); if (log > 5) return 0; + var out = 1; - // 32 = 2 ^ 5, so need only six cases + // 32 = 2 ^ 5, so need only five cases switch (log) { case 5: { if (e & 1) out *= x; @@ -2354,9 +2354,9 @@ export function ipow64(x: i64, e: i32): i64 { case 2: return x * x; } - var out: i64 = 1; var log = 32 - clz(e); if (log > 6) return 0; + var out: i64 = 1; // 64 = 2 ^ 6, so need only six cases switch (log) { From d03cbc2018d085981216355804287048f48fcac3 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 6 Aug 2018 19:43:23 +0300 Subject: [PATCH 09/12] add tests for ipow64 --- std/assembly/math.ts | 27 +- tests/compiler/std/math.optimized.wat | 728 +++++++++++++++++++++- tests/compiler/std/math.ts | 37 ++ tests/compiler/std/math.untouched.wat | 843 +++++++++++++++++++++++++- 4 files changed, 1627 insertions(+), 8 deletions(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index fa9c87778a..4767270fd3 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2313,11 +2313,21 @@ export function ipow32(x: i32, e: i32): i32 { } var log = 32 - clz(e); - if (log > 5) return 0; var out = 1; - // 32 = 2 ^ 5, so need only five cases - switch (log) { + // 32 = 2 ^ 5, so need only five cases. + // But some extra cases needs for properly overflowing + switch (log & 7) { + case 7: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 6: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } case 5: { if (e & 1) out *= x; e >>= 1; @@ -2355,11 +2365,16 @@ export function ipow64(x: i64, e: i32): i64 { } var log = 32 - clz(e); - if (log > 6) return 0; var out: i64 = 1; - // 64 = 2 ^ 6, so need only six cases - switch (log) { + // 64 = 2 ^ 6, so need only six cases. + // But some extra cases needs for properly overflowing + switch (log & 7) { + case 7: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } case 6: { if (e & 1) out *= x; e >>= 1; diff --git a/tests/compiler/std/math.optimized.wat b/tests/compiler/std/math.optimized.wat index 37e5126391..b83197c253 100644 --- a/tests/compiler/std/math.optimized.wat +++ b/tests/compiler/std/math.optimized.wat @@ -20,6 +20,7 @@ (type $Iv (func (param i64))) (type $II (func (param i64) (result i64))) (type $f (func (result f32))) + (type $IiI (func (param i64 i32) (result i64))) (type $v (func)) (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32))) (import "JSMath" "E" (global $~lib/math/JSMath.E f64)) @@ -13981,7 +13982,246 @@ (get_local $3) ) ) - (func $start (; 158 ;) (; has Stack IR ;) (type $v) + (func $~lib/math/ipow64 (; 158 ;) (; has Stack IR ;) (type $IiI) (param $0 i64) (param $1 i32) (result i64) + (local $2 i64) + (local $3 i32) + (if + (i32.lt_s + (get_local $1) + (i32.const 0) + ) + (return + (i64.const 0) + ) + ) + (block $break|0 + (block $case2|0 + (block $case1|0 + (if + (get_local $1) + (block + (br_if $case1|0 + (i32.eq + (get_local $1) + (i32.const 1) + ) + ) + (br_if $case2|0 + (i32.eq + (get_local $1) + (i32.const 2) + ) + ) + (br $break|0) + ) + ) + (return + (i64.const 1) + ) + ) + (return + (get_local $0) + ) + ) + (return + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (set_local $2 + (i64.const 1) + ) + (block $case7|1 + (block $case6|1 + (block $case5|1 + (block $case4|1 + (block $case3|1 + (block $case2|1 + (if + (i32.ne + (tee_local $3 + (i32.sub + (i32.const 32) + (i32.clz + (get_local $1) + ) + ) + ) + (i32.const 7) + ) + (block $tablify|0 + (br_table $case7|1 $case6|1 $case5|1 $case4|1 $case3|1 $case2|1 $tablify|0 + (i32.sub + (get_local $3) + (i32.const 1) + ) + ) + ) + ) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (get_local $0) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (i64.mul + (get_local $2) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (i64.mul + (get_local $2) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (i64.mul + (get_local $2) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (i64.mul + (get_local $2) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (i64.mul + (get_local $2) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (i64.mul + (get_local $2) + (get_local $0) + ) + ) + ) + (get_local $2) + ) + (func $start (; 159 ;) (; has Stack IR ;) (type $v) (local $0 i32) (local $1 i32) (local $2 f64) @@ -53243,5 +53483,491 @@ (unreachable) ) ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 0) + (i32.const 0) + ) + (i64.const 1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3123) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 0) + (i32.const 1) + ) + (i64.const 0) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3124) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 0) + (i32.const 2) + ) + (i64.const 0) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3125) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 0) + (i32.const 3) + ) + (i64.const 0) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3126) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 1) + (i32.const 0) + ) + (i64.const 1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3128) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 1) + (i32.const 1) + ) + (i64.const 1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3129) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 1) + (i32.const 2) + ) + (i64.const 1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3130) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 1) + (i32.const 3) + ) + (i64.const 1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3131) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 2) + (i32.const 0) + ) + (i64.const 1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3133) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 2) + (i32.const 1) + ) + (i64.const 2) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3134) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 2) + (i32.const 2) + ) + (i64.const 4) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3135) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 2) + (i32.const 3) + ) + (i64.const 8) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3136) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const -1) + (i32.const 0) + ) + (i64.const 1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3138) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const -1) + (i32.const 1) + ) + (i64.const -1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3139) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const -1) + (i32.const 2) + ) + (i64.const 1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3140) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const -1) + (i32.const 3) + ) + (i64.const -1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3141) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const -2) + (i32.const 0) + ) + (i64.const 1) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3143) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const -2) + (i32.const 1) + ) + (i64.const -2) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3144) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const -2) + (i32.const 2) + ) + (i64.const 4) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3145) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const -2) + (i32.const 3) + ) + (i64.const -8) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3146) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 40) + ) + (i64.const -6289078614652622815) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3148) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 41) + ) + (i64.const -420491770248316829) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3149) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 42) + ) + (i64.const -1261475310744950487) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3150) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 43) + ) + (i64.const -3784425932234851461) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3151) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 63) + ) + (i64.const -3237885987332494933) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3152) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 64) + ) + (i64.const 8733086111712066817) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3153) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i64.ne + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 128) + ) + (i64.const -9204772141784466943) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3154) + (i32.const 0) + ) + (unreachable) + ) + ) ) ) diff --git a/tests/compiler/std/math.ts b/tests/compiler/std/math.ts index 03dfd203fa..f797127d82 100644 --- a/tests/compiler/std/math.ts +++ b/tests/compiler/std/math.ts @@ -3117,3 +3117,40 @@ assert(test_truncf(0.9999923706, 0.0, 0.0, INEXACT)); assert(test_truncf(-0.9999923706, -0.0, 0.0, INEXACT)); assert(test_truncf(7.888609052e-31, 0.0, 0.0, INEXACT)); assert(test_truncf(-7.888609052e-31, -0.0, 0.0, INEXACT)); + +// ipow64 ///////////////////////////////////////////////////////////////////////////////////// + +assert(ipow64(0, 0) == 1); +assert(ipow64(0, 1) == 0); +assert(ipow64(0, 2) == 0); +assert(ipow64(0, 3) == 0); + +assert(ipow64(1, 0) == 1); +assert(ipow64(1, 1) == 1); +assert(ipow64(1, 2) == 1); +assert(ipow64(1, 3) == 1); + +assert(ipow64(2, 0) == 1); +assert(ipow64(2, 1) == 2); +assert(ipow64(2, 2) == 4); +assert(ipow64(2, 3) == 8); + +assert(ipow64(-1, 0) == 1); +assert(ipow64(-1, 1) == -1); +assert(ipow64(-1, 2) == 1); +assert(ipow64(-1, 3) == -1); + +assert(ipow64(-2, 0) == 1); +assert(ipow64(-2, 1) == -2); +assert(ipow64(-2, 2) == 4); +assert(ipow64(-2, 3) == -8); + +assert(ipow64(3, 40) == 12157665459056928801); +assert(ipow64(3, 41) == -420491770248316829); // should overflow +assert(ipow64(3, 42) == -1261475310744950487); // should overflow +assert(ipow64(3, 43) == -3784425932234851461); // should overflow +assert(ipow64(3, 63) == -3237885987332494933); // should overflow +assert(ipow64(3, 64) == 8733086111712066817); // should overflow + +// fail +// assert(ipow64(3, 128) == -9204772141784466943); // should overflow diff --git a/tests/compiler/std/math.untouched.wat b/tests/compiler/std/math.untouched.wat index 81b4123863..82fb7a1676 100644 --- a/tests/compiler/std/math.untouched.wat +++ b/tests/compiler/std/math.untouched.wat @@ -20,6 +20,7 @@ (type $Iv (func (param i64))) (type $II (func (param i64) (result i64))) (type $f (func (result f32))) + (type $IiI (func (param i64 i32) (result i64))) (type $v (func)) (import "env" "abort" (func $~lib/env/abort (param i32 i32 i32 i32))) (import "JSMath" "E" (global $~lib/math/JSMath.E f64)) @@ -16116,7 +16117,307 @@ (get_local $3) ) ) - (func $start (; 158 ;) (type $v) + (func $~lib/math/ipow64 (; 158 ;) (type $IiI) (param $0 i64) (param $1 i32) (result i64) + (local $2 i32) + (local $3 i32) + (local $4 i64) + (if + (i32.lt_s + (get_local $1) + (i32.const 0) + ) + (return + (i64.const 0) + ) + ) + (block $break|0 + (block $case2|0 + (block $case1|0 + (block $case0|0 + (set_local $2 + (get_local $1) + ) + (br_if $case0|0 + (i32.eq + (get_local $2) + (i32.const 0) + ) + ) + (br_if $case1|0 + (i32.eq + (get_local $2) + (i32.const 1) + ) + ) + (br_if $case2|0 + (i32.eq + (get_local $2) + (i32.const 2) + ) + ) + (br $break|0) + ) + (return + (i64.const 1) + ) + ) + (return + (get_local $0) + ) + ) + (return + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (set_local $3 + (i32.sub + (i32.const 32) + (i32.clz + (get_local $1) + ) + ) + ) + (set_local $4 + (i64.const 1) + ) + (block $break|1 + (block $case7|1 + (block $case6|1 + (block $case5|1 + (block $case4|1 + (block $case3|1 + (block $case2|1 + (block $case1|1 + (block $case0|1 + (set_local $2 + (get_local $3) + ) + (br_if $case1|1 + (i32.eq + (get_local $2) + (i32.const 7) + ) + ) + (br_if $case2|1 + (i32.eq + (get_local $2) + (i32.const 6) + ) + ) + (br_if $case3|1 + (i32.eq + (get_local $2) + (i32.const 5) + ) + ) + (br_if $case4|1 + (i32.eq + (get_local $2) + (i32.const 4) + ) + ) + (br_if $case5|1 + (i32.eq + (get_local $2) + (i32.const 3) + ) + ) + (br_if $case6|1 + (i32.eq + (get_local $2) + (i32.const 2) + ) + ) + (br_if $case7|1 + (i32.eq + (get_local $2) + (i32.const 1) + ) + ) + (br $case0|1) + ) + ) + (block + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $4 + (i64.mul + (get_local $4) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + ) + (block + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $4 + (i64.mul + (get_local $4) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + ) + (block + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $4 + (i64.mul + (get_local $4) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + ) + (block + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $4 + (i64.mul + (get_local $4) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + ) + (block + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $4 + (i64.mul + (get_local $4) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + ) + (block + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $4 + (i64.mul + (get_local $4) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + ) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $4 + (i64.mul + (get_local $4) + (get_local $0) + ) + ) + ) + ) + (get_local $4) + ) + (func $start (; 159 ;) (type $v) (local $0 i32) (local $1 f64) (local $2 i32) @@ -56130,5 +56431,545 @@ (unreachable) ) ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 0) + (i32.const 0) + ) + (i64.const 1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3123) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 0) + (i32.const 1) + ) + (i64.const 0) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3124) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 0) + (i32.const 2) + ) + (i64.const 0) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3125) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 0) + (i32.const 3) + ) + (i64.const 0) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3126) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 1) + (i32.const 0) + ) + (i64.const 1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3128) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 1) + (i32.const 1) + ) + (i64.const 1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3129) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 1) + (i32.const 2) + ) + (i64.const 1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3130) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 1) + (i32.const 3) + ) + (i64.const 1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3131) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 2) + (i32.const 0) + ) + (i64.const 1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3133) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 2) + (i32.const 1) + ) + (i64.const 2) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3134) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 2) + (i32.const 2) + ) + (i64.const 4) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3135) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 2) + (i32.const 3) + ) + (i64.const 8) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3136) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const -1) + (i32.const 0) + ) + (i64.const 1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3138) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const -1) + (i32.const 1) + ) + (i64.const -1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3139) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const -1) + (i32.const 2) + ) + (i64.const 1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3140) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const -1) + (i32.const 3) + ) + (i64.const -1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3141) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const -2) + (i32.const 0) + ) + (i64.const 1) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3143) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const -2) + (i32.const 1) + ) + (i64.const -2) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3144) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const -2) + (i32.const 2) + ) + (i64.const 4) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3145) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const -2) + (i32.const 3) + ) + (i64.const -8) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3146) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 40) + ) + (i64.const -6289078614652622815) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3148) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 41) + ) + (i64.const -420491770248316829) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3149) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 42) + ) + (i64.const -1261475310744950487) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3150) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 43) + ) + (i64.const -3784425932234851461) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3151) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 63) + ) + (i64.const -3237885987332494933) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3152) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 64) + ) + (i64.const 8733086111712066817) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3153) + (i32.const 0) + ) + (unreachable) + ) + ) + (if + (i32.eqz + (i64.eq + (call $~lib/math/ipow64 + (i64.const 3) + (i32.const 128) + ) + (i64.const -9204772141784466943) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3154) + (i32.const 0) + ) + (unreachable) + ) + ) ) ) From d913de71afa3fdddd5a16de19a3c0bdfa380bcdd Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 6 Aug 2018 21:45:26 +0300 Subject: [PATCH 10/12] handle overflow with big exponents and optimaze for shinkage >= 1 --- std/assembly/math.ts | 149 +++++++++++---------- tests/compiler/std/math.optimized.wat | 185 +++++++++++++++----------- tests/compiler/std/math.ts | 4 +- tests/compiler/std/math.untouched.wat | 179 +++++++++++++------------ 4 files changed, 280 insertions(+), 237 deletions(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index 4767270fd3..b5e1d5f708 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2312,47 +2312,47 @@ export function ipow32(x: i32, e: i32): i32 { case 2: return x * x; } - var log = 32 - clz(e); var out = 1; + var log = 32 - clz(e); - // 32 = 2 ^ 5, so need only five cases. - // But some extra cases needs for properly overflowing - switch (log & 7) { - case 7: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 6: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 5: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 4: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 3: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 2: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 1: { - if (e & 1) out *= x; + if (ASC_SHRINK_LEVEL < 1) { + if (log <= 5) { + // 32 = 2 ^ 5, so need only five cases. + // But some extra cases needs for properly overflowing + switch (log) { + case 5: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 4: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 3: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 2: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 1: { + if (e & 1) out *= x; + } + } + return out; } } + while (e > 0) { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } return out; } @@ -2364,46 +2364,51 @@ export function ipow64(x: i64, e: i32): i64 { case 2: return x * x; } - var log = 32 - clz(e); var out: i64 = 1; + var log = 32 - clz(e); - // 64 = 2 ^ 6, so need only six cases. - // But some extra cases needs for properly overflowing - switch (log & 7) { - case 7: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 6: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 5: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 4: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 3: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 2: { - if (e & 1) out *= x; - e >>= 1; - x *= x; - } - case 1: { - if (e & 1) out *= x; + if (ASC_SHRINK_LEVEL < 1) { + if (log <= 6) { + // 64 = 2 ^ 6, so need only six cases. + // But some extra cases needs for properly overflowing + switch (log) { + case 6: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 5: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 4: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 3: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 2: { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } + case 1: { + if (e & 1) out *= x; + } + } + return out; } } + while (e > 0) { + if (e & 1) out *= x; + e >>= 1; + x *= x; + } return out; } diff --git a/tests/compiler/std/math.optimized.wat b/tests/compiler/std/math.optimized.wat index b83197c253..c8b04c22cd 100644 --- a/tests/compiler/std/math.optimized.wat +++ b/tests/compiler/std/math.optimized.wat @@ -14033,31 +14033,87 @@ (set_local $2 (i64.const 1) ) - (block $case7|1 - (block $case6|1 - (block $case5|1 - (block $case4|1 - (block $case3|1 - (block $case2|1 - (if - (i32.ne - (tee_local $3 - (i32.sub - (i32.const 32) - (i32.clz - (get_local $1) + (if + (i32.le_s + (tee_local $3 + (i32.sub + (i32.const 32) + (i32.clz + (get_local $1) + ) + ) + ) + (i32.const 6) + ) + (block + (block $break|1 + (block $case5|1 + (block $case4|1 + (block $case3|1 + (block $case2|1 + (block $case1|1 + (if + (i32.ne + (get_local $3) + (i32.const 6) + ) + (block + (block $tablify|0 + (br_table $case5|1 $case4|1 $case3|1 $case2|1 $case1|1 $tablify|0 + (i32.sub + (get_local $3) + (i32.const 1) + ) + ) ) + (br $break|1) ) ) - (i32.const 7) - ) - (block $tablify|0 - (br_table $case7|1 $case6|1 $case5|1 $case4|1 $case3|1 $case2|1 $tablify|0 - (i32.sub - (get_local $3) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (get_local $0) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) (i32.const 1) ) ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (i64.mul + (get_local $2) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) ) ) (if @@ -14066,7 +14122,10 @@ (i32.const 1) ) (set_local $2 - (get_local $0) + (i64.mul + (get_local $2) + (get_local $0) + ) ) ) (set_local $1 @@ -14144,6 +14203,31 @@ ) ) ) + ) + (return + (get_local $2) + ) + ) + ) + (loop $continue|2 + (if + (i32.gt_s + (get_local $1) + (i32.const 0) + ) + (block + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $2 + (i64.mul + (get_local $2) + (get_local $0) + ) + ) + ) (set_local $1 (i32.shr_s (get_local $1) @@ -14156,66 +14240,7 @@ (get_local $0) ) ) - ) - (if - (i32.and - (get_local $1) - (i32.const 1) - ) - (set_local $2 - (i64.mul - (get_local $2) - (get_local $0) - ) - ) - ) - (set_local $1 - (i32.shr_s - (get_local $1) - (i32.const 1) - ) - ) - (set_local $0 - (i64.mul - (get_local $0) - (get_local $0) - ) - ) - ) - (if - (i32.and - (get_local $1) - (i32.const 1) - ) - (set_local $2 - (i64.mul - (get_local $2) - (get_local $0) - ) - ) - ) - (set_local $1 - (i32.shr_s - (get_local $1) - (i32.const 1) - ) - ) - (set_local $0 - (i64.mul - (get_local $0) - (get_local $0) - ) - ) - ) - (if - (i32.and - (get_local $1) - (i32.const 1) - ) - (set_local $2 - (i64.mul - (get_local $2) - (get_local $0) + (br $continue|2) ) ) ) diff --git a/tests/compiler/std/math.ts b/tests/compiler/std/math.ts index f797127d82..737c427d16 100644 --- a/tests/compiler/std/math.ts +++ b/tests/compiler/std/math.ts @@ -3151,6 +3151,4 @@ assert(ipow64(3, 42) == -1261475310744950487); // should overflow assert(ipow64(3, 43) == -3784425932234851461); // should overflow assert(ipow64(3, 63) == -3237885987332494933); // should overflow assert(ipow64(3, 64) == 8733086111712066817); // should overflow - -// fail -// assert(ipow64(3, 128) == -9204772141784466943); // should overflow +assert(ipow64(3, 128) == -9204772141784466943); // should overflow diff --git a/tests/compiler/std/math.untouched.wat b/tests/compiler/std/math.untouched.wat index 82fb7a1676..91fa7dd697 100644 --- a/tests/compiler/std/math.untouched.wat +++ b/tests/compiler/std/math.untouched.wat @@ -86,6 +86,7 @@ (global $~lib/math/random_state1 (mut i64) (i64.const 0)) (global $~lib/builtins/f64.EPSILON f64 (f64.const 2.220446049250313e-16)) (global $~lib/builtins/f32.EPSILON f32 (f32.const 1.1920928955078125e-07)) + (global $ASC_SHRINK_LEVEL i32 (i32.const 0)) (global $HEAP_BASE i32 (i32.const 68)) (memory $0 1) (data (i32.const 8) "\0b\00\00\00s\00t\00d\00/\00m\00a\00t\00h\00.\00t\00s\00") @@ -16119,8 +16120,8 @@ ) (func $~lib/math/ipow64 (; 158 ;) (type $IiI) (param $0 i64) (param $1 i32) (result i64) (local $2 i32) - (local $3 i32) - (local $4 i64) + (local $3 i64) + (local $4 i32) (if (i32.lt_s (get_local $1) @@ -16173,6 +16174,9 @@ ) ) (set_local $3 + (i64.const 1) + ) + (set_local $4 (i32.sub (i32.const 32) (i32.clz @@ -16180,12 +16184,13 @@ ) ) ) - (set_local $4 - (i64.const 1) - ) - (block $break|1 - (block $case7|1 - (block $case6|1 + (if + (i32.le_s + (get_local $4) + (i32.const 6) + ) + (block + (block $break|1 (block $case5|1 (block $case4|1 (block $case3|1 @@ -16193,51 +16198,71 @@ (block $case1|1 (block $case0|1 (set_local $2 - (get_local $3) - ) - (br_if $case1|1 - (i32.eq - (get_local $2) - (i32.const 7) - ) + (get_local $4) ) - (br_if $case2|1 + (br_if $case0|1 (i32.eq (get_local $2) (i32.const 6) ) ) - (br_if $case3|1 + (br_if $case1|1 (i32.eq (get_local $2) (i32.const 5) ) ) - (br_if $case4|1 + (br_if $case2|1 (i32.eq (get_local $2) (i32.const 4) ) ) - (br_if $case5|1 + (br_if $case3|1 (i32.eq (get_local $2) (i32.const 3) ) ) - (br_if $case6|1 + (br_if $case4|1 (i32.eq (get_local $2) (i32.const 2) ) ) - (br_if $case7|1 + (br_if $case5|1 (i32.eq (get_local $2) (i32.const 1) ) ) - (br $case0|1) + (br $break|1) + ) + (block + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $3 + (i64.mul + (get_local $3) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) ) ) (block @@ -16246,9 +16271,9 @@ (get_local $1) (i32.const 1) ) - (set_local $4 + (set_local $3 (i64.mul - (get_local $4) + (get_local $3) (get_local $0) ) ) @@ -16273,9 +16298,9 @@ (get_local $1) (i32.const 1) ) - (set_local $4 + (set_local $3 (i64.mul - (get_local $4) + (get_local $3) (get_local $0) ) ) @@ -16300,9 +16325,9 @@ (get_local $1) (i32.const 1) ) - (set_local $4 + (set_local $3 (i64.mul - (get_local $4) + (get_local $3) (get_local $0) ) ) @@ -16327,9 +16352,9 @@ (get_local $1) (i32.const 1) ) - (set_local $4 + (set_local $3 (i64.mul - (get_local $4) + (get_local $3) (get_local $0) ) ) @@ -16348,74 +16373,64 @@ ) ) ) - (block - (if - (i32.and - (get_local $1) - (i32.const 1) - ) - (set_local $4 - (i64.mul - (get_local $4) - (get_local $0) - ) - ) - ) - (set_local $1 - (i32.shr_s - (get_local $1) - (i32.const 1) - ) - ) - (set_local $0 - (i64.mul - (get_local $0) - (get_local $0) - ) - ) - ) - ) - (block (if (i32.and (get_local $1) (i32.const 1) ) - (set_local $4 + (set_local $3 (i64.mul - (get_local $4) + (get_local $3) (get_local $0) ) ) ) - (set_local $1 - (i32.shr_s - (get_local $1) - (i32.const 1) - ) - ) - (set_local $0 - (i64.mul - (get_local $0) - (get_local $0) - ) - ) ) - ) - (if - (i32.and - (get_local $1) - (i32.const 1) + (return + (get_local $3) ) - (set_local $4 - (i64.mul - (get_local $4) - (get_local $0) + ) + ) + (block $break|2 + (loop $continue|2 + (if + (i32.gt_s + (get_local $1) + (i32.const 0) + ) + (block + (block + (if + (i32.and + (get_local $1) + (i32.const 1) + ) + (set_local $3 + (i64.mul + (get_local $3) + (get_local $0) + ) + ) + ) + (set_local $1 + (i32.shr_s + (get_local $1) + (i32.const 1) + ) + ) + (set_local $0 + (i64.mul + (get_local $0) + (get_local $0) + ) + ) + ) + (br $continue|2) ) ) ) ) - (get_local $4) + (get_local $3) ) (func $start (; 159 ;) (type $v) (local $0 i32) From 7875b4564548dd57c072ece93f1dbc04ce558454 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Mon, 6 Aug 2018 21:51:33 +0300 Subject: [PATCH 11/12] better code compation --- std/assembly/math.ts | 35 +++++++------- tests/compiler/std/math.optimized.wat | 14 ++++-- tests/compiler/std/math.untouched.wat | 68 +++++++++++++-------------- 3 files changed, 61 insertions(+), 56 deletions(-) diff --git a/std/assembly/math.ts b/std/assembly/math.ts index b5e1d5f708..112b788787 100644 --- a/std/assembly/math.ts +++ b/std/assembly/math.ts @@ -2305,17 +2305,17 @@ export namespace NativeMathf { } export function ipow32(x: i32, e: i32): i32 { - if (e < 0) return 0; - switch (e) { - case 0: return 1; - case 1: return x; - case 2: return x * x; - } - var out = 1; - var log = 32 - clz(e); - if (ASC_SHRINK_LEVEL < 1) { + if (e < 0) return 0; + + switch (e) { + case 0: return 1; + case 1: return x; + case 2: return x * x; + } + + let log = 32 - clz(e); if (log <= 5) { // 32 = 2 ^ 5, so need only five cases. // But some extra cases needs for properly overflowing @@ -2357,17 +2357,16 @@ export function ipow32(x: i32, e: i32): i32 { } export function ipow64(x: i64, e: i32): i64 { - if (e < 0) return 0; - switch (e) { - case 0: return 1; - case 1: return x; - case 2: return x * x; - } - var out: i64 = 1; - var log = 32 - clz(e); - if (ASC_SHRINK_LEVEL < 1) { + if (e < 0) return 0; + switch (e) { + case 0: return 1; + case 1: return x; + case 2: return x * x; + } + + let log = 32 - clz(e); if (log <= 6) { // 64 = 2 ^ 6, so need only six cases. // But some extra cases needs for properly overflowing diff --git a/tests/compiler/std/math.optimized.wat b/tests/compiler/std/math.optimized.wat index c8b04c22cd..398ee5ac4d 100644 --- a/tests/compiler/std/math.optimized.wat +++ b/tests/compiler/std/math.optimized.wat @@ -13985,6 +13985,9 @@ (func $~lib/math/ipow64 (; 158 ;) (; has Stack IR ;) (type $IiI) (param $0 i64) (param $1 i32) (result i64) (local $2 i64) (local $3 i32) + (set_local $2 + (i64.const 1) + ) (if (i32.lt_s (get_local $1) @@ -14030,9 +14033,6 @@ ) ) ) - (set_local $2 - (i64.const 1) - ) (if (i32.le_s (tee_local $3 @@ -14058,8 +14058,14 @@ (i32.const 6) ) (block + (br_if $case1|1 + (i32.eq + (get_local $3) + (i32.const 5) + ) + ) (block $tablify|0 - (br_table $case5|1 $case4|1 $case3|1 $case2|1 $case1|1 $tablify|0 + (br_table $case5|1 $case4|1 $case3|1 $case2|1 $tablify|0 (i32.sub (get_local $3) (i32.const 1) diff --git a/tests/compiler/std/math.untouched.wat b/tests/compiler/std/math.untouched.wat index 91fa7dd697..71b59bbad2 100644 --- a/tests/compiler/std/math.untouched.wat +++ b/tests/compiler/std/math.untouched.wat @@ -16119,9 +16119,12 @@ ) ) (func $~lib/math/ipow64 (; 158 ;) (type $IiI) (param $0 i64) (param $1 i32) (result i64) - (local $2 i32) - (local $3 i64) + (local $2 i64) + (local $3 i32) (local $4 i32) + (set_local $2 + (i64.const 1) + ) (if (i32.lt_s (get_local $1) @@ -16135,24 +16138,24 @@ (block $case2|0 (block $case1|0 (block $case0|0 - (set_local $2 + (set_local $3 (get_local $1) ) (br_if $case0|0 (i32.eq - (get_local $2) + (get_local $3) (i32.const 0) ) ) (br_if $case1|0 (i32.eq - (get_local $2) + (get_local $3) (i32.const 1) ) ) (br_if $case2|0 (i32.eq - (get_local $2) + (get_local $3) (i32.const 2) ) ) @@ -16174,9 +16177,6 @@ ) ) (set_local $3 - (i64.const 1) - ) - (set_local $4 (i32.sub (i32.const 32) (i32.clz @@ -16186,7 +16186,7 @@ ) (if (i32.le_s - (get_local $4) + (get_local $3) (i32.const 6) ) (block @@ -16197,42 +16197,42 @@ (block $case2|1 (block $case1|1 (block $case0|1 - (set_local $2 - (get_local $4) + (set_local $4 + (get_local $3) ) (br_if $case0|1 (i32.eq - (get_local $2) + (get_local $4) (i32.const 6) ) ) (br_if $case1|1 (i32.eq - (get_local $2) + (get_local $4) (i32.const 5) ) ) (br_if $case2|1 (i32.eq - (get_local $2) + (get_local $4) (i32.const 4) ) ) (br_if $case3|1 (i32.eq - (get_local $2) + (get_local $4) (i32.const 3) ) ) (br_if $case4|1 (i32.eq - (get_local $2) + (get_local $4) (i32.const 2) ) ) (br_if $case5|1 (i32.eq - (get_local $2) + (get_local $4) (i32.const 1) ) ) @@ -16244,9 +16244,9 @@ (get_local $1) (i32.const 1) ) - (set_local $3 + (set_local $2 (i64.mul - (get_local $3) + (get_local $2) (get_local $0) ) ) @@ -16271,9 +16271,9 @@ (get_local $1) (i32.const 1) ) - (set_local $3 + (set_local $2 (i64.mul - (get_local $3) + (get_local $2) (get_local $0) ) ) @@ -16298,9 +16298,9 @@ (get_local $1) (i32.const 1) ) - (set_local $3 + (set_local $2 (i64.mul - (get_local $3) + (get_local $2) (get_local $0) ) ) @@ -16325,9 +16325,9 @@ (get_local $1) (i32.const 1) ) - (set_local $3 + (set_local $2 (i64.mul - (get_local $3) + (get_local $2) (get_local $0) ) ) @@ -16352,9 +16352,9 @@ (get_local $1) (i32.const 1) ) - (set_local $3 + (set_local $2 (i64.mul - (get_local $3) + (get_local $2) (get_local $0) ) ) @@ -16378,16 +16378,16 @@ (get_local $1) (i32.const 1) ) - (set_local $3 + (set_local $2 (i64.mul - (get_local $3) + (get_local $2) (get_local $0) ) ) ) ) (return - (get_local $3) + (get_local $2) ) ) ) @@ -16405,9 +16405,9 @@ (get_local $1) (i32.const 1) ) - (set_local $3 + (set_local $2 (i64.mul - (get_local $3) + (get_local $2) (get_local $0) ) ) @@ -16430,7 +16430,7 @@ ) ) ) - (get_local $3) + (get_local $2) ) (func $start (; 159 ;) (type $v) (local $0 i32) From 4b9527f7a6ca0cbc491fe4e2d35aad2cfda1a807 Mon Sep 17 00:00:00 2001 From: MaxGraey Date: Tue, 7 Aug 2018 19:06:02 +0300 Subject: [PATCH 12/12] add special test --- tests/compiler/std/math.optimized.wat | 24 ++++++++++++++++++++++++ tests/compiler/std/math.ts | 2 ++ tests/compiler/std/math.untouched.wat | 26 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/tests/compiler/std/math.optimized.wat b/tests/compiler/std/math.optimized.wat index 398ee5ac4d..18fa8fa817 100644 --- a/tests/compiler/std/math.optimized.wat +++ b/tests/compiler/std/math.optimized.wat @@ -54000,5 +54000,29 @@ (unreachable) ) ) + (if + (i64.ne + (i64.add + (call $~lib/math/ipow64 + (i64.const 57055) + (i32.const 3) + ) + (call $~lib/math/ipow64 + (i64.const 339590) + (i32.const 3) + ) + ) + (i64.const 39347712995520375) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3156) + (i32.const 0) + ) + (unreachable) + ) + ) ) ) diff --git a/tests/compiler/std/math.ts b/tests/compiler/std/math.ts index 737c427d16..fb5e1f6415 100644 --- a/tests/compiler/std/math.ts +++ b/tests/compiler/std/math.ts @@ -3152,3 +3152,5 @@ assert(ipow64(3, 43) == -3784425932234851461); // should overflow assert(ipow64(3, 63) == -3237885987332494933); // should overflow assert(ipow64(3, 64) == 8733086111712066817); // should overflow assert(ipow64(3, 128) == -9204772141784466943); // should overflow + +assert(ipow64(57055, 3) + ipow64(339590, 3) == 39347712995520375); // add Buterin's twit example diff --git a/tests/compiler/std/math.untouched.wat b/tests/compiler/std/math.untouched.wat index 71b59bbad2..60e925e55c 100644 --- a/tests/compiler/std/math.untouched.wat +++ b/tests/compiler/std/math.untouched.wat @@ -56986,5 +56986,31 @@ (unreachable) ) ) + (if + (i32.eqz + (i64.eq + (i64.add + (call $~lib/math/ipow64 + (i64.const 57055) + (i32.const 3) + ) + (call $~lib/math/ipow64 + (i64.const 339590) + (i32.const 3) + ) + ) + (i64.const 39347712995520375) + ) + ) + (block + (call $~lib/env/abort + (i32.const 0) + (i32.const 8) + (i32.const 3156) + (i32.const 0) + ) + (unreachable) + ) + ) ) )