diff options
author | Alon Zakai <alonzakai@gmail.com> | 2015-11-24 17:56:39 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2015-11-24 17:56:39 -0800 |
commit | 78560acbd0da7238cbf619ada67e4ad98d17605a (patch) | |
tree | 8ca4bb87ff26faaff2f75497015415b3f9089dff /src | |
parent | a1d8724f01ad324754cfbab6a175ad47001b87a9 (diff) | |
download | binaryen-78560acbd0da7238cbf619ada67e4ad98d17605a.tar.gz binaryen-78560acbd0da7238cbf619ada67e4ad98d17605a.tar.bz2 binaryen-78560acbd0da7238cbf619ada67e4ad98d17605a.zip |
initial work on wasm2asm
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm2asm.h | 187 |
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 + |