diff options
-rw-r--r-- | src/asmjs/shared-constants.cpp | 1 | ||||
-rw-r--r-- | src/asmjs/shared-constants.h | 1 | ||||
-rw-r--r-- | src/ast/localize.h | 47 | ||||
-rw-r--r-- | src/passes/PostEmscripten.cpp | 23 | ||||
-rw-r--r-- | test/passes/post-emscripten.txt | 71 | ||||
-rw-r--r-- | test/passes/post-emscripten.wast | 56 |
6 files changed, 197 insertions, 2 deletions
diff --git a/src/asmjs/shared-constants.cpp b/src/asmjs/shared-constants.cpp index e30fd939c..d704c8009 100644 --- a/src/asmjs/shared-constants.cpp +++ b/src/asmjs/shared-constants.cpp @@ -49,6 +49,7 @@ cashew::IString GLOBAL("global"), FLOOR("floor"), CEIL("ceil"), SQRT("sqrt"), + POW("pow"), I32_TEMP("asm2wasm_i32_temp"), DEBUGGER("debugger"), USE_ASM("use asm"), diff --git a/src/asmjs/shared-constants.h b/src/asmjs/shared-constants.h index e0c627511..7b48c3df5 100644 --- a/src/asmjs/shared-constants.h +++ b/src/asmjs/shared-constants.h @@ -52,6 +52,7 @@ extern cashew::IString GLOBAL, FLOOR, CEIL, SQRT, + POW, I32_TEMP, DEBUGGER, USE_ASM, diff --git a/src/ast/localize.h b/src/ast/localize.h new file mode 100644 index 000000000..9e7dd6653 --- /dev/null +++ b/src/ast/localize.h @@ -0,0 +1,47 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef wasm_ast_localizer_h +#define wasm_ast_localizer_h + +#include <wasm-builder.h> + +namespace wasm { + +// Make an expression available in a local. If already in one, just +// use that local, otherwise use a new local + +struct Localizer { + Index index; + Expression* expr; + + Localizer(Expression* input, Function* func, Module* wasm) { + expr = input; + if (auto* get = expr->dynCast<GetLocal>()) { + index = get->index; + } else if (auto* set = expr->dynCast<SetLocal>()) { + index = set->index; + } else { + index = Builder::addVar(func, expr->type); + expr = Builder(*wasm).makeTeeLocal(index, expr); + } + } +}; + +} // namespace wasm + +#endif // wasm_ast_localizer_h + diff --git a/src/passes/PostEmscripten.cpp b/src/passes/PostEmscripten.cpp index 51b8c2ec1..937a70e36 100644 --- a/src/passes/PostEmscripten.cpp +++ b/src/passes/PostEmscripten.cpp @@ -21,6 +21,9 @@ #include <wasm.h> #include <pass.h> +#include <wasm-builder.h> +#include <ast/localize.h> +#include <asmjs/shared-constants.h> namespace wasm { @@ -88,6 +91,26 @@ struct PostEmscripten : public WalkerPass<PostWalker<PostEmscripten>> { void visitStore(Store* curr) { optimizeMemoryAccess(curr->ptr, curr->offset); } + + void visitCallImport(CallImport* curr) { + // special asm.js imports can be optimized + auto* import = getModule()->getImport(curr->target); + if (import->module == GLOBAL_MATH) { + if (import->base == POW) { + if (auto* exponent = curr->operands[1]->dynCast<Const>()) { + if (exponent->value == Literal(double(2.0))) { + // This is just a square operation, do a multiply + Localizer localizer(curr->operands[0], getFunction(), getModule()); + Builder builder(*getModule()); + replaceCurrent(builder.makeBinary(MulFloat64, localizer.expr, builder.makeGetLocal(localizer.index, localizer.expr->type))); + } else if (exponent->value == Literal(double(0.5))) { + // This is just a square root operation + replaceCurrent(Builder(*getModule()).makeUnary(SqrtFloat64, curr->operands[0])); + } + } + } + } + } }; Pass *createPostEmscriptenPass() { diff --git a/test/passes/post-emscripten.txt b/test/passes/post-emscripten.txt index 179dec8c8..947318051 100644 --- a/test/passes/post-emscripten.txt +++ b/test/passes/post-emscripten.txt @@ -1,6 +1,9 @@ (module (type $0 (func (param i32))) - (type $1 (func (param i32) (result i32))) + (type $FUNCSIG$ddd (func (param f64 f64) (result f64))) + (type $2 (func (param i32) (result i32))) + (type $3 (func)) + (import "global.Math" "pow" (func $Math_pow (param f64 f64) (result f64))) (memory $0 256 256) (export "load-off-2" (func $load-off-2)) (func $b0 (type $0) (param $x i32) @@ -41,7 +44,7 @@ ) ) ) - (func $load-off-2 (type $1) (param $0 i32) (result i32) + (func $load-off-2 (type $2) (param $0 i32) (result i32) (i32.store (i32.const 6) (get_local $0) @@ -112,4 +115,68 @@ (get_local $0) ) ) + (func $pow2 (type $3) + (local $x f64) + (local $y f64) + (local $2 f64) + (local $3 f64) + (drop + (f64.mul + (tee_local $2 + (f64.const 1) + ) + (get_local $2) + ) + ) + (drop + (call $Math_pow + (f64.const 1) + (f64.const 3) + ) + ) + (drop + (call $Math_pow + (f64.const 2) + (f64.const 1) + ) + ) + (set_local $x + (f64.const 5) + ) + (drop + (f64.mul + (get_local $x) + (get_local $x) + ) + ) + (drop + (f64.mul + (tee_local $y + (f64.const 7) + ) + (get_local $y) + ) + ) + (drop + (f64.mul + (tee_local $3 + (f64.const 8) + ) + (get_local $3) + ) + ) + ) + (func $pow.2 (type $3) + (drop + (f64.sqrt + (f64.const 1) + ) + ) + (drop + (call $Math_pow + (f64.const 1) + (f64.const 0.51) + ) + ) + ) ) diff --git a/test/passes/post-emscripten.wast b/test/passes/post-emscripten.wast index f262975f5..5c255ffca 100644 --- a/test/passes/post-emscripten.wast +++ b/test/passes/post-emscripten.wast @@ -1,6 +1,7 @@ (module (memory 256 256) (type $0 (func (param i32))) + (import "global.Math" "pow" (func $Math_pow (param f64 f64) (result f64))) (func $b0 (type $0) (param $x i32) (drop (i32.load @@ -152,4 +153,59 @@ ) ) ) + (func $pow2 + (local $x f64) + (local $y f64) + (drop + (call $Math_pow + (f64.const 1) + (f64.const 2) + ) + ) + (drop + (call $Math_pow + (f64.const 1) + (f64.const 3) + ) + ) + (drop + (call $Math_pow + (f64.const 2) + (f64.const 1) + ) + ) + (set_local $x (f64.const 5)) + (drop + (call $Math_pow + (get_local $x) + (f64.const 2) + ) + ) + (drop + (call $Math_pow + (tee_local $y (f64.const 7)) + (f64.const 2) + ) + ) + (drop + (call $Math_pow + (f64.const 8) + (f64.const 2) + ) + ) + ) + (func $pow.2 + (drop + (call $Math_pow + (f64.const 1) + (f64.const 0.5) + ) + ) + (drop + (call $Math_pow + (f64.const 1) + (f64.const 0.51) + ) + ) + ) ) |