summaryrefslogtreecommitdiff
path: root/src/tools/wasm2js.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/wasm2js.cpp')
-rw-r--r--src/tools/wasm2js.cpp60
1 files changed, 52 insertions, 8 deletions
diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp
index f55f2586b..34ed2d9cb 100644
--- a/src/tools/wasm2js.cpp
+++ b/src/tools/wasm2js.cpp
@@ -24,6 +24,7 @@
#include "wasm-s-parser.h"
#include "wasm2js.h"
#include "optimization-options.h"
+#include "pass.h"
using namespace cashew;
using namespace wasm;
@@ -32,6 +33,33 @@ using namespace wasm;
namespace {
+static void optimizeWasm(Module& wasm, PassOptions options) {
+ // Perform various optimizations that will be good for JS, but would not be great
+ // for wasm in general
+ struct OptimizeForJS : public WalkerPass<PostWalker<OptimizeForJS>> {
+ bool isFunctionParallel() override { return true; }
+
+ Pass* create() override { return new OptimizeForJS; }
+
+ void visitBinary(Binary* curr) {
+ // x - -c (where c is a constant) is larger than x + c, in js (but not
+ // necessarily in wasm, where LEBs prefer negatives).
+ if (curr->op == SubInt32) {
+ if (auto* c = curr->right->dynCast<Const>()) {
+ if (c->value.geti32() < 0) {
+ curr->op = AddInt32;
+ c->value = c->value.neg();
+ }
+ }
+ }
+ }
+ };
+
+ PassRunner runner(&wasm, options);
+ runner.add<OptimizeForJS>();
+ runner.run();
+}
+
template<typename T>
static void printJS(Ref ast, T& output) {
JSPrinter jser(true, true, ast);
@@ -41,10 +69,15 @@ static void printJS(Ref ast, T& output) {
static void optimizeJS(Ref ast) {
// helpers
+
auto isOrZero = [](Ref node) {
return node->isArray() && node->size() > 0 && node[0] == BINARY && node[1] == OR && node[3]->isNumber() && node[3]->getNumber() == 0;
};
+ auto isPlus = [](Ref node) {
+ return node->isArray() && node->size() > 0 && node[0] == UNARY_PREFIX && node[1] == PLUS;
+ };
+
auto isBitwise = [](Ref node) {
if (node->isArray() && node->size() > 0 && node[0] == BINARY) {
auto op = node[1];
@@ -84,13 +117,22 @@ static void optimizeJS(Ref ast) {
node[3] = node[3][2];
}
}
+ // +(+x) => +x
+ else if (isPlus(node)) {
+ while (isPlus(node[2])) {
+ node[2] = node[2][2];
+ }
+ }
});
}
-static void emitWasm(Module& wasm, Output& output, Wasm2JSBuilder::Flags flags, Name name, bool optimize=false) {
- Wasm2JSBuilder wasm2js(flags);
+static void emitWasm(Module& wasm, Output& output, Wasm2JSBuilder::Flags flags, PassOptions options, Name name) {
+ if (options.optimizeLevel > 0) {
+ optimizeWasm(wasm, options);
+ }
+ Wasm2JSBuilder wasm2js(flags, options);
auto js = wasm2js.processWasm(&wasm, name);
- if (optimize) {
+ if (options.optimizeLevel >= 2) {
optimizeJS(js);
}
Wasm2JSGlue glue(wasm, output, flags, name);
@@ -104,7 +146,8 @@ public:
AssertionEmitter(Element& root,
SExpressionWasmBuilder& sexpBuilder,
Output& out,
- Wasm2JSBuilder::Flags flags) : root(root), sexpBuilder(sexpBuilder), out(out), flags(flags) {}
+ Wasm2JSBuilder::Flags flags,
+ PassOptions options) : root(root), sexpBuilder(sexpBuilder), out(out), flags(flags), options(options) {}
void emit();
@@ -113,6 +156,7 @@ private:
SExpressionWasmBuilder& sexpBuilder;
Output& out;
Wasm2JSBuilder::Flags flags;
+ PassOptions options;
Module tempAllocationModule;
Ref emitAssertReturnFunc(Builder& wasmBuilder,
@@ -131,7 +175,7 @@ private:
void fixCalls(Ref asmjs, Name asmModule);
Ref processFunction(Function* func) {
- Wasm2JSBuilder sub(flags);
+ Wasm2JSBuilder sub(flags, options);
return sub.processStandaloneFunction(&tempAllocationModule, func);
}
@@ -370,7 +414,7 @@ void AssertionEmitter::emit() {
asmModule = Name(moduleNameS.str().c_str());
Module wasm;
SExpressionWasmBuilder builder(wasm, e);
- emitWasm(wasm, out, flags, funcName);
+ emitWasm(wasm, out, flags, options, funcName);
continue;
}
if (!isAssertHandled(e)) {
@@ -492,9 +536,9 @@ int main(int argc, const char *argv[]) {
if (options.debug) std::cerr << "j-printing..." << std::endl;
Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release);
if (!binaryInput && options.extra["asserts"] == "1") {
- AssertionEmitter(*root, *sexprBuilder, output, flags).emit();
+ AssertionEmitter(*root, *sexprBuilder, output, flags, options.passOptions).emit();
} else {
- emitWasm(wasm, output, flags, "asmFunc", options.passOptions.optimizeLevel > 0);
+ emitWasm(wasm, output, flags, options.passOptions, "asmFunc");
}
if (options.debug) std::cerr << "done." << std::endl;