diff --git a/src/compiler.ts b/src/compiler.ts index f14ec3e787..74518ef05d 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -5187,6 +5187,22 @@ export class Compiler extends DiagnosticEmitter { } case TypeKind.I32: case TypeKind.U32: { + if (this.options.willOptimize) { + // Precompute power if LHS and RHS constants + // TODO: move this optimization to AIR + if ( + getExpressionId(leftExpr) == ExpressionId.Const && + getExpressionId(rightExpr) == ExpressionId.Const + ) { + let leftValue = getConstValueI32(leftExpr); + let rightValue = getConstValueI32(rightExpr); + this.currentType = type; + return module.i32(i64_low(i64_pow( + i64_new(leftValue), + i64_new(rightValue) + ))); + } + } let instance = this.i32PowInstance; if (!instance) { let prototype = this.program.lookup(CommonNames.ipow32); @@ -5213,6 +5229,20 @@ export class Compiler extends DiagnosticEmitter { } case TypeKind.I64: case TypeKind.U64: { + if (this.options.willOptimize) { + // Precompute power if LHS and RHS constants + // TODO: move this optimization to AIR + if ( + getExpressionId(leftExpr) == ExpressionId.Const && + getExpressionId(rightExpr) == ExpressionId.Const + ) { + let leftValue = i64_new(getConstValueI64Low(leftExpr), getConstValueI64High(leftExpr)); + let rightValue = i64_new(getConstValueI64Low(rightExpr), getConstValueI64High(rightExpr)); + let result = i64_pow(leftValue, rightValue); + this.currentType = type; + return module.i64(i64_low(result), i64_high(result)); + } + } let instance = this.i64PowInstance; if (!instance) { let prototype = this.program.lookup(CommonNames.ipow64); @@ -5234,6 +5264,30 @@ export class Compiler extends DiagnosticEmitter { case TypeKind.ISIZE: case TypeKind.USIZE: { let isWasm64 = this.options.isWasm64; + if (this.options.willOptimize) { + // Precompute power if LHS and RHS constants + // TODO: move this optimization to AIR + if ( + getExpressionId(leftExpr) == ExpressionId.Const && + getExpressionId(rightExpr) == ExpressionId.Const + ) { + if (isWasm64) { + let leftValue = i64_new(getConstValueI64Low(leftExpr), getConstValueI64High(leftExpr)); + let rightValue = i64_new(getConstValueI64Low(rightExpr), getConstValueI64High(rightExpr)); + let result = i64_pow(leftValue, rightValue); + this.currentType = type; + return module.i64(i64_low(result), i64_high(result)); + } else { + let leftValue = getConstValueI32(leftExpr); + let rightValue = getConstValueI32(rightExpr); + this.currentType = type; + return module.i32(i64_low(i64_pow( + i64_new(leftValue), + i64_new(rightValue) + ))); + } + } + } let instance = isWasm64 ? this.i64PowInstance : this.i32PowInstance; if (!instance) { let prototype = this.program.lookup(isWasm64 ? CommonNames.ipow64 : CommonNames.ipow32); @@ -5258,6 +5312,19 @@ export class Compiler extends DiagnosticEmitter { return this.makeCallDirect(instance, [ leftExpr, rightExpr ], reportNode); } case TypeKind.F32: { + if (this.options.willOptimize) { + // Precompute power if LHS and RHS constants + // TODO: move this optimization to AIR + if ( + getExpressionId(leftExpr) == ExpressionId.Const && + getExpressionId(rightExpr) == ExpressionId.Const + ) { + let leftValue = getConstValueF32(leftExpr); + let rightValue = getConstValueF32(rightExpr); + this.currentType = type; + return module.f32(f32(Math.pow(leftValue, rightValue))); + } + } let instance = this.f32PowInstance; if (!instance) { let namespace = this.program.lookup(CommonNames.Mathf); @@ -5287,6 +5354,19 @@ export class Compiler extends DiagnosticEmitter { } // Math.pow otherwise (result is f64) case TypeKind.F64: { + if (this.options.willOptimize) { + // Precompute power if LHS and RHS constants + // TODO: move this optimization to AIR + if ( + getExpressionId(leftExpr) == ExpressionId.Const && + getExpressionId(rightExpr) == ExpressionId.Const + ) { + let leftValue = getConstValueF64(leftExpr); + let rightValue = getConstValueF64(rightExpr); + this.currentType = type; + return module.f64(Math.pow(leftValue, rightValue)); + } + } let instance = this.f64PowInstance; if (!instance) { let namespace = this.program.lookup(CommonNames.Math); diff --git a/tests/compiler/std/math.release.wat b/tests/compiler/std/math.release.wat index b6111df58d..2976d7d875 100644 --- a/tests/compiler/std/math.release.wat +++ b/tests/compiler/std/math.release.wat @@ -19,7 +19,6 @@ (type $f64_=>_none (func (param f64))) (type $i64_i64_i64_i64_i64_=>_none (func (param i64 i64 i64 i64 i64))) (type $i64_i64_=>_i64 (func (param i64 i64) (result i64))) - (type $i32_i32_=>_i32 (func (param i32 i32) (result i32))) (import "env" "Math.E" (global $~lib/bindings/dom/Math.E f64)) (import "env" "Math.LN2" (global $~lib/bindings/dom/Math.LN2 f64)) (import "env" "Math.LN10" (global $~lib/bindings/dom/Math.LN10 f64)) @@ -11958,191 +11957,6 @@ end local.get $2 ) - (func $~lib/math/ipow32 (param $0 i32) (param $1 i32) (result i32) - (local $2 i32) - i32.const 1 - local.set $2 - local.get $0 - i32.const 2 - i32.eq - if - i32.const 1 - local.get $1 - i32.shl - i32.const 0 - local.get $1 - i32.const 32 - i32.lt_u - select - return - end - local.get $1 - i32.const 0 - i32.le_s - if - local.get $0 - i32.const -1 - i32.eq - if - i32.const -1 - i32.const 1 - local.get $1 - i32.const 1 - i32.and - select - return - end - local.get $1 - i32.eqz - local.get $0 - i32.const 1 - i32.eq - i32.or - return - else - local.get $1 - i32.const 1 - i32.eq - if - local.get $0 - return - else - local.get $1 - i32.const 2 - i32.eq - if - local.get $0 - local.get $0 - i32.mul - return - else - local.get $1 - i32.const 32 - i32.lt_s - if - block $break|0 - block $case4|0 - block $case3|0 - block $case2|0 - block $case1|0 - block $case0|0 - i32.const 31 - local.get $1 - i32.clz - i32.sub - br_table $case4|0 $case3|0 $case2|0 $case1|0 $case0|0 $break|0 - end - local.get $0 - i32.const 1 - 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 - end - 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 - end - 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 - end - 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 - end - local.get $0 - local.get $2 - i32.mul - local.get $2 - local.get $1 - i32.const 1 - i32.and - select - local.set $2 - end - local.get $2 - return - end - end - end - end - loop $while-continue|1 - 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|1 - end - end - local.get $2 - ) (func $start:std/math (local $0 f64) (local $1 i32) @@ -56354,382 +56168,6 @@ call $~lib/builtins/abort unreachable end - i32.const 1 - i32.const 3 - call $~lib/math/ipow32 - i32.const 1 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4091 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const -2 - i32.const 3 - call $~lib/math/ipow32 - i32.const -8 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4092 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const -1 - i32.const 0 - call $~lib/math/ipow32 - i32.const 1 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4093 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const -1 - i32.const -1 - call $~lib/math/ipow32 - i32.const -1 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4094 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const -1 - i32.const -2 - call $~lib/math/ipow32 - i32.const 1 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4095 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const -1 - i32.const -3 - call $~lib/math/ipow32 - i32.const -1 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4096 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 0 - i32.const -2 - call $~lib/math/ipow32 - if - i32.const 0 - i32.const 1056 - i32.const 4098 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 0 - i32.const -1 - call $~lib/math/ipow32 - if - i32.const 0 - i32.const 1056 - i32.const 4099 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 0 - i32.const 2 - call $~lib/math/ipow32 - if - i32.const 0 - i32.const 1056 - i32.const 4102 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 1 - i32.const -2 - call $~lib/math/ipow32 - i32.const 1 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4104 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 1 - i32.const -1 - call $~lib/math/ipow32 - i32.const 1 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4105 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 1 - i32.const 2 - call $~lib/math/ipow32 - i32.const 1 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4108 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 1 - i32.const 3 - call $~lib/math/ipow32 - i32.const 255 - i32.and - i32.const 1 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4110 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const -2 - i32.const 3 - call $~lib/math/ipow32 - i32.const 255 - i32.and - i32.const 248 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4111 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 4 - i32.const 7 - call $~lib/math/ipow32 - i32.const 65535 - i32.and - i32.const 16384 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4112 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 4 - i32.const 8 - call $~lib/math/ipow32 - i32.const 65535 - i32.and - if - i32.const 0 - i32.const 1056 - i32.const 4113 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i32.const 5 - i32.const 10 - call $~lib/math/ipow32 - i32.const 65535 - i32.and - i32.const 761 - i32.ne - if - i32.const 0 - i32.const 1056 - i32.const 4114 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 0 - i64.const 0 - call $~lib/math/ipow64 - i64.const 1 - i64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4116 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 0 - i64.const 1 - call $~lib/math/ipow64 - i64.eqz - i32.eqz - if - i32.const 0 - i32.const 1056 - i32.const 4117 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 1 - i64.const 3 - call $~lib/math/ipow64 - i64.const 1 - i64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4118 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 2 - i64.const 3 - call $~lib/math/ipow64 - i64.const 8 - i64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4119 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 4294967295 - i64.const 3 - call $~lib/math/ipow64 - i64.const 12884901887 - i64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4120 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 65535 - i64.const 3 - call $~lib/math/ipow64 - i64.const 281462092005375 - i64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4121 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 65535 - i64.const 8 - call $~lib/math/ipow64 - i64.const -15762478437236735 - i64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4122 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 61731 - i64.const 4 - call $~lib/math/ipow64 - i64.const -3925184889716469295 - i64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4123 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 61731 - i64.const 4 - call $~lib/math/ipow64 - i64.const -3925184889716469295 - i64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4124 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 57055 - i64.const 3 - call $~lib/math/ipow64 - i64.const 339590 - i64.const 3 - call $~lib/math/ipow64 - i64.add - i64.const 340126 - i64.const 3 - call $~lib/math/ipow64 - i64.eq - if - i32.const 0 - i32.const 1056 - i32.const 4126 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - i64.const 57055 - i64.const 3 - call $~lib/math/ipow64 - i64.const 339590 - i64.const 3 - call $~lib/math/ipow64 - i64.add - i64.const 39347712995520375 - i64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4127 - i32.const 1 - call $~lib/builtins/abort - unreachable - end f64.const 1 f64.const 0.5 call $~lib/math/NativeMath.pow @@ -56769,32 +56207,6 @@ call $~lib/builtins/abort unreachable end - f64.const 0 - f64.const 0 - call $~lib/math/NativeMath.pow - f64.const 1 - f64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4132 - i32.const 1 - call $~lib/builtins/abort - unreachable - end - f64.const 1 - f64.const 1 - call $~lib/math/NativeMath.pow - f64.const 1 - f64.ne - if - i32.const 0 - i32.const 1056 - i32.const 4133 - i32.const 1 - call $~lib/builtins/abort - unreachable - end ) (func $~start call $start:std/math