Skip to content

Use integer power for integer types #1146

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 80 commits into from
Jun 13, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
fd09ce3
add i64_pow helpers
MaxGraey Mar 4, 2020
d026f4a
minor opts for i64_pow
MaxGraey Mar 4, 2020
5f0b589
add basic logic for compiler & refactor ipow
MaxGraey Mar 4, 2020
4c0cd33
fixes
MaxGraey Mar 4, 2020
6c7f493
fixes
MaxGraey Mar 4, 2020
1757ecb
add Fermat's Last Theorem case
MaxGraey Mar 4, 2020
b773944
simplify
MaxGraey Mar 4, 2020
8fa08f0
rebuild rest tests
MaxGraey Mar 4, 2020
bf53fbc
include also other int types but without isize / usize
MaxGraey Mar 4, 2020
7503cc5
add more tests
MaxGraey Mar 4, 2020
48b9b08
cleanup
MaxGraey Mar 4, 2020
1a5bbdf
more tests with casts
MaxGraey Mar 5, 2020
b6f8c25
clearer
MaxGraey Mar 5, 2020
97909bf
better check for fast path in ipow32/64
MaxGraey Mar 5, 2020
a8bc26f
clean space
MaxGraey Mar 5, 2020
254458b
more tests
MaxGraey Mar 5, 2020
f222e4c
improve
MaxGraey Mar 5, 2020
f0dd9e6
add comment with TODO and shortest addition chains
MaxGraey Mar 6, 2020
4ca7c92
typo
MaxGraey Mar 6, 2020
2dfe9c9
refactor
MaxGraey Mar 6, 2020
9ba46b1
optimize int pow for booleans
MaxGraey Mar 7, 2020
db8c969
more tests & fixes
MaxGraey Mar 7, 2020
95e0f57
rebuild tests
MaxGraey Mar 7, 2020
8f7f397
fix glue code as well
MaxGraey Mar 7, 2020
660df02
cleanups
MaxGraey Mar 7, 2020
c9b9626
typo
MaxGraey Mar 7, 2020
ac0816e
refactor i64_pow
MaxGraey Mar 7, 2020
772d3a5
fix resolver
MaxGraey Mar 7, 2020
e7f8988
simplify
MaxGraey Mar 7, 2020
2291c76
refactor
MaxGraey Mar 7, 2020
80fbb45
more
MaxGraey Mar 7, 2020
99f107d
more
MaxGraey Mar 7, 2020
ab20782
switch to commonType
MaxGraey Mar 7, 2020
7e7bf6f
cleanups
MaxGraey Mar 7, 2020
774173c
remove unnecessary type assignments
MaxGraey Mar 7, 2020
3413481
skip compileExpression if expresion compaund and already pre-compiled
MaxGraey Mar 7, 2020
f93957e
remove compileExpr
MaxGraey Mar 7, 2020
8a28586
use special optimizations for booleans
MaxGraey Mar 8, 2020
2480ee8
simplify
MaxGraey Mar 8, 2020
667a9bf
simplify + add more tests
MaxGraey Mar 8, 2020
1acd61c
remove special case by adressed comments
MaxGraey Mar 8, 2020
652af0f
Merge branch 'master' into int-pow
MaxGraey Mar 10, 2020
cbde99b
special case for -1 ** -e
MaxGraey Mar 11, 2020
93bf22f
update
MaxGraey Mar 11, 2020
15bd49d
refactor ipow32 / ipow64
MaxGraey Mar 11, 2020
76dfc11
Merge branch 'master' into int-pow
MaxGraey Mar 11, 2020
ee2d5ad
Merge branch 'master' into int-pow
MaxGraey Mar 13, 2020
bc8ebd5
rebuild
MaxGraey Mar 13, 2020
91d84b0
Merge branch 'master' into int-pow
MaxGraey Mar 14, 2020
4d07064
rebuild
MaxGraey Mar 14, 2020
e585485
Merge branch 'master' into int-pow
MaxGraey Mar 15, 2020
0d48b5a
Merge branch 'master' into int-pow
MaxGraey Mar 15, 2020
1c85077
rebuild
MaxGraey Mar 15, 2020
9365659
Merge branch 'master' into int-pow
MaxGraey Mar 22, 2020
d315067
Merge branch 'master' into int-pow
MaxGraey Apr 13, 2020
0ced38e
update
MaxGraey Apr 13, 2020
8f7421d
Merge branch 'master' into int-pow
MaxGraey Apr 16, 2020
788d70a
update
MaxGraey Apr 16, 2020
a1045ff
Merge branch 'master' into int-pow
MaxGraey Apr 21, 2020
35d614e
rebuild
MaxGraey Apr 21, 2020
0e31ce7
Merge branch 'master' into int-pow
MaxGraey Apr 23, 2020
a6d39c1
update tests
MaxGraey Apr 23, 2020
1d127eb
Merge branch 'master' into int-pow
MaxGraey May 1, 2020
abfc319
rebuild
MaxGraey May 1, 2020
5d6eaf4
remove TBD
MaxGraey May 1, 2020
1fee173
Merge branch 'master' into int-pow
MaxGraey May 13, 2020
f16894c
Merge branch 'master' into int-pow
MaxGraey May 15, 2020
c2ce148
rebuild
MaxGraey May 15, 2020
d82a98b
Fix bootstrap
MaxGraey May 15, 2020
135eafe
Merge branch 'master' into int-pow
MaxGraey Jun 6, 2020
20b54c6
rebuild
MaxGraey Jun 6, 2020
f98d11a
fix lint
MaxGraey Jun 6, 2020
3781465
handle small types
MaxGraey Jun 6, 2020
c483af5
remove some redundant tests
MaxGraey Jun 6, 2020
512a132
minor optimization
MaxGraey Jun 7, 2020
306c011
use commonDenominator also for resolver
MaxGraey Jun 9, 2020
8df219d
fix comment
MaxGraey Jun 9, 2020
5b0f490
retrieve operator's kind via fromBinaryToken
MaxGraey Jun 9, 2020
f89399d
add mixed pow tests for resolver
MaxGraey Jun 9, 2020
d51f471
Merge branch 'master' into int-pow
MaxGraey Jun 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ export namespace CommonNames {
// runtime
export const abort = "abort";
export const pow = "pow";
export const ipow32 = "ipow32";
export const ipow64 = "ipow64";
export const mod = "mod";
export const alloc = "__alloc";
export const realloc = "__realloc";
Expand Down
48 changes: 46 additions & 2 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3687,6 +3687,8 @@ export class Compiler extends DiagnosticEmitter {
private f64ModInstance: Function | null = null;
private f32PowInstance: Function | null = null;
private f64PowInstance: Function | null = null;
private i32PowInstance: Function | null = null;
private i64PowInstance: Function | null = null;

private compileBinaryExpression(
expression: BinaryExpression,
Expand Down Expand Up @@ -4620,8 +4622,50 @@ export class Compiler extends DiagnosticEmitter {
let targetType = leftType;
let instance: Function | null;

// Mathf.pow if lhs is f32 (result is f32)
if (this.currentType.kind == TypeKind.F32) {
if ((this.currentType.kind == TypeKind.I32 || this.currentType.kind == TypeKind.U32)) {
let type = this.currentType.kind == TypeKind.I32 ? Type.i32 : Type.u32;

rightExpr = this.compileExpression(right, type, Constraints.CONV_IMPLICIT);
rightType = this.currentType;
instance = this.i32PowInstance;

if (!instance) {
let prototype = this.program.lookupGlobal(CommonNames.ipow32);
if (!prototype) {
this.error(
DiagnosticCode.Cannot_find_name_0,
expression.range, "ipow32"
);
expr = module.unreachable();
break;
}
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.i32PowInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}

} else if (this.currentType.kind == TypeKind.I64 || this.currentType.kind == TypeKind.U64) {

let type = this.currentType.kind == TypeKind.I64 ? Type.i64 : Type.u64;

rightExpr = this.compileExpression(right, type, Constraints.CONV_IMPLICIT);
rightType = this.currentType;
instance = this.i64PowInstance;

if (!instance) {
let prototype = this.program.lookupGlobal(CommonNames.ipow64);
if (!prototype) {
this.error(
DiagnosticCode.Cannot_find_name_0,
expression.range, "ipow64"
);
expr = module.unreachable();
break;
}
assert(prototype.kind == ElementKind.FUNCTION_PROTOTYPE);
this.i64PowInstance = instance = this.resolver.resolveFunction(<FunctionPrototype>prototype, null);
}
// Mathf.pow if lhs is f32 (result is f32)
} else if (this.currentType.kind == TypeKind.F32) {
rightExpr = this.compileExpression(right, Type.f32, Constraints.CONV_IMPLICIT);
rightType = this.currentType;
instance = this.f32PowInstance;
Expand Down
1 change: 1 addition & 0 deletions src/glue/js/i64.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ declare function i64_high(value: i64): i32;
declare function i64_add(left: i64, right: i64): i64;
declare function i64_sub(left: i64, right: i64): i64;
declare function i64_mul(left: i64, right: i64): i64;
declare function i64_pow(left: i64, right: i64): i64;
declare function i64_div(left: i64, right: i64): i64;
declare function i64_div_u(left: i64, right: i64): i64;
declare function i64_rem(left: i64, right: i64): i64;
Expand Down
20 changes: 20 additions & 0 deletions src/glue/js/i64.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,26 @@ global.i64_mul = function(left, right) {
return left.mul(right);
};

global.i64_pow = function(left, right) {
var rightHi = right.high;
if (rightHi < 0) return Long.ZERO;
var rightLo = right.low;
if (!rightHi) {
if (rightLo == 0) return Long.ONE;
if (rightLo == 1) return left;
if (rightLo == 2) return left.mul(left);
}
var result = Long.ONE;
while (rightLo | rightHi) {
if (rightLo & 1) result = result.mul(left);
right = right.shru(1);
left = left.mul(left);
rightLo = right.low;
rightHi = right.high;
}
return result;
};

global.i64_div = function(left, right) {
return left.div(right);
};
Expand Down
15 changes: 15 additions & 0 deletions src/glue/wasm/i64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ function i64_mul(left: i64, right: i64): i64 {
return left * right;
}

// @ts-ignore: decorator
@global
function i64_pow(left: i64, right: i64): i64 {
if (right <= 0) return i64(right == 0);
if (right == 1) return left;
if (right == 2) return left * left;
var result: i64 = 1;
while (right) {
if (right & 1) result *= left;
right >>>= 1;
left *= left;
}
return result;
}

// @ts-ignore: decorator
@global
function i64_div(left: i64, right: i64): i64 {
Expand Down
76 changes: 22 additions & 54 deletions std/assembly/math.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3004,13 +3004,9 @@ export namespace NativeMathf {
export function ipow32(x: i32, e: i32): i32 {
var out = 1;
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;
}
if (e <= 0) return i32(e == 0);
if (e == 1) return x;
if (e == 2) return x * x;

let log = 32 - clz(e);
if (log <= 5) {
Expand All @@ -3019,22 +3015,22 @@ export function ipow32(x: i32, e: i32): i32 {
switch (log) {
case 5: {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
case 4: {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
case 3: {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
case 2: {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
case 1: {
Expand All @@ -3045,52 +3041,49 @@ export function ipow32(x: i32, e: i32): i32 {
}
}

while (e > 0) {
while (e) {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
return out;
}

export function ipow64(x: i64, e: i32): i64 {
export function ipow64(x: i64, e: i64): i64 {
var out: i64 = 1;
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;
}
if (e <= 0) return i64(e == 0);
if (e == 1) return x;
if (e == 2) return x * x;

let log = 32 - clz(e);
let log = 64 - <i32>clz(e);
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;
e >>>= 1;
x *= x;
}
case 5: {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
case 4: {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
case 3: {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
case 2: {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
case 1: {
Expand All @@ -3100,35 +3093,10 @@ export function ipow64(x: i64, e: i32): i64 {
return out;
}
}

while (e > 0) {
while (e) {
if (e & 1) out *= x;
e >>= 1;
e >>>= 1;
x *= x;
}
return out;
}

export function ipow32f(x: f32, e: i32): f32 {
var sign = e >> 31;
e = (e + sign) ^ sign; // abs(e)
var out: f32 = 1;
while (e) {
out *= select<f32>(x, 1.0, e & 1);
e >>= 1;
x *= x;
}
return sign ? <f32>1.0 / out : out;
}

export function ipow64f(x: f64, e: i32): f64 {
var sign = e >> 31;
e = (e + sign) ^ sign; // abs(e)
var out = 1.0;
while (e) {
out *= select(x, 1.0, e & 1);
e >>= 1;
x *= x;
}
return sign ? 1.0 / out : out;
}
}
47 changes: 41 additions & 6 deletions tests/compiler/binary.optimized.wat
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(module
(type $none_=>_none (func))
(type $i32_=>_i32 (func (param i32) (result i32)))
(type $f32_=>_f32 (func (param f32) (result f32)))
(type $f64_=>_f64 (func (param f64) (result f64)))
(memory $0 1)
Expand All @@ -12,7 +13,39 @@
(global $binary/F (mut f64) (f64.const 0))
(export "memory" (memory $0))
(start $~start)
(func $~lib/math/NativeMathf.mod (; 0 ;) (param $0 f32) (result f32)
(func $~lib/math/ipow32 (; 0 ;) (param $0 i32) (result i32)
(local $1 i32)
(local $2 i32)
i32.const 1
local.set $1
i32.const 1
local.set $2
loop $while-continue|0
local.get $1
if
local.get $0
local.get $2
i32.mul
local.get $2
local.get $1
i32.const 1
i32.and
select
local.set $2
local.get $1
i32.const 1
i32.shr_u
local.set $1
local.get $0
local.get $0
i32.mul
local.set $0
br $while-continue|0
end
end
local.get $2
)
(func $~lib/math/NativeMathf.mod (; 1 ;) (param $0 f32) (result f32)
(local $1 i32)
(local $2 i32)
(local $3 i32)
Expand Down Expand Up @@ -156,7 +189,7 @@
local.get $0
f32.mul
)
(func $~lib/math/NativeMath.mod (; 1 ;) (param $0 f64) (result f64)
(func $~lib/math/NativeMath.mod (; 2 ;) (param $0 f64) (result f64)
(local $1 i64)
(local $2 i64)
(local $3 i64)
Expand Down Expand Up @@ -307,12 +340,15 @@
local.get $0
f64.mul
)
(func $start:binary (; 2 ;)
(func $start:binary (; 3 ;)
global.get $binary/i
i32.const 1
i32.rem_s
drop
global.get $binary/i
call $~lib/math/ipow32
drop
global.get $binary/i
i32.const 1
i32.lt_s
global.set $binary/b
Expand Down Expand Up @@ -349,8 +385,7 @@
i32.rem_s
global.set $binary/i
global.get $binary/i
f64.convert_i32_s
i32.trunc_f64_s
call $~lib/math/ipow32
global.set $binary/i
global.get $binary/i
i32.const 1
Expand Down Expand Up @@ -615,7 +650,7 @@
call $~lib/math/NativeMath.mod
global.set $binary/F
)
(func $~start (; 3 ;)
(func $~start (; 4 ;)
call $start:binary
)
)
Loading