diff options
Diffstat (limited to 'src')
-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 |
5 files changed, 110 insertions, 0 deletions
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"); |