summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2015-11-24 17:56:39 -0800
committerAlon Zakai <alonzakai@gmail.com>2015-11-24 17:56:39 -0800
commit78560acbd0da7238cbf619ada67e4ad98d17605a (patch)
tree8ca4bb87ff26faaff2f75497015415b3f9089dff /src
parenta1d8724f01ad324754cfbab6a175ad47001b87a9 (diff)
downloadbinaryen-78560acbd0da7238cbf619ada67e4ad98d17605a.tar.gz
binaryen-78560acbd0da7238cbf619ada67e4ad98d17605a.tar.bz2
binaryen-78560acbd0da7238cbf619ada67e4ad98d17605a.zip
initial work on wasm2asm
Diffstat (limited to 'src')
-rw-r--r--src/wasm2asm.h187
1 files changed, 187 insertions, 0 deletions
diff --git a/src/wasm2asm.h b/src/wasm2asm.h
new file mode 100644
index 000000000..94406813e
--- /dev/null
+++ b/src/wasm2asm.h
@@ -0,0 +1,187 @@
+
+//
+// WebAssembly-to-asm.js translator. Uses the Emscripten optimizer
+// infrastructure.
+//
+
+#include "wasm.h"
+#include "emscripten-optimizer/optimizer.h"
+#include "mixed_arena.h"
+
+namespace wasm {
+
+using namespace cashew;
+
+IString ASM_FUNC("asmFunc");
+
+//
+// Wasm2AsmBuilder - converts a WebAssembly module into asm.js
+//
+
+class Wasm2AsmBuilder {
+ MixedArena& allocator;
+
+ // How many temp vars we need
+ int i32s = 0, f32s = 0, f64s = 0;
+
+public:
+ Asm2WasmBuilder(MixedArena& allocator) : allocator(allocator) {}
+
+ Ref processWasm(Module* wasm);
+ Ref processFunction(Function* func);
+
+ //
+ // Tracks state while converting a function. We need to add new
+ // temporaries, and overall handle the fact that statements ==
+ // expressions in wasm, but not asm.js. That means that a wasm
+ // expression may be turned into an asm.js statement, which we
+ // cannot just place into an expression, but need to keep
+ // creating statements until we reach a statement context.
+ //
+
+ // @param receives Whether the context we are in receives a value, or if not,
+ // then we can drop our return, if we have one.
+ Ref processExpression(Expression* curr, bool XXX WasmType receives);
+};
+
+Ref Wasm2AsmBuilder::processWasm(Module* wasm) {
+ Ref ret = ValueBuilder::makeTopLevel();
+ Ref asmFunc = ValueBuilder::makeFunction();
+ asmFunc[1] = ValueBuilder::makeRawString(ASM_FUNC);
+ ret[1]->push_back(asmFunc);
+ // imports XXX
+ // exports XXX
+ // functions
+ for (auto func : wasm->functions) {
+ asmFunc[3]->push_back(processFunction(func));
+ }
+ // table XXX
+ // memory XXX
+ return ret;
+}
+
+Ref Wasm2AsmBuilder::processFunction(Function* func) {
+ Ref ret = ValueBuilder::makeFunction();
+ ret[1] = ValueBuilder::makeRawString(func->name);
+ // arguments XXX
+ // body
+ ret[3]->push_back(processExpression(func->body, func->result != none));
+ // locals, including new temp locals XXX
+ return ret;
+}
+
+Ref Wasm2AsmBuilder::processExpression(Expression* curr) {
+ struct ExpressionProcessor : public WasmVisitor<Ref> {
+ bool receives;
+ ExpressionProcessor(bool receives) : receives(receives) {}
+
+ // Expressions with control flow turn into a block, which we must
+ // then handle, even if we are an expression.
+ bool isBlock(Ref ast) {
+ return ast[0] == BLOCK;
+ }
+
+ // If we replace an expression with a block, and we need to return
+ // a value, it will show up in the last element, as an assign. This
+ // returns it.
+ IString getBlockValue(Ref ast) {
+ assert(ast.size() >= 2 && ast[1].size() > 0);
+ Ref last = deStat(ast[1][ast[1].size()-1]);
+ assert(last[0] == ASSIGN && last[2][0] == NAME);
+ return last[2][1]->getIString();
+ }
+
+ Ref blockify(Ref ast) {
+ if (isBlock(ast)) return ast;
+ Ref ret = ValueBuilder::makeBlock();
+ ret[1]->push_back(ast);
+ return ret;
+ }
+
+ Ref blockifyWithValue(Ref ast) {
+ if (isBlock(ast)) return ast;
+ Ref ret = ValueBuilder::makeBlock();
+ ret[1]->push_back(ast);
+ return ret;
+ }
+
+ // Visitors
+
+ void visitBlock(Block *curr) override {
+ Ref ret = ValueBuilder::makeBlock();
+ size_t size = curr->list.size();
+ for (size_t i = 0; i < size; i++) {
+ ret[1]->push_back(processExpression(func->body, i < size-1 ? false : receives);
+ }
+ return ret;
+ }
+ void visitIf(If *curr) override {
+ assert(receives ? !!curr->ifFalse : true); // an if without an else cannot be in a receiving context
+ Ref condition = processExpression(curr->condition, receives);
+ Ref ifTrue = processExpression(curr->ifTrue, receives);
+ Ref ifFalse;
+ if (curr->ifFalse) {
+ ifFalse = processExpression(curr->ifFalse, receives);
+ }
+ if (!isBlock(condition) && !receives) {
+ return ValueBuilder::makeIf(condition, ifTrue, ifFalse); // simple if
+ }
+ if (receives) {
+ IString parent->getTemp();
+ ifTrue = blockifyWithValue(ifTrue);
+ ifFalse = blockifyWithValue(ifFalse);
+ }
+ condition = blockify(blockify);
+ // just add an if to the block
+ IString check = getBlockValue(condition);
+ condition[1]->push_back(ValueBuilder::makeIf(condition, ifTrue, ifFalse));
+ return condition;
+ if (isBlock(condition)) {
+ }
+ }
+ void visitLoop(Loop *curr) override {
+ }
+ void visitLabel(Label *curr) override {
+ }
+ void visitBreak(Break *curr) override {
+ }
+ void visitSwitch(Switch *curr) override {
+ }
+ void visitCall(Call *curr) override {
+ }
+ void visitCallImport(CallImport *curr) override {
+ }
+ void visitCallIndirect(CallIndirect *curr) override {
+ }
+ void visitGetLocal(GetLocal *curr) override {
+ }
+ void visitSetLocal(SetLocal *curr) override {
+ }
+ void visitLoad(Load *curr) override {
+ }
+ void visitStore(Store *curr) override {
+ }
+ void visitConst(Const *curr) override {
+ }
+ void visitUnary(Unary *curr) override {
+ }
+ void visitBinary(Binary *curr) override {
+ }
+ void visitCompare(Compare *curr) override {
+ }
+ void visitConvert(Convert *curr) override {
+ }
+ void visitSelect(Select *curr) override {
+ }
+ void visitHost(Host *curr) override {
+ }
+ void visitNop(Nop *curr) override {
+ }
+ void visitUnreachable(Unreachable *curr) override {
+ }
+ };
+ return ExpressionProcessor(state).visit(curr);
+}
+
+} // namespace wasm
+