diff options
-rw-r--r-- | src/asm2wasm.cpp | 128 | ||||
-rw-r--r-- | src/wasm.h | 285 |
2 files changed, 181 insertions, 232 deletions
diff --git a/src/asm2wasm.cpp b/src/asm2wasm.cpp index e20bbe5a1..609909ab8 100644 --- a/src/asm2wasm.cpp +++ b/src/asm2wasm.cpp @@ -224,14 +224,14 @@ class Asm2WasmModule : public wasm::Module { unsigned maxGlobal; // highest address we can put a global struct MappedGlobal { unsigned address; - BasicType type; + WasmType type; bool import; // if true, this is an import - we should read the value, not just set a zero MappedGlobal() : address(0), type(none), import(false) {} - MappedGlobal(unsigned address, BasicType type, bool import) : address(address), type(type), import(import) {} + MappedGlobal(unsigned address, WasmType type, bool import) : address(address), type(type), import(import) {} }; std::map<IString, MappedGlobal> mappedGlobals; - void allocateGlobal(IString name, BasicType type, bool import) { + void allocateGlobal(IString name, WasmType type, bool import) { assert(mappedGlobals.find(name) == mappedGlobals.end()); mappedGlobals.emplace(name, MappedGlobal(nextGlobal, type, import)); nextGlobal += 8; @@ -293,7 +293,7 @@ class Asm2WasmModule : public wasm::Module { } } - char getSigFromType(BasicType type) { + char getSigFromType(WasmType type) { switch (type) { case i32: return 'i'; case f64: return 'd'; @@ -304,7 +304,7 @@ class Asm2WasmModule : public wasm::Module { FunctionType *getFunctionType(Ref parent, ExpressionList& operands) { // generate signature - BasicType result = detectWasmType(parent, nullptr); + WasmType result = detectWasmType(parent, nullptr); std::string str = "FUNCSIG$"; str += getSigFromType(result); for (auto operand : operands) { @@ -332,19 +332,19 @@ public: void optimize(); private: - BasicType asmToWasmType(AsmType asmType) { + WasmType asmToWasmType(AsmType asmType) { switch (asmType) { - case ASM_INT: return BasicType::i32; - case ASM_DOUBLE: return BasicType::f64; - case ASM_NONE: return BasicType::none; + case ASM_INT: return WasmType::i32; + case ASM_DOUBLE: return WasmType::f64; + case ASM_NONE: return WasmType::none; default: abort_on("confused asmType", asmType); } } - AsmType wasmToAsmType(BasicType type) { + AsmType wasmToAsmType(WasmType type) { switch (type) { - case BasicType::i32: return ASM_INT; - case BasicType::f64: return ASM_DOUBLE; - case BasicType::none: return ASM_NONE; + case WasmType::i32: return ASM_INT; + case WasmType::f64: return ASM_DOUBLE; + case WasmType::none: return ASM_NONE; default: abort_on("confused wasmType", type); } } @@ -359,7 +359,7 @@ private: return detectType(ast, data); } - BasicType detectWasmType(Ref ast, AsmData *data) { + WasmType detectWasmType(Ref ast, AsmData *data) { return asmToWasmType(detectAsmType(ast, data)); } @@ -381,18 +381,18 @@ private: if (op == TRSHIFT) { binary = BinaryOp::ShrU; return true; } if (op == EQ) { relational = RelationalOp::Eq; return false; } if (op == NE) { relational = RelationalOp::Ne; return false; } - BasicType leftType = detectWasmType(left, asmData); + WasmType leftType = detectWasmType(left, asmData); #if 0 std::cout << "CHECK\n"; left->stringify(std::cout); std::cout << " => "; - printBasicType(std::cout, leftType); + printWasmType(std::cout, leftType); std::cout << '\n'; right->stringify(std::cout); std::cout << " => "; - printBasicType(std::cout, detectWasmType(right, asmData)); + printWasmType(std::cout, detectWasmType(right, asmData)); #endif - bool isInteger = leftType == BasicType::i32; + bool isInteger = leftType == WasmType::i32; bool isUnsigned = isUnsignedCoercion(left) || isUnsignedCoercion(right); if (op == DIV) { if (isInteger) { @@ -473,7 +473,7 @@ void Asm2WasmModule::processAsm(Ref ast) { Ref body = asmFunction[3]; assert(body[0][0] == STAT && body[0][1][0] == STRING && (body[0][1][1]->getIString() == IString("use asm") || body[0][1][1]->getIString() == IString("almost asm"))); - auto addImport = [&](IString name, Ref imported, BasicType type) { + auto addImport = [&](IString name, Ref imported, WasmType type) { assert(imported[0] == DOT); Ref module = imported[1]; if (module[0] == DOT) { @@ -499,9 +499,9 @@ void Asm2WasmModule::processAsm(Ref ast) { import.base = imported[2]->getIString(); // special-case some asm builtins if (import.module == GLOBAL && (import.base == NAN_ || import.base == INFINITY_)) { - type = BasicType::f64; + type = WasmType::f64; } - if (type != BasicType::none) { + if (type != WasmType::none) { // wasm has no imported constants, so allocate a global, and we need to write the value into that allocateGlobal(name, type, true); } else { @@ -522,12 +522,12 @@ void Asm2WasmModule::processAsm(Ref ast) { if (value[0] == NUM) { // global int assert(value[1]->getNumber() == 0); - allocateGlobal(name, BasicType::i32, false); + allocateGlobal(name, WasmType::i32, false); } else if (value[0] == BINARY) { // int import assert(value[1] == OR && value[3][0] == NUM && value[3][1]->getNumber() == 0); Ref import = value[2]; // env.what - addImport(name, import, BasicType::i32); + addImport(name, import, WasmType::i32); } else if (value[0] == UNARY_PREFIX) { // double import or global assert(value[1] == PLUS); @@ -535,14 +535,14 @@ void Asm2WasmModule::processAsm(Ref ast) { if (import[0] == NUM) { // global assert(import[1]->getNumber() == 0); - allocateGlobal(name, BasicType::f64, false); + allocateGlobal(name, WasmType::f64, false); } else { // import - addImport(name, import, BasicType::f64); + addImport(name, import, WasmType::f64); } } else if (value[0] == DOT) { // function import - addImport(name, value, BasicType::none); + addImport(name, value, WasmType::none); } else if (value[0] == NEW) { // ignore imports of typed arrays, but note the names of the arrays value = value[1]; @@ -583,11 +583,11 @@ void Asm2WasmModule::processAsm(Ref ast) { } for (unsigned k = 0; k < contents->size(); k++) { IString curr = contents[k][1]->getIString(); - if (table.vars.size() <= k) { - table.vars.push_back(curr); + if (table.names.size() <= k) { + table.names.push_back(curr); } else { if (counts[curr] == 1) { // if just one appearance, not a null thunk - table.vars[k] = curr; + table.names[k] = curr; } } } @@ -731,12 +731,12 @@ Function* Asm2WasmModule::processFunction(Ref ast) { assert(mappedGlobals.find(name) != mappedGlobals.end()); MappedGlobal global = mappedGlobals[name]; auto ret = allocator.alloc<Store>(); - ret->bytes = getBasicTypeSize(global.type); + ret->bytes = getWasmTypeSize(global.type); ret->float_ = isFloat(global.type); ret->offset = 0; ret->align = ret->bytes; auto ptr = allocator.alloc<Const>(); - ptr->value.type = BasicType::i32; // XXX for wasm64, need 64 + ptr->value.type = WasmType::i32; // XXX for wasm64, need 64 ptr->value.i32 = global.address; ret->ptr = ptr; ret->value = process(ast[3]); @@ -762,7 +762,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { } else if (what == BINARY) { if (ast[1] == OR && ast[3][0] == NUM && ast[3][1]->getNumber() == 0) { auto ret = process(ast[2]); // just look through the ()|0 coercion - ret->type = BasicType::i32; // we add it here for e.g. call coercions + ret->type = WasmType::i32; // we add it here for e.g. call coercions return ret; } BinaryOp binary; @@ -786,10 +786,10 @@ Function* Asm2WasmModule::processFunction(Ref ast) { auto ret = allocator.alloc<Const>(); double num = ast[1]->getNumber(); if (isInteger32(num)) { - ret->value.type = BasicType::i32; + ret->value.type = WasmType::i32; ret->value.i32 = num; } else { - ret->value.type = BasicType::f64; + ret->value.type = WasmType::f64; ret->value.f64 = num; } ret->type = ret->value.type; @@ -807,13 +807,13 @@ Function* Asm2WasmModule::processFunction(Ref ast) { assert(mappedGlobals.find(name) != mappedGlobals.end()); MappedGlobal global = mappedGlobals[name]; auto ret = allocator.alloc<Load>(); - ret->bytes = getBasicTypeSize(global.type); + ret->bytes = getWasmTypeSize(global.type); ret->signed_ = true; // but doesn't matter ret->float_ = isFloat(global.type); ret->offset = 0; ret->align = ret->bytes; auto ptr = allocator.alloc<Const>(); - ptr->value.type = BasicType::i32; // XXX for wasm64, need 64 + ptr->value.type = WasmType::i32; // XXX for wasm64, need 64 ptr->value.i32 = global.address; ret->ptr = ptr; ret->type = global.type; @@ -831,13 +831,13 @@ Function* Asm2WasmModule::processFunction(Ref ast) { ret->offset = 0; ret->align = view.bytes; ret->ptr = processUnshifted(ast[2], view.bytes); - ret->type = getBasicType(view.bytes, !view.integer); + ret->type = getWasmType(view.bytes, !view.integer); return ret; } else if (what == UNARY_PREFIX) { if (ast[1] == PLUS) { if (ast[2][0] == NUM) { auto ret = allocator.alloc<Const>(); - ret->value.type = BasicType::f64; + ret->value.type = WasmType::f64; ret->value.f64 = ast[2][1]->getNumber(); ret->type = ret->value.type; return ret; @@ -847,12 +847,12 @@ Function* Asm2WasmModule::processFunction(Ref ast) { auto ret = allocator.alloc<Convert>(); ret->op = isUnsignedCoercion(ast[2]) ? ConvertUInt32 : ConvertSInt32; ret->value = process(ast[2]); - ret->type = BasicType::f64; + ret->type = WasmType::f64; return ret; } assert(childType == ASM_NONE || childType == ASM_DOUBLE); // e.g. a coercion on a call or for a return auto ret = process(ast[2]); // just look through the +() coercion - ret->type = BasicType::f64; // we add it here for e.g. call coercions + ret->type = WasmType::f64; // we add it here for e.g. call coercions return ret; } else if (ast[1] == MINUS) { if (ast[2][0] == NUM || (ast[2][0] == UNARY_PREFIX && ast[2][1] == PLUS && ast[2][2][0] == NUM)) { @@ -868,14 +868,14 @@ Function* Asm2WasmModule::processFunction(Ref ast) { ret->op = Sub; ret->left = allocator.alloc<Const>()->set(Literal((int32_t)0)); ret->right = process(ast[2]); - ret->type = BasicType::i32; + ret->type = WasmType::i32; return ret; } assert(asmType == ASM_DOUBLE); auto ret = allocator.alloc<Unary>(); ret->op = Neg; ret->value = process(ast[2]); - ret->type = BasicType::f64; + ret->type = WasmType::f64; return ret; } else if (ast[1] == B_NOT) { // ~, might be ~~ as a coercion or just a not @@ -883,7 +883,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { auto ret = allocator.alloc<Convert>(); ret->op = TruncSFloat64; // equivalent to U, except for error handling, which asm.js doesn't have anyhow ret->value = process(ast[2][2]); - ret->type = BasicType::i32; + ret->type = WasmType::i32; return ret; } // no bitwise unary not, so do xor with -1 @@ -891,7 +891,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { ret->op = Xor; ret->left = process(ast[2]); ret->right = allocator.alloc<Const>()->set(Literal(int32_t(-1))); - ret->type = BasicType::i32; + ret->type = WasmType::i32; return ret; } else if (ast[1] == L_NOT) { // no logical unary not, so do == 0 @@ -917,7 +917,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { ret->op = Mul; ret->left = process(ast[2][0]); ret->right = process(ast[2][1]); - ret->type = BasicType::i32; + ret->type = WasmType::i32; return ret; } if (name == Math_clz32) { @@ -925,7 +925,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { auto ret = allocator.alloc<Unary>(); ret->op = Clz; ret->value = process(ast[2][0]); - ret->type = BasicType::i32; + ret->type = WasmType::i32; return ret; } Call* ret; @@ -962,7 +962,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { ret->type = getFunctionType(astStackHelper.getParent(), ret->operands); return ret; } else if (what == RETURN) { - BasicType type = !!ast[1] ? detectWasmType(ast[1], &asmData) : none; + WasmType type = !!ast[1] ? detectWasmType(ast[1], &asmData) : none; if (seenReturn) { assert(function->result == type); } else { @@ -971,7 +971,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { // wasm has no return, so we just break on the topmost block needTopmost = true; auto ret = allocator.alloc<Break>(); - ret->var = TOPMOST; + ret->name = TOPMOST; ret->condition = nullptr; ret->value = !!ast[1] ? process(ast[1]) : nullptr; return ret; @@ -980,14 +980,14 @@ Function* Asm2WasmModule::processFunction(Ref ast) { } else if (what == BREAK) { auto ret = allocator.alloc<Break>(); assert(breakStack.size() > 0); - ret->var = !!ast[1] ? getBreakLabelName(ast[1]->getIString()) : breakStack.back(); + ret->name = !!ast[1] ? getBreakLabelName(ast[1]->getIString()) : breakStack.back(); ret->condition = nullptr; ret->value = nullptr; return ret; } else if (what == CONTINUE) { auto ret = allocator.alloc<Break>(); assert(continueStack.size() > 0); - ret->var = !!ast[1] ? getContinueLabelName(ast[1]->getIString()) : continueStack.back(); + ret->name = !!ast[1] ? getContinueLabelName(ast[1]->getIString()) : continueStack.back(); ret->condition = nullptr; ret->value = nullptr; return ret; @@ -1011,7 +1011,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { ret->body = process(ast[2]); } else { Break *continueWhile = allocator.alloc<Break>(); - continueWhile->var = in; + continueWhile->name = in; continueWhile->condition = process(ast[1]); continueWhile->value = nullptr; auto body = allocator.alloc<Block>(); @@ -1033,7 +1033,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { } else { stop = getNextId("do-once"); } - block->var = stop; + block->name = stop; breakStack.push_back(stop); continueStack.push_back(IMPOSSIBLE_CONTINUE); block->list.push_back(process(ast[2])); @@ -1060,7 +1060,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { continueStack.pop_back(); breakStack.pop_back(); Break *continueIf = allocator.alloc<Break>(); - continueIf->var = in; + continueIf->name = in; continueIf->condition = process(ast[1]); continueIf->value = nullptr; if (Block *block = dynamic_cast<Block*>(ret->body)) { @@ -1094,7 +1094,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { IString name = getNextId("switch"); breakStack.push_back(name); auto ret = allocator.alloc<Switch>(); - ret->var = name; + ret->name = name; ret->value = process(ast[1]); Ref cases = ast[2]; for (unsigned i = 0; i < cases->size(); i++) { @@ -1130,7 +1130,7 @@ Function* Asm2WasmModule::processFunction(Ref ast) { unsigned addr = ptr[1]->getInteger(); unsigned shifted = addr << shifts; auto ret = allocator.alloc<Const>(); - ret->value.type = BasicType::i32; + ret->value.type = WasmType::i32; ret->value.i32 = shifted; return (Expression*)ret; } @@ -1151,13 +1151,13 @@ Function* Asm2WasmModule::processFunction(Ref ast) { function->body = processStatements(body, start); if (needTopmost) { Block* topmost = dynamic_cast<Block*>(function->body); - // if there's no block there, or there is a block but it already has a var, we need a new block. - if (!topmost || topmost->var.is()) { + // if there's no block there, or there is a block but it already has a name, we need a new block. + if (!topmost || topmost->name.is()) { topmost = allocator.alloc<Block>(); topmost->list.push_back(function->body); function->body = topmost; } - topmost->var = TOPMOST; + topmost->name = TOPMOST; } // cleanups/checks assert(breakStack.size() == 0 && continueStack.size() == 0); @@ -1172,10 +1172,10 @@ void Asm2WasmModule::optimize() { Expression* walkBlock(Block *curr) override { if (curr->list.size() != 1) return curr; // just one element; maybe we can return just the element - if (curr->var.isNull()) return curr->list[0]; + if (curr->name.isNull()) return curr->list[0]; // we might be broken to, but if it's a trivial singleton child break, we can optimize here as well Break *child = dynamic_cast<Break*>(curr->list[0]); - if (!child || child->var != curr->var || !child->value) return curr; + if (!child || child->name != curr->name || !child->value) return curr; struct BreakSeeker : public WasmWalker { IString target; // look for this one @@ -1184,12 +1184,12 @@ void Asm2WasmModule::optimize() { BreakSeeker(IString target) : target(target), found(false) {} Expression* walkBreak(Break *curr) override { - if (curr->var == target) found++; + if (curr->name == target) found++; } }; - // look in the child's children to see if there are more uses of this var - BreakSeeker breakSeeker(curr->var); + // look in the child's children to see if there are more uses of this name + BreakSeeker breakSeeker(curr->name); breakSeeker.walk(child->condition); breakSeeker.walk(child->value); if (breakSeeker.found == 0) return child->value; @@ -1257,7 +1257,7 @@ int main(int argc, char **argv) { wasm.optimize(); if (debug) std::cerr << "printing...\n"; - wasm.print(std::cout); + std::cout << wasm; if (debug) std::cerr << "done.\n"; } diff --git a/src/wasm.h b/src/wasm.h index f66f8bb8c..86bb91cc5 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -52,14 +52,15 @@ std::ostream &doIndent(std::ostream &o, unsigned indent) { } return o; } -void incIndent(std::ostream &o, unsigned& indent) { +std::ostream &incIndent(std::ostream &o, unsigned& indent) { o << '\n'; - indent++; + indent++; + return o; } -void decIndent(std::ostream &o, unsigned& indent) { +std::ostream &decIndent(std::ostream &o, unsigned& indent) { indent--; doIndent(o, indent); - o << ')'; + return o << ')'; } // Basics @@ -69,16 +70,15 @@ struct Name : public cashew::IString { Name(const char *str) : cashew::IString(str) {} Name(cashew::IString str) : cashew::IString(str) {} - std::ostream& print(std::ostream &o) { - assert(str); - o << '$' << str; // reference interpreter requires we prefix all names - return o; + friend std::ostream& operator<<(std::ostream &o, Name name) { + assert(name.str); + return o << '$' << name.str; // reference interpreter requires we prefix all names } }; // Types -enum BasicType { +enum WasmType { none, i32, i64, @@ -86,28 +86,27 @@ enum BasicType { f64 }; -std::ostream& printBasicType(std::ostream &o, BasicType type) { +const char* printWasmType(WasmType type) { switch (type) { - case BasicType::none: o << "none"; break; - case BasicType::i32: o << "i32"; break; - case BasicType::i64: o << "i64"; break; - case BasicType::f32: o << "f32"; break; - case BasicType::f64: o << "f64"; break; + case WasmType::none: return "none"; + case WasmType::i32: return "i32"; + case WasmType::i64: return "i64"; + case WasmType::f32: return "f32"; + case WasmType::f64: return "f64"; } - return o; } -unsigned getBasicTypeSize(BasicType type) { +unsigned getWasmTypeSize(WasmType type) { switch (type) { - case BasicType::none: abort(); - case BasicType::i32: return 4; - case BasicType::i64: return 8; - case BasicType::f32: return 4; - case BasicType::f64: return 8; + case WasmType::none: abort(); + case WasmType::i32: return 4; + case WasmType::i64: return 8; + case WasmType::f32: return 4; + case WasmType::f64: return 8; } } -bool isFloat(BasicType type) { +bool isFloat(WasmType type) { switch (type) { case f32: case f64: return true; @@ -115,29 +114,33 @@ bool isFloat(BasicType type) { return false; } -BasicType getBasicType(unsigned size, bool float_) { - if (size < 4) return BasicType::i32; - if (size == 4) return float_ ? BasicType::f32 : BasicType::i32; - if (size == 8) return float_ ? BasicType::f64 : BasicType::i64; +WasmType getWasmType(unsigned size, bool float_) { + if (size < 4) return WasmType::i32; + if (size == 4) return float_ ? WasmType::f32 : WasmType::i32; + if (size == 8) return float_ ? WasmType::f64 : WasmType::i64; abort(); } -void prepareMajorColor(std::ostream &o) { +std::ostream &prepareMajorColor(std::ostream &o) { Colors::red(o); Colors::bold(o); + return o; } -void prepareColor(std::ostream &o) { +std::ostream &prepareColor(std::ostream &o) { Colors::magenta(o); Colors::bold(o); + return o; } -void prepareMinorColor(std::ostream &o) { +std::ostream &prepareMinorColor(std::ostream &o) { Colors::orange(o); + return o; } -void restoreNormalColor(std::ostream &o) { +std::ostream &restoreNormalColor(std::ostream &o) { Colors::normal(o); + return o; } std::ostream& printText(std::ostream &o, const char *str) { @@ -145,12 +148,11 @@ std::ostream& printText(std::ostream &o, const char *str) { Colors::green(o); o << str; Colors::normal(o); - o << '"'; - return o; + return o << '"'; } struct Literal { - BasicType type; + WasmType type; union { int32_t i32; int64_t i64; @@ -158,26 +160,24 @@ struct Literal { double f64; }; - Literal() : type(BasicType::none) {} - Literal(int32_t init) : type(BasicType::i32), i32(init) {} - Literal(int64_t init) : type(BasicType::i64), i64(init) {} - Literal(float init) : type(BasicType::f32), f32(init) {} - Literal(double init) : type(BasicType::f64), f64(init) {} + Literal() : type(WasmType::none) {} + Literal(int32_t init) : type(WasmType::i32), i32(init) {} + Literal(int64_t init) : type(WasmType::i64), i64(init) {} + Literal(float init) : type(WasmType::f32), f32(init) {} + Literal(double init) : type(WasmType::f64), f64(init) {} - std::ostream& print(std::ostream &o) { + friend std::ostream& operator<<(std::ostream &o, Literal literal) { o << '('; - prepareMinorColor(o); - printBasicType(o, type) << ".const "; - switch (type) { + prepareMinorColor(o) << printWasmType(literal.type) << ".const "; + switch (literal.type) { case none: abort(); - case BasicType::i32: o << i32; break; - case BasicType::i64: o << i64; break; - case BasicType::f32: o << JSPrinter::numToString(f32); break; - case BasicType::f64: o << JSPrinter::numToString(f64); break; + case WasmType::i32: o << literal.i32; break; + case WasmType::i64: o << literal.i64; break; + case WasmType::f32: o << JSPrinter::numToString(literal.f32); break; + case WasmType::f64: o << JSPrinter::numToString(literal.f64); break; } restoreNormalColor(o); - o << ')'; - return o; + return o << ')'; } }; @@ -213,7 +213,7 @@ enum HostOp { class Expression { public: - BasicType type; + WasmType type; Expression() : type(type) {} @@ -251,28 +251,25 @@ typedef std::vector<Expression*> ExpressionList; // TODO: optimize class Nop : public Expression { std::ostream& print(std::ostream &o, unsigned indent) override { - printMinorOpening(o, "nop") << ')'; - return o; + return printMinorOpening(o, "nop") << ')'; } }; class Block : public Expression { public: - Name var; + Name name; ExpressionList list; std::ostream& print(std::ostream &o, unsigned indent) override { printOpening(o, "block"); - if (var.is()) { - o << " "; - var.print(o); + if (name.is()) { + o << ' ' << name; } incIndent(o, indent); for (auto expression : list) { printFullLine(o, indent, expression); } - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -286,8 +283,7 @@ public: printFullLine(o, indent, condition); printFullLine(o, indent, ifTrue); if (ifFalse) printFullLine(o, indent, ifFalse); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -299,38 +295,33 @@ public: std::ostream& print(std::ostream &o, unsigned indent) override { printOpening(o, "loop"); if (out.is()) { - o << " "; - out.print(o); + o << ' ' << out; if (in.is()) { - o << " "; - in.print(o); - } + o << ' ' << in; + } } incIndent(o, indent); printFullLine(o, indent, body); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; class Label : public Expression { public: - Name var; + Name name; }; class Break : public Expression { public: - Name var; + Name name; Expression *condition, *value; std::ostream& print(std::ostream &o, unsigned indent) override { - printOpening(o, "break "); - var.print(o); + printOpening(o, "break ") << name; incIndent(o, indent); if (condition) printFullLine(o, indent, condition); if (value) printFullLine(o, indent, value); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -342,19 +333,17 @@ public: bool fallthru; }; - Name var; + Name name; Expression *value; std::vector<Case> cases; Expression *default_; std::ostream& print(std::ostream &o, unsigned indent) override { - printOpening(o, "switch "); - var.print(o); + printOpening(o, "switch ") << name; incIndent(o, indent); printFullLine(o, indent, value); o << "TODO: cases/default\n"; - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -365,7 +354,7 @@ public: ExpressionList operands; std::ostream& printBody(std::ostream &o, unsigned indent) { - target.print(o); + o << target; if (operands.size() > 0) { incIndent(o, indent); for (auto operand : operands) { @@ -394,27 +383,24 @@ class CallImport : public Call { class FunctionType { public: Name name; - BasicType result; - std::vector<BasicType> params; + WasmType result; + std::vector<WasmType> params; std::ostream& print(std::ostream &o, unsigned indent, bool full=false) { if (full) { - printOpening(o, "type") << ' '; - name.print(o) << " (func"; + printOpening(o, "type") << ' ' << name << " (func"; } if (params.size() > 0) { o << ' '; printMinorOpening(o, "param"); for (auto& param : params) { - o << ' '; - printBasicType(o, param); + o << ' ' << printWasmType(param); } o << ')'; } if (result != none) { o << ' '; - printMinorOpening(o, "result "); - printBasicType(o, result) << ')'; + printMinorOpening(o, "result ") << printWasmType(result) << ')'; } if (full) { o << "))";; @@ -443,15 +429,13 @@ public: ExpressionList operands; std::ostream& print(std::ostream &o, unsigned indent) override { - printOpening(o, "call_indirect "); - type->name.print(o); + printOpening(o, "call_indirect ") << type->name; incIndent(o, indent); printFullLine(o, indent, target); for (auto operand : operands) { printFullLine(o, indent, operand); } - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -460,9 +444,7 @@ public: Name id; std::ostream& print(std::ostream &o, unsigned indent) override { - printOpening(o, "get_local "); - id.print(o) << ')'; - return o; + return printOpening(o, "get_local ") << id << ')'; } }; @@ -472,12 +454,10 @@ public: Expression *value; std::ostream& print(std::ostream &o, unsigned indent) override { - printOpening(o, "set_local "); - id.print(o); + printOpening(o, "set_local ") << id; incIndent(o, indent); printFullLine(o, indent, value); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -492,8 +472,7 @@ public: std::ostream& print(std::ostream &o, unsigned indent) override { o << '('; - prepareColor(o); - printBasicType(o, getBasicType(bytes, float_)) << ".load"; + prepareColor(o) << printWasmType(getWasmType(bytes, float_)) << ".load"; if (bytes < 4) { if (bytes == 1) { o << '8'; @@ -509,8 +488,7 @@ public: assert(!offset); incIndent(o, indent); printFullLine(o, indent, ptr); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -524,8 +502,7 @@ public: std::ostream& print(std::ostream &o, unsigned indent) override { o << '('; - prepareColor(o); - printBasicType(o, getBasicType(bytes, float_)) << ".store"; + prepareColor(o) << printWasmType(getWasmType(bytes, float_)) << ".store"; if (bytes < 4) { if (bytes == 1) { o << '8'; @@ -541,8 +518,7 @@ public: incIndent(o, indent); printFullLine(o, indent, ptr); printFullLine(o, indent, value); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -556,8 +532,7 @@ public: } std::ostream& print(std::ostream &o, unsigned indent) override { - value.print(o); - return o; + return o << value; } }; @@ -568,8 +543,7 @@ public: std::ostream& print(std::ostream &o, unsigned indent) override { o << '('; - prepareColor(o); - printBasicType(o, type) << '.'; + prepareColor(o) << printWasmType(type) << '.'; switch (op) { case Clz: o << "clz"; break; case Neg: o << "neg"; break; @@ -578,8 +552,7 @@ public: } incIndent(o, indent); printFullLine(o, indent, value); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -590,8 +563,7 @@ public: std::ostream& print(std::ostream &o, unsigned indent) override { o << '('; - prepareColor(o); - printBasicType(o, type) << '.'; + prepareColor(o) << printWasmType(type) << '.'; switch (op) { case Add: o << "add"; break; case Sub: o << "sub"; break; @@ -616,8 +588,7 @@ public: incIndent(o, indent); printFullLine(o, indent, left); printFullLine(o, indent, right); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -627,13 +598,12 @@ public: Expression *left, *right; Compare() { - type = BasicType::i32; + type = WasmType::i32; } std::ostream& print(std::ostream &o, unsigned indent) override { o << '('; - prepareColor(o); - printBasicType(o, type) << '.'; + prepareColor(o) << printWasmType(type) << '.'; switch (op) { case Eq: o << "eq"; break; case Ne: o << "ne"; break; @@ -655,8 +625,7 @@ public: incIndent(o, indent); printFullLine(o, indent, left); printFullLine(o, indent, right); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -667,8 +636,7 @@ public: std::ostream& print(std::ostream &o, unsigned indent) override { o << '('; - prepareColor(o); - printBasicType(o, type) << ".convert_"; + prepareColor(o) << printWasmType(type) << ".convert_"; switch (op) { case ConvertUInt32: o << "u/i32"; break; case ConvertSInt32: o << "s/i32"; break; @@ -678,8 +646,7 @@ public: restoreNormalColor(o); incIndent(o, indent); printFullLine(o, indent, value); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -693,45 +660,38 @@ public: struct NameType { Name name; - BasicType type; + WasmType type; NameType() : name(nullptr), type(none) {} - NameType(Name name, BasicType type) : name(name), type(type) {} + NameType(Name name, WasmType type) : name(name), type(type) {} }; class Function { public: Name name; - BasicType result; + WasmType result; std::vector<NameType> params; std::vector<NameType> locals; Expression *body; std::ostream& print(std::ostream &o, unsigned indent) { - printOpening(o, "func ", true); - name.print(o); + printOpening(o, "func ", true) << name; if (params.size() > 0) { for (auto& param : params) { o << ' '; - printMinorOpening(o, "param "); - param.name.print(o) << " "; - printBasicType(o, param.type) << ")"; + printMinorOpening(o, "param ") << param.name << ' ' << printWasmType(param.type) << ")"; } } if (result != none) { o << ' '; - printMinorOpening(o, "result "); - printBasicType(o, result) << ")"; + printMinorOpening(o, "result ") << printWasmType(result) << ")"; } incIndent(o, indent); for (auto& local : locals) { doIndent(o, indent); - printMinorOpening(o, "local "); - local.name.print(o) << " "; - printBasicType(o, local.type) << ")\n"; + printMinorOpening(o, "local ") << local.name << ' ' << printWasmType(local.type) << ")\n"; } printFullLine(o, indent, body); - decIndent(o, indent); - return o; + return decIndent(o, indent); } }; @@ -741,13 +701,11 @@ public: FunctionType type; std::ostream& print(std::ostream &o, unsigned indent) { - printOpening(o, "import "); - name.print(o) << ' '; + printOpening(o, "import ") << name << ' '; printText(o, module.str) << ' '; printText(o, base.str) << ' '; type.print(o, indent); - o << ')'; - return o; + return o << ')'; } }; @@ -757,26 +715,21 @@ public: Name value; std::ostream& print(std::ostream &o, unsigned indent) { - printOpening(o, "export") << ' '; - printText(o, name.str) << ' '; - value.print(o); - o << ')'; - return o; + printOpening(o, "export "); + return printText(o, name.str) << ' ' << value << ')'; } }; class Table { public: - std::vector<Name> vars; + std::vector<Name> names; std::ostream& print(std::ostream &o, unsigned indent) { printOpening(o, "table"); - for (auto var : vars) { - o << ' '; - var.print(o); + for (auto name : names) { + o << ' ' << name; } - o << ')'; - return o; + return o << ')'; } }; @@ -789,48 +742,44 @@ protected: Table table; std::vector<Function*> functions; - // internals - std::map<Name, void*> map; // maps var ids/names to things - unsigned nextVar; - public: - Module() : nextVar(1) {} + Module() {} - std::ostream& print(std::ostream &o) { + friend std::ostream& operator<<(std::ostream &o, Module module) { unsigned indent = 0; printOpening(o, "module", true); incIndent(o, indent); doIndent(o, indent); printOpening(o, "memory") << " 16777216)\n"; // XXX - for (auto& curr : functionTypes) { + for (auto& curr : module.functionTypes) { doIndent(o, indent); curr.second->print(o, indent, true); o << '\n'; } #if 0 - for (auto& curr : imports) { + for (auto& curr : module.imports) { doIndent(o, indent); curr.second.print(o, indent); o << '\n'; } #endif - for (auto& curr : exports) { + for (auto& curr : module.exports) { doIndent(o, indent); curr.print(o, indent); o << '\n'; } - if (table.vars.size() > 0) { + if (module.table.names.size() > 0) { doIndent(o, indent); - table.print(o, indent); + module.table.print(o, indent); o << '\n'; } - for (auto& curr : functions) { + for (auto& curr : module.functions) { doIndent(o, indent); curr->print(o, indent); o << '\n'; } decIndent(o, indent); - o << '\n'; + return o << '\n'; } }; |