diff options
-rwxr-xr-x | build-js.sh | 1 | ||||
-rw-r--r-- | src/passes/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/passes/RemoveCopysign.cpp | 106 | ||||
-rw-r--r-- | src/passes/pass.cpp | 1 | ||||
-rw-r--r-- | src/passes/passes.h | 1 | ||||
-rw-r--r-- | src/wasm2asm.h | 1 | ||||
-rw-r--r-- | test/passes/remove-copysign.txt | 40 | ||||
-rw-r--r-- | test/passes/remove-copysign.wast | 7 | ||||
-rw-r--r-- | test/wasm2asm/float-ops.2asm.js | 29 | ||||
-rw-r--r-- | test/wasm2asm/float-ops.wast | 6 |
10 files changed, 193 insertions, 0 deletions
diff --git a/build-js.sh b/build-js.sh index cdea05f65..aa653387d 100755 --- a/build-js.sh +++ b/build-js.sh @@ -110,6 +110,7 @@ echo "building shared bitcode" $BINARYEN_SRC/passes/PrintCallGraph.cpp \ $BINARYEN_SRC/passes/RedundantSetElimination.cpp \ $BINARYEN_SRC/passes/RelooperJumpThreading.cpp \ + $BINARYEN_SRC/passes/RemoveCopysign.cpp \ $BINARYEN_SRC/passes/RemoveImports.cpp \ $BINARYEN_SRC/passes/RemoveMemory.cpp \ $BINARYEN_SRC/passes/RemoveUnusedBrs.cpp \ diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt index d4fff78df..784a46032 100644 --- a/src/passes/CMakeLists.txt +++ b/src/passes/CMakeLists.txt @@ -30,6 +30,7 @@ SET(passes_SOURCES RedundantSetElimination.cpp RelooperJumpThreading.cpp ReReloop.cpp + RemoveCopysign.cpp RemoveImports.cpp RemoveMemory.cpp RemoveUnusedBrs.cpp diff --git a/src/passes/RemoveCopysign.cpp b/src/passes/RemoveCopysign.cpp new file mode 100644 index 000000000..2b57441ee --- /dev/null +++ b/src/passes/RemoveCopysign.cpp @@ -0,0 +1,106 @@ +/* + * Copyright 2018 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. + */ + +// +// Removes the `f32.copysign` and `f64.copysign` instructions and replaces them +// with equivalent bit operations. Primarily intended to be used with `wasm2asm` +// where `Math.copysign` doesn't exist. +// + +#include <wasm.h> +#include <pass.h> + +#include "wasm-builder.h" + +namespace wasm { + +struct RemoveCopysignPass : public WalkerPass<PostWalker<RemoveCopysignPass>> { + bool isFunctionParallel() override { return false; } + + Pass* create() override { return new RemoveCopysignPass; } + + void doWalkModule(Module* module) { + if (!builder) builder = make_unique<Builder>(*module); + PostWalker<RemoveCopysignPass>::doWalkModule(module); + } + + void doWalkFunction(Function* func) { + if (!builder) builder = make_unique<Builder>(*getModule()); + PostWalker<RemoveCopysignPass>::doWalkFunction(func); + } + + void visitBinary(Binary *curr) { + Literal signBit, otherBits; + UnaryOp int2float, float2int; + BinaryOp bitAnd, bitOr; + switch (curr->op) { + case CopySignFloat32: + float2int = ReinterpretFloat32; + int2float = ReinterpretInt32; + bitAnd = AndInt32; + bitOr = OrInt32; + signBit = Literal(uint32_t(1 << 31)); + otherBits = Literal(uint32_t(1 << 31) - 1); + break; + + case CopySignFloat64: + float2int = ReinterpretFloat64; + int2float = ReinterpretInt64; + bitAnd = AndInt64; + bitOr = OrInt64; + signBit = Literal(uint64_t(1) << 63); + otherBits = Literal((uint64_t(1) << 63) - 1); + break; + + default: return; + } + + replaceCurrent( + builder->makeUnary( + int2float, + builder->makeBinary( + bitOr, + builder->makeBinary( + bitAnd, + builder->makeUnary( + float2int, + curr->left + ), + builder->makeConst(otherBits) + ), + builder->makeBinary( + bitAnd, + builder->makeUnary( + float2int, + curr->right + ), + builder->makeConst(signBit) + ) + ) + ) + ); + } + +private: + std::unique_ptr<Builder> builder; +}; + +Pass *createRemoveCopysignPass() { + return new RemoveCopysignPass(); +} + +} // namespace wasm + diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp index 5c43aaa4e..e820cd1fa 100644 --- a/src/passes/pass.cpp +++ b/src/passes/pass.cpp @@ -99,6 +99,7 @@ void PassRegistry::registerPasses() { registerPass("print-full", "print in full s-expression format", createFullPrinterPass); registerPass("print-call-graph", "print call graph", createPrintCallGraphPass); registerPass("relooper-jump-threading", "thread relooper jumps (fastcomp output only)", createRelooperJumpThreadingPass); + registerPass("remove-copysign", "removes the copysign instruction", createRemoveCopysignPass); registerPass("remove-imports", "removes imports and replaces them with nops", createRemoveImportsPass); registerPass("remove-memory", "removes memory segments", createRemoveMemoryPass); registerPass("remove-unused-brs", "removes breaks from locations that are not needed", createRemoveUnusedBrsPass); diff --git a/src/passes/passes.h b/src/passes/passes.h index cf77f9fac..410b8fe11 100644 --- a/src/passes/passes.h +++ b/src/passes/passes.h @@ -56,6 +56,7 @@ Pass* createPrecomputePropagatePass(); Pass* createPrinterPass(); Pass* createPrintCallGraphPass(); Pass* createRelooperJumpThreadingPass(); +Pass* createRemoveCopysignPass(); Pass* createRemoveImportsPass(); Pass* createRemoveMemoryPass(); Pass* createRemoveUnusedBrsPass(); diff --git a/src/wasm2asm.h b/src/wasm2asm.h index 357896654..9e3abaa25 100644 --- a/src/wasm2asm.h +++ b/src/wasm2asm.h @@ -384,6 +384,7 @@ Ref Wasm2AsmBuilder::processWasm(Module* wasm) { addWasmCompatibilityFuncs(wasm); PassRunner runner(wasm); runner.add<AutoDrop>(); + runner.add("remove-copysign"); // must be before i64-to-i32 runner.add("i64-to-i32-lowering"); runner.add("flatten"); runner.add("simplify-locals-notee-nostructure"); diff --git a/test/passes/remove-copysign.txt b/test/passes/remove-copysign.txt new file mode 100644 index 000000000..b411f083b --- /dev/null +++ b/test/passes/remove-copysign.txt @@ -0,0 +1,40 @@ +(module + (type $0 (func (param f64 f64) (result f64))) + (type $1 (func (param f32 f32) (result f32))) + (func $copysign64 (; 0 ;) (type $0) (param $0 f64) (param $1 f64) (result f64) + (f64.reinterpret/i64 + (i64.or + (i64.and + (i64.reinterpret/f64 + (get_local $0) + ) + (i64.const 9223372036854775807) + ) + (i64.and + (i64.reinterpret/f64 + (get_local $1) + ) + (i64.const -9223372036854775808) + ) + ) + ) + ) + (func $copysign32 (; 1 ;) (type $1) (param $0 f32) (param $1 f32) (result f32) + (f32.reinterpret/i32 + (i32.or + (i32.and + (i32.reinterpret/f32 + (get_local $0) + ) + (i32.const 2147483647) + ) + (i32.and + (i32.reinterpret/f32 + (get_local $1) + ) + (i32.const -2147483648) + ) + ) + ) + ) +) diff --git a/test/passes/remove-copysign.wast b/test/passes/remove-copysign.wast new file mode 100644 index 000000000..d64a30965 --- /dev/null +++ b/test/passes/remove-copysign.wast @@ -0,0 +1,7 @@ +(module + (func $copysign64 (param $0 f64) (param $1 f64) (result f64) + (f64.copysign (get_local $0) (get_local $1))) + (func $copysign32 (param $0 f32) (param $1 f32) (result f32) + (f32.copysign (get_local $0) (get_local $1))) +) + diff --git a/test/wasm2asm/float-ops.2asm.js b/test/wasm2asm/float-ops.2asm.js index fceaa7985..bad4bae9d 100644 --- a/test/wasm2asm/float-ops.2asm.js +++ b/test/wasm2asm/float-ops.2asm.js @@ -206,6 +206,35 @@ function asmFunc(global, env, buffer) { return +Math_sqrt($0); } + function copysign64($0, $1) { + $0 = +$0; + $1 = +$1; + var i64toi32_i32$0 = 0, i64toi32_i32$2 = 0, i64toi32_i32$3 = 0, i64toi32_i32$1 = 0; + HEAPF64[0 >> 3] = $0; + i64toi32_i32$0 = HEAP32[(0 + 4 | 0) >> 2] | 0; + i64toi32_i32$2 = HEAP32[0 >> 2] | 0; + i64toi32_i32$1 = 2147483647; + i64toi32_i32$3 = 4294967295; + i64toi32_i32$1 = i64toi32_i32$0 & i64toi32_i32$1 | 0; + i64toi32_i32$3 = i64toi32_i32$2 & i64toi32_i32$3 | 0; + HEAPF64[0 >> 3] = $1; + i64toi32_i32$2 = HEAP32[(0 + 4 | 0) >> 2] | 0; + i64toi32_i32$3 = HEAP32[0 >> 2] | 0; + i64toi32_i32$0 = 2147483648; + i64toi32_i32$0 = i64toi32_i32$2 & i64toi32_i32$0 | 0; + i64toi32_i32$2 = i64toi32_i32$3 & 0 | 0; + i64toi32_i32$0 = i64toi32_i32$1 | i64toi32_i32$0 | 0; + HEAP32[0 >> 2] = i64toi32_i32$3 | i64toi32_i32$2 | 0; + HEAP32[(0 + 4 | 0) >> 2] = i64toi32_i32$0; + return +(+HEAPF64[0 >> 3]); + } + + function copysign32($0, $1) { + $0 = Math_fround($0); + $1 = Math_fround($1); + return Math_fround((HEAP32[0] = (HEAPF32[0] = $0, HEAP32[0]) & 2147483647 | 0 | ((HEAPF32[0] = $1, HEAP32[0]) & 2147483648 | 0) | 0, HEAPF32[0])); + } + function __wasm_ctz_i32(x) { x = x | 0; var $1 = 0; diff --git a/test/wasm2asm/float-ops.wast b/test/wasm2asm/float-ops.wast index 4ca32bb49..de26c9931 100644 --- a/test/wasm2asm/float-ops.wast +++ b/test/wasm2asm/float-ops.wast @@ -101,4 +101,10 @@ (func (export "f64.sqrt") (param $0 f64) (result f64) (f64.sqrt (get_local $0))) + + ;; copysign + (func $copysign64 (param $0 f64) (param $1 f64) (result f64) + (f64.copysign (get_local $0) (get_local $1))) + (func $copysign32 (param $0 f32) (param $1 f32) (result f32) + (f32.copysign (get_local $0) (get_local $1))) ) |