summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild-js.sh1
-rw-r--r--src/passes/CMakeLists.txt1
-rw-r--r--src/passes/RemoveCopysign.cpp106
-rw-r--r--src/passes/pass.cpp1
-rw-r--r--src/passes/passes.h1
-rw-r--r--src/wasm2asm.h1
-rw-r--r--test/passes/remove-copysign.txt40
-rw-r--r--test/passes/remove-copysign.wast7
-rw-r--r--test/wasm2asm/float-ops.2asm.js29
-rw-r--r--test/wasm2asm/float-ops.wast6
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)))
)