summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-02-17 12:44:14 -0800
committerAlon Zakai <alonzakai@gmail.com>2016-02-17 14:25:01 -0800
commitdbb5f32bafcf3c8f51eefb95e6c298ce6b9ac8cc (patch)
tree88a9617fb2ad21c329043f1f4efd72a0abbb29dc
parent252962faba97b68684a470447c7202cf27ad8c05 (diff)
downloadbinaryen-dbb5f32bafcf3c8f51eefb95e6c298ce6b9ac8cc.tar.gz
binaryen-dbb5f32bafcf3c8f51eefb95e6c298ce6b9ac8cc.tar.bz2
binaryen-dbb5f32bafcf3c8f51eefb95e6c298ce6b9ac8cc.zip
move printing to a pass
-rw-r--r--CMakeLists.txt6
-rw-r--r--src/asm2wasm-main.cpp2
-rw-r--r--src/binaryen-shell.cpp6
-rw-r--r--src/pass.cpp11
-rw-r--r--src/pass.h34
-rw-r--r--src/passes/Print.cpp482
-rw-r--r--src/s2wasm-main.cpp3
-rw-r--r--src/s2wasm.h3
-rw-r--r--src/support/file.h4
-rw-r--r--src/wasm-dis.cpp4
-rw-r--r--src/wasm.h511
11 files changed, 536 insertions, 530 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c7f4858c6..e3ec72c6e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -80,6 +80,7 @@ SET(binaryen-shell_SOURCES
src/passes/MergeBlocks.cpp
src/passes/NameManager.cpp
src/passes/PostEmscripten.cpp
+ src/passes/Print.cpp
src/passes/RemoveImports.cpp
src/passes/RemoveUnusedBrs.cpp
src/passes/RemoveUnusedNames.cpp
@@ -98,6 +99,7 @@ SET(asm2wasm_SOURCES
src/pass.cpp
src/passes/MergeBlocks.cpp
src/passes/PostEmscripten.cpp
+ src/passes/Print.cpp
src/passes/RemoveUnusedBrs.cpp
src/passes/RemoveUnusedNames.cpp
src/passes/SimplifyLocals.cpp
@@ -126,6 +128,8 @@ SET_PROPERTY(TARGET wasm2asm PROPERTY CXX_STANDARD_REQUIRED ON)
INSTALL(TARGETS wasm2asm DESTINATION bin)
SET(s2wasm_SOURCES
+ src/pass.cpp
+ src/passes/Print.cpp
src/s2wasm-main.cpp
)
ADD_EXECUTABLE(s2wasm
@@ -146,6 +150,8 @@ SET_PROPERTY(TARGET wasm-as PROPERTY CXX_STANDARD_REQUIRED ON)
INSTALL(TARGETS wasm-as DESTINATION bin)
SET(wasm_dis_SOURCES
+ src/pass.cpp
+ src/passes/Print.cpp
src/wasm-dis.cpp
)
ADD_EXECUTABLE(wasm-dis
diff --git a/src/asm2wasm-main.cpp b/src/asm2wasm-main.cpp
index 1fd1273c0..3c1377c08 100644
--- a/src/asm2wasm-main.cpp
+++ b/src/asm2wasm-main.cpp
@@ -76,7 +76,7 @@ int main(int argc, const char *argv[]) {
if (options.debug) std::cerr << "printing..." << std::endl;
Output output(options.extra["output"], options.debug);
- output << wasm;
+ printWasm(&wasm, output.getStream());
if (mappedGlobals) {
if (options.debug)
diff --git a/src/binaryen-shell.cpp b/src/binaryen-shell.cpp
index d450e4db7..1b0bf8f78 100644
--- a/src/binaryen-shell.cpp
+++ b/src/binaryen-shell.cpp
@@ -281,7 +281,7 @@ static void run_asserts(size_t* i, bool* checked, AllocatingModule* wasm,
Colors::bold(std::cout);
std::cerr << "printing in module invalidity test:\n";
Colors::normal(std::cout);
- std::cout << wasm;
+ printWasm(&wasm, std::cout);
}
bool invalid = false;
std::unique_ptr<SExpressionWasmBuilder> builder;
@@ -411,7 +411,7 @@ int main(int argc, const char* argv[]) {
Colors::bold(std::cout);
std::cerr << "printing before:\n";
Colors::normal(std::cout);
- std::cout << wasm;
+ printWasm(&wasm, std::cout);
}
MixedArena moreModuleAllocations;
@@ -429,7 +429,7 @@ int main(int argc, const char* argv[]) {
Colors::bold(std::cout);
std::cerr << "printing after:\n";
Colors::normal(std::cout);
- std::cout << wasm;
+ printWasm(&wasm, std::cout);
}
run_asserts(&i, &checked, &wasm, &root, &builder, print_before,
print_after, entry);
diff --git a/src/pass.cpp b/src/pass.cpp
index 1d3c2d67d..432979413 100644
--- a/src/pass.cpp
+++ b/src/pass.cpp
@@ -53,17 +53,6 @@ std::string PassRegistry::getPassDescription(std::string name) {
// PassRunner
-void PassRunner::add(std::string passName) {
- auto pass = PassRegistry::get()->createPass(passName);
- assert(pass);
- passes.push_back(pass);
-}
-
-template<class P>
-void PassRunner::add() {
- passes.push_back(new P());
-}
-
void PassRunner::run(Module* module) {
for (auto pass : passes) {
currPass = pass;
diff --git a/src/pass.h b/src/pass.h
index a95be9850..250ba59b2 100644
--- a/src/pass.h
+++ b/src/pass.h
@@ -71,10 +71,21 @@ struct PassRunner {
PassRunner(MixedArena* allocator) : allocator(allocator) {}
- void add(std::string passName);
+ void add(std::string passName) {
+ auto pass = PassRegistry::get()->createPass(passName);
+ assert(pass);
+ passes.push_back(pass);
+ }
template<class P>
- void add();
+ void add() {
+ passes.push_back(new P());
+ }
+
+ template<class P, class Arg>
+ void add(Arg& arg){
+ passes.push_back(new P(arg));
+ }
void run(Module* module);
@@ -143,6 +154,25 @@ private:
size_t counter = 0;
};
+// Prints out a module
+class Printer : public Pass {
+ std::ostream& o;
+
+public:
+ Printer() : o(std::cout) {}
+ Printer(std::ostream& o) : o(o) {}
+
+ void run(PassRunner* runner, Module* module) override;
+};
+
+// Standard pass utilities
+
+inline void printWasm(Module* module, std::ostream& o) {
+ PassRunner passRunner(nullptr);
+ passRunner.add<Printer>(o);
+ passRunner.run(module);
+}
+
} // namespace wasm
#endif // wasm_pass_h
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
new file mode 100644
index 000000000..14cb929c5
--- /dev/null
+++ b/src/passes/Print.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2015 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.
+ */
+
+//
+// Print out text in s-expression format
+//
+
+#include <wasm.h>
+#include <pass.h>
+
+namespace wasm {
+
+struct PrintSExpression : public WasmVisitor<PrintSExpression, void> {
+ std::ostream& o;
+ unsigned indent;
+
+ PrintSExpression(std::ostream& o) : o(o), indent(0) {}
+
+ void printFullLine(Expression *expression) {
+ doIndent(o, indent);
+ visit(expression);
+ o << '\n';
+ }
+
+ void visitBlock(Block *curr) {
+ printOpening(o, "block");
+ if (curr->name.is()) {
+ o << ' ' << curr->name;
+ }
+ incIndent(o, indent);
+ for (auto expression : curr->list) {
+ printFullLine(expression);
+ }
+ decIndent(o, indent);
+ }
+ void visitIf(If *curr) {
+ printOpening(o, curr->ifFalse ? "if_else" : "if");
+ incIndent(o, indent);
+ printFullLine(curr->condition);
+ printFullLine(curr->ifTrue);
+ if (curr->ifFalse) printFullLine(curr->ifFalse);
+ decIndent(o, indent);
+ }
+ void visitLoop(Loop *curr) {
+ printOpening(o, "loop");
+ if (curr->out.is()) {
+ o << ' ' << curr->out;
+ assert(curr->in.is()); // if just one is printed, it must be the in
+ }
+ if (curr->in.is()) {
+ o << ' ' << curr->in;
+ }
+ incIndent(o, indent);
+ auto block = curr->body->dyn_cast<Block>();
+ if (block && block->name.isNull()) {
+ // wasm spec has loops containing children directly, while our ast
+ // has a single child for simplicity. print out the optimal form.
+ for (auto expression : block->list) {
+ printFullLine(expression);
+ }
+ } else {
+ printFullLine(curr->body);
+ }
+ decIndent(o, indent);
+ }
+ void visitBreak(Break *curr) {
+ if (curr->condition) {
+ printOpening(o, "br_if ") << curr->name;
+ incIndent(o, indent);
+ } else {
+ printOpening(o, "br ") << curr->name;
+ if (!curr->value || curr->value->is<Nop>()) {
+ // avoid a new line just for the parens
+ o << ")";
+ return;
+ }
+ incIndent(o, indent);
+ }
+ if (curr->value && !curr->value->is<Nop>()) printFullLine(curr->value);
+ if (curr->condition) {
+ printFullLine(curr->condition);
+ }
+ decIndent(o, indent);
+ }
+ void visitSwitch(Switch *curr) {
+ printOpening(o, "tableswitch ");
+ if (curr->name.is()) o << curr->name;
+ incIndent(o, indent);
+ printFullLine(curr->value);
+ doIndent(o, indent) << "(table";
+ std::set<Name> caseNames;
+ for (auto& c : curr->cases) {
+ caseNames.insert(c.name);
+ }
+ for (auto& t : curr->targets) {
+ o << " (" << (caseNames.count(t) == 0 ? "br" : "case") << " " << (t.is() ? t : curr->default_) << ")";
+ }
+ o << ")";
+ if (curr->default_.is()) o << " (" << (caseNames.count(curr->default_) == 0 ? "br" : "case") << " " << curr->default_ << ")";
+ o << "\n";
+ for (auto& c : curr->cases) {
+ doIndent(o, indent);
+ printMinorOpening(o, "case ") << c.name;
+ incIndent(o, indent);
+ printFullLine(c.body);
+ decIndent(o, indent) << '\n';
+ }
+ decIndent(o, indent);
+ }
+
+ void printCallBody(Call* curr) {
+ o << curr->target;
+ if (curr->operands.size() > 0) {
+ incIndent(o, indent);
+ for (auto operand : curr->operands) {
+ printFullLine(operand);
+ }
+ decIndent(o, indent);
+ } else {
+ o << ')';
+ }
+ }
+
+ void visitCall(Call *curr) {
+ printOpening(o, "call ");
+ printCallBody(curr);
+ }
+ void visitCallImport(CallImport *curr) {
+ printOpening(o, "call_import ");
+ printCallBody(curr);
+ }
+ void visitCallIndirect(CallIndirect *curr) {
+ printOpening(o, "call_indirect ") << curr->fullType->name;
+ incIndent(o, indent);
+ printFullLine(curr->target);
+ for (auto operand : curr->operands) {
+ printFullLine(operand);
+ }
+ decIndent(o, indent);
+ }
+ void visitGetLocal(GetLocal *curr) {
+ printOpening(o, "get_local ") << curr->name << ')';
+ }
+ void visitSetLocal(SetLocal *curr) {
+ printOpening(o, "set_local ") << curr->name;
+ incIndent(o, indent);
+ printFullLine(curr->value);
+ decIndent(o, indent);
+ }
+ void visitLoad(Load *curr) {
+ o << '(';
+ prepareColor(o) << printWasmType(curr->type) << ".load";
+ if (curr->bytes < 4 || (curr->type == i64 && curr->bytes < 8)) {
+ if (curr->bytes == 1) {
+ o << '8';
+ } else if (curr->bytes == 2) {
+ o << "16";
+ } else if (curr->bytes == 4) {
+ o << "32";
+ } else {
+ abort();
+ }
+ o << (curr->signed_ ? "_s" : "_u");
+ }
+ restoreNormalColor(o);
+ if (curr->offset) {
+ o << " offset=" << curr->offset;
+ }
+ if (curr->align) {
+ o << " align=" << curr->align;
+ }
+ incIndent(o, indent);
+ printFullLine(curr->ptr);
+ decIndent(o, indent);
+ }
+ void visitStore(Store *curr) {
+ o << '(';
+ prepareColor(o) << printWasmType(curr->type) << ".store";
+ if (curr->bytes < 4 || (curr->type == i64 && curr->bytes < 8)) {
+ if (curr->bytes == 1) {
+ o << '8';
+ } else if (curr->bytes == 2) {
+ o << "16";
+ } else if (curr->bytes == 4) {
+ o << "32";
+ } else {
+ abort();
+ }
+ }
+ restoreNormalColor(o);
+ if (curr->offset) {
+ o << " offset=" << curr->offset;
+ }
+ if (curr->align) {
+ o << " align=" << curr->align;
+ }
+ incIndent(o, indent);
+ printFullLine(curr->ptr);
+ printFullLine(curr->value);
+ decIndent(o, indent);
+ }
+ void visitConst(Const *curr) {
+ o << curr->value;
+ }
+ void visitUnary(Unary *curr) {
+ o << '(';
+ prepareColor(o) << printWasmType(curr->type) << '.';
+ switch (curr->op) {
+ case Clz: o << "clz"; break;
+ case Ctz: o << "ctz"; break;
+ case Popcnt: o << "popcnt"; break;
+ case Neg: o << "neg"; break;
+ case Abs: o << "abs"; break;
+ case Ceil: o << "ceil"; break;
+ case Floor: o << "floor"; break;
+ case Trunc: o << "trunc"; break;
+ case Nearest: o << "nearest"; break;
+ case Sqrt: o << "sqrt"; break;
+ case ExtendSInt32: o << "extend_s/i32"; break;
+ case ExtendUInt32: o << "extend_u/i32"; break;
+ case WrapInt64: o << "wrap/i64"; break;
+ case TruncSFloat32: o << "trunc_s/f32"; break;
+ case TruncUFloat32: o << "trunc_u/f32"; break;
+ case TruncSFloat64: o << "trunc_s/f64"; break;
+ case TruncUFloat64: o << "trunc_u/f64"; break;
+ case ReinterpretFloat: o << "reinterpret/" << (curr->type == i64 ? "f64" : "f32"); break;
+ case ConvertUInt32: o << "convert_u/i32"; break;
+ case ConvertSInt32: o << "convert_s/i32"; break;
+ case ConvertUInt64: o << "convert_u/i64"; break;
+ case ConvertSInt64: o << "convert_s/i64"; break;
+ case PromoteFloat32: o << "promote/f32"; break;
+ case DemoteFloat64: o << "demote/f64"; break;
+ case ReinterpretInt: o << "reinterpret/" << (curr->type == f64 ? "i64" : "i32"); break;
+ default: abort();
+ }
+ incIndent(o, indent);
+ printFullLine(curr->value);
+ decIndent(o, indent);
+ }
+ void visitBinary(Binary *curr) {
+ o << '(';
+ prepareColor(o) << printWasmType(curr->isRelational() ? curr->left->type : curr->type) << '.';
+ switch (curr->op) {
+ case Add: o << "add"; break;
+ case Sub: o << "sub"; break;
+ case Mul: o << "mul"; break;
+ case DivS: o << "div_s"; break;
+ case DivU: o << "div_u"; break;
+ case RemS: o << "rem_s"; break;
+ case RemU: o << "rem_u"; break;
+ case And: o << "and"; break;
+ case Or: o << "or"; break;
+ case Xor: o << "xor"; break;
+ case Shl: o << "shl"; break;
+ case ShrU: o << "shr_u"; break;
+ case ShrS: o << "shr_s"; break;
+ case Div: o << "div"; break;
+ case CopySign: o << "copysign"; break;
+ case Min: o << "min"; break;
+ case Max: o << "max"; break;
+ case Eq: o << "eq"; break;
+ case Ne: o << "ne"; break;
+ case LtS: o << "lt_s"; break;
+ case LtU: o << "lt_u"; break;
+ case LeS: o << "le_s"; break;
+ case LeU: o << "le_u"; break;
+ case GtS: o << "gt_s"; break;
+ case GtU: o << "gt_u"; break;
+ case GeS: o << "ge_s"; break;
+ case GeU: o << "ge_u"; break;
+ case Lt: o << "lt"; break;
+ case Le: o << "le"; break;
+ case Gt: o << "gt"; break;
+ case Ge: o << "ge"; break;
+ default: abort();
+ }
+ restoreNormalColor(o);
+ incIndent(o, indent);
+ printFullLine(curr->left);
+ printFullLine(curr->right);
+ decIndent(o, indent);
+ }
+ void visitSelect(Select *curr) {
+ o << '(';
+ prepareColor(o) << printWasmType(curr->type) << ".select";
+ incIndent(o, indent);
+ printFullLine(curr->ifTrue);
+ printFullLine(curr->ifFalse);
+ printFullLine(curr->condition);
+ decIndent(o, indent);
+ }
+ void visitReturn(Return *curr) {
+ printOpening(o, "return");
+ if (!curr->value || curr->value->is<Nop>()) {
+ // avoid a new line just for the parens
+ o << ")";
+ return;
+ }
+ incIndent(o, indent);
+ printFullLine(curr->value);
+ decIndent(o, indent);
+ }
+ void visitHost(Host *curr) {
+ switch (curr->op) {
+ case PageSize: printOpening(o, "pagesize") << ')'; break;
+ case MemorySize: printOpening(o, "memory_size") << ')'; break;
+ case GrowMemory: {
+ printOpening(o, "grow_memory");
+ incIndent(o, indent);
+ printFullLine(curr->operands[0]);
+ decIndent(o, indent);
+ break;
+ }
+ case HasFeature: printOpening(o, "hasfeature ") << curr->nameOperand << ')'; break;
+ default: abort();
+ }
+ }
+ void visitNop(Nop *curr) {
+ printMinorOpening(o, "nop") << ')';
+ }
+ void visitUnreachable(Unreachable *curr) {
+ printMinorOpening(o, "unreachable") << ')';
+ }
+ // Module-level visitors
+ void visitFunctionType(FunctionType *curr, bool full=false) {
+ if (full) {
+ printOpening(o, "type") << ' ' << curr->name << " (func";
+ }
+ if (curr->params.size() > 0) {
+ o << ' ';
+ printMinorOpening(o, "param");
+ for (auto& param : curr->params) {
+ o << ' ' << printWasmType(param);
+ }
+ o << ')';
+ }
+ if (curr->result != none) {
+ o << ' ';
+ printMinorOpening(o, "result ") << printWasmType(curr->result) << ')';
+ }
+ if (full) {
+ o << "))";;
+ }
+ }
+ void visitImport(Import *curr) {
+ printOpening(o, "import ") << curr->name << ' ';
+ printText(o, curr->module.str) << ' ';
+ printText(o, curr->base.str);
+ if (curr->type) visitFunctionType(curr->type);
+ o << ')';
+ }
+ void visitExport(Export *curr) {
+ printOpening(o, "export ");
+ printText(o, curr->name.str) << ' ' << curr->value << ')';
+ }
+ void visitFunction(Function *curr) {
+ printOpening(o, "func ", true) << curr->name;
+ if (curr->type.is()) {
+ o << " (type " << curr->type << ')';
+ }
+ if (curr->params.size() > 0) {
+ for (auto& param : curr->params) {
+ o << ' ';
+ printMinorOpening(o, "param ") << param.name << ' ' << printWasmType(param.type) << ")";
+ }
+ }
+ if (curr->result != none) {
+ o << ' ';
+ printMinorOpening(o, "result ") << printWasmType(curr->result) << ")";
+ }
+ incIndent(o, indent);
+ for (auto& local : curr->locals) {
+ doIndent(o, indent);
+ printMinorOpening(o, "local ") << local.name << ' ' << printWasmType(local.type) << ")\n";
+ }
+ // It is ok to emit a block here, as a function can directly contain a list, even if our
+ // ast avoids that for simplicity. We can just do that optimization here..
+ if (curr->body->is<Block>() && curr->body->cast<Block>()->name.isNull()) {
+ Block* block = curr->body->cast<Block>();
+ for (auto item : block->list) {
+ printFullLine(item);
+ }
+ } else {
+ printFullLine(curr->body);
+ }
+ decIndent(o, indent);
+ }
+ void visitTable(Table *curr) {
+ printOpening(o, "table");
+ for (auto name : curr->names) {
+ o << ' ' << name;
+ }
+ o << ')';
+ }
+ void visitModule(Module *curr) {
+ printOpening(o, "module", true);
+ incIndent(o, indent);
+ doIndent(o, indent);
+ printOpening(o, "memory") << " " << curr->memory.initial;
+ if (curr->memory.max && curr->memory.max != (uint32_t)-1) o << " " << curr->memory.max;
+ for (auto segment : curr->memory.segments) {
+ o << "\n (segment " << segment.offset << " \"";
+ for (size_t i = 0; i < segment.size; i++) {
+ unsigned char c = segment.data[i];
+ switch (c) {
+ case '\n': o << "\\n"; break;
+ case '\r': o << "\\0d"; break;
+ case '\t': o << "\\t"; break;
+ case '\f': o << "\\0c"; break;
+ case '\b': o << "\\08"; break;
+ case '\\': o << "\\\\"; break;
+ case '"' : o << "\\\""; break;
+ case '\'' : o << "\\'"; break;
+ default: {
+ if (c >= 32 && c < 127) {
+ o << c;
+ } else {
+ o << std::hex << '\\' << (c/16) << (c%16) << std::dec;
+ }
+ }
+ }
+ }
+ o << "\")";
+ }
+ o << (curr->memory.segments.size() > 0 ? "\n " : "") << ")\n";
+ if (curr->start.is()) {
+ doIndent(o, indent);
+ printOpening(o, "start") << " " << curr->start << ")\n";
+ }
+ for (auto& child : curr->functionTypes) {
+ doIndent(o, indent);
+ visitFunctionType(child, true);
+ o << '\n';
+ }
+ for (auto& child : curr->imports) {
+ doIndent(o, indent);
+ visitImport(child);
+ o << '\n';
+ }
+ for (auto& child : curr->exports) {
+ doIndent(o, indent);
+ visitExport(child);
+ o << '\n';
+ }
+ if (curr->table.names.size() > 0) {
+ doIndent(o, indent);
+ visitTable(&curr->table);
+ o << '\n';
+ }
+ for (auto& child : curr->functions) {
+ doIndent(o, indent);
+ visitFunction(child);
+ o << '\n';
+ }
+ decIndent(o, indent);
+ o << '\n';
+ }
+};
+
+// Main entry point. Eventually this will direct printing to one of various options.
+
+void Printer::run(PassRunner* runner, Module* module) {
+ PrintSExpression print(o);
+ print.visitModule(module);
+}
+
+static RegisterPass<Printer> registerPass("print", "print in s-expression format");
+
+} // namespace wasm
diff --git a/src/s2wasm-main.cpp b/src/s2wasm-main.cpp
index 03321a608..377d44c52 100644
--- a/src/s2wasm-main.cpp
+++ b/src/s2wasm-main.cpp
@@ -84,7 +84,8 @@ int main(int argc, const char *argv[]) {
if (options.debug) std::cerr << "Printing..." << std::endl;
Output output(options.extra["output"], options.debug);
- output << wasm << meta.str() << std::endl;
+ printWasm(&wasm, output.getStream());
+ output << meta.str() << std::endl;
if (options.debug) std::cerr << "Done." << std::endl;
}
diff --git a/src/s2wasm.h b/src/s2wasm.h
index 5557cc2ff..9c875ea9e 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -25,6 +25,7 @@
#include "wasm.h"
#include "parsing.h"
+#include "pass.h"
#include "asm_v_wasm.h"
namespace wasm {
@@ -1262,7 +1263,7 @@ public:
// extra emscripten processing
void emscriptenGlue(std::ostream& o) {
if (debug) {
- std::cerr << wasm << '\n';
+ printWasm(&wasm, std::cerr);
}
wasm.removeImport(EMSCRIPTEN_ASM_CONST); // we create _sig versions
diff --git a/src/support/file.h b/src/support/file.h
index 5e464d6c1..47f7ececb 100644
--- a/src/support/file.h
+++ b/src/support/file.h
@@ -44,6 +44,10 @@ class Output {
return out << v;
}
+ std::ostream& getStream() {
+ return out;
+ }
+
private:
Output() = delete;
Output(const Output &) = delete;
diff --git a/src/wasm-dis.cpp b/src/wasm-dis.cpp
index 7fb3ed2d5..c7ebf8861 100644
--- a/src/wasm-dis.cpp
+++ b/src/wasm-dis.cpp
@@ -18,6 +18,7 @@
// wasm2asm console tool
//
+#include "pass.h"
#include "support/colors.h"
#include "support/command-line.h"
#include "support/file.h"
@@ -49,7 +50,8 @@ int main(int argc, const char *argv[]) {
if (options.debug) std::cerr << "Printing..." << std::endl;
Output output(options.extra["output"], options.debug);
- output << wasm << std::endl;
+ printWasm(&wasm, output.getStream());
+ output << '\n';
if (options.debug) std::cerr << "Done." << std::endl;
}
diff --git a/src/wasm.h b/src/wasm.h
index 516ea9630..387b39c02 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -22,12 +22,11 @@
// it easy to not just inspect but also to process. For example, some
// things that this enables are:
//
-// * Pretty-printing: Implemented in this file (printing can help
-// understand the data structures here).
// * Interpreting: See wasm-interpreter.h.
// * Optimizing: See asm2wasm.h, which performs some optimizations
// after code generation.
// * Validation: See wasm-validator.h.
+// * Pretty-printing: See Print.cpp.
//
//
@@ -756,18 +755,6 @@ public:
assert(_id == T()._id);
return (T*)this;
}
-
- inline std::ostream& print(std::ostream &o, unsigned indent); // avoid virtual here, for performance
-
- friend std::ostream& operator<<(std::ostream &o, Expression* expression) {
- return expression->print(o, 0);
- }
-
- static std::ostream& printFullLine(std::ostream &o, unsigned indent, Expression *expression) {
- doIndent(o, indent);
- expression->print(o, indent);
- return o << '\n';
- }
};
inline const char *getExpressionName(Expression *curr) {
@@ -801,10 +788,6 @@ typedef std::vector<Expression*> ExpressionList; // TODO: optimize?
class Nop : public Expression {
public:
Nop() : Expression(NopId) {}
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- return printMinorOpening(o, "nop") << ')';
- }
};
class Block : public Expression {
@@ -815,18 +798,6 @@ public:
Name name;
ExpressionList list;
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- printOpening(o, "block");
- if (name.is()) {
- o << ' ' << name;
- }
- incIndent(o, indent);
- for (auto expression : list) {
- printFullLine(o, indent, expression);
- }
- return decIndent(o, indent);
- }
};
class If : public Expression {
@@ -837,15 +808,6 @@ public:
Expression *condition, *ifTrue, *ifFalse;
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- printOpening(o, ifFalse ? "if_else" : "if");
- incIndent(o, indent);
- printFullLine(o, indent, condition);
- printFullLine(o, indent, ifTrue);
- if (ifFalse) printFullLine(o, indent, ifFalse);
- return decIndent(o, indent);
- }
-
void finalize() {
if (condition) {
type = getReachableWasmType(ifTrue->type, ifFalse->type);
@@ -860,29 +822,6 @@ public:
Name out, in;
Expression *body;
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- printOpening(o, "loop");
- if (out.is()) {
- o << ' ' << out;
- assert(in.is()); // if just one is printed, it must be the in
- }
- if (in.is()) {
- o << ' ' << in;
- }
- incIndent(o, indent);
- auto block = body->dyn_cast<Block>();
- if (block && block->name.isNull()) {
- // wasm spec has loops containing children directly, while our ast
- // has a single child for simplicity. print out the optimal form.
- for (auto expression : block->list) {
- printFullLine(o, indent, expression);
- }
- } else {
- printFullLine(o, indent, body);
- }
- return decIndent(o, indent);
- }
-
void finalize() {
type = body->type; // loop might have a type, if the body ends in something that does not break
}
@@ -897,26 +836,6 @@ public:
Name name;
Expression *value;
Expression *condition;
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- if (condition) {
- printOpening(o, "br_if ") << name;
- incIndent(o, indent);
- } else {
- printOpening(o, "br ") << name;
- if (!value || value->is<Nop>()) {
- // avoid a new line just for the parens
- o << ")";
- return o;
- }
- incIndent(o, indent);
- }
- if (value && !value->is<Nop>()) printFullLine(o, indent, value);
- if (condition) {
- printFullLine(o, indent, condition);
- }
- return decIndent(o, indent);
- }
};
class Switch : public Expression {
@@ -935,33 +854,6 @@ public:
std::vector<Name> targets;
Name default_;
std::vector<Case> cases;
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- printOpening(o, "tableswitch ");
- if (name.is()) o << name;
- incIndent(o, indent);
- printFullLine(o, indent, value);
- doIndent(o, indent) << "(table";
- std::set<Name> caseNames;
- for (auto& c : cases) {
- caseNames.insert(c.name);
- }
- for (auto& t : targets) {
- o << " (" << (caseNames.count(t) == 0 ? "br" : "case") << " " << (t.is() ? t : default_) << ")";
- }
- o << ")";
- if (default_.is()) o << " (" << (caseNames.count(default_) == 0 ? "br" : "case") << " " << default_ << ")";
- o << "\n";
- for (auto& c : cases) {
- doIndent(o, indent);
- printMinorOpening(o, "case ") << c.name;
- incIndent(o, indent);
- printFullLine(o, indent, c.body);
- decIndent(o, indent) << '\n';
- }
- return decIndent(o, indent);
- }
-
};
class CallBase : public Expression {
@@ -976,25 +868,6 @@ public:
Call() : CallBase(CallId) {}
Name target;
-
- std::ostream& printBody(std::ostream &o, unsigned indent) {
- o << target;
- if (operands.size() > 0) {
- incIndent(o, indent);
- for (auto operand : operands) {
- printFullLine(o, indent, operand);
- }
- decIndent(o, indent);
- } else {
- o << ')';
- }
- return o;
- }
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- printOpening(o, "call ");
- return printBody(o, indent);
- }
};
class CallImport : public Call {
@@ -1002,11 +875,6 @@ public:
CallImport() {
_id = CallImportId;
}
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- printOpening(o, "call_import ");
- return printBody(o, indent);
- }
};
class FunctionType {
@@ -1017,28 +885,6 @@ public:
FunctionType() : result(none) {}
- std::ostream& print(std::ostream &o, unsigned indent, bool full=false) {
- if (full) {
- printOpening(o, "type") << ' ' << name << " (func";
- }
- if (params.size() > 0) {
- o << ' ';
- printMinorOpening(o, "param");
- for (auto& param : params) {
- o << ' ' << printWasmType(param);
- }
- o << ')';
- }
- if (result != none) {
- o << ' ';
- printMinorOpening(o, "result ") << printWasmType(result) << ')';
- }
- if (full) {
- o << "))";;
- }
- return o;
- }
-
bool operator==(FunctionType& b) {
if (name != b.name) return false; // XXX
if (result != b.result) return false;
@@ -1059,16 +905,6 @@ public:
FunctionType *fullType;
Expression *target;
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- printOpening(o, "call_indirect ") << fullType->name;
- incIndent(o, indent);
- printFullLine(o, indent, target);
- for (auto operand : operands) {
- printFullLine(o, indent, operand);
- }
- return decIndent(o, indent);
- }
};
class GetLocal : public Expression {
@@ -1076,10 +912,6 @@ public:
GetLocal() : Expression(GetLocalId) {}
Name name;
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- return printOpening(o, "get_local ") << name << ')';
- }
};
class SetLocal : public Expression {
@@ -1088,13 +920,6 @@ public:
Name name;
Expression *value;
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- printOpening(o, "set_local ") << name;
- incIndent(o, indent);
- printFullLine(o, indent, value);
- return decIndent(o, indent);
- }
};
class Load : public Expression {
@@ -1106,33 +931,6 @@ public:
uint32_t offset;
uint32_t align;
Expression *ptr;
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- o << '(';
- prepareColor(o) << printWasmType(type) << ".load";
- if (bytes < 4 || (type == i64 && bytes < 8)) {
- if (bytes == 1) {
- o << '8';
- } else if (bytes == 2) {
- o << "16";
- } else if (bytes == 4) {
- o << "32";
- } else {
- abort();
- }
- o << (signed_ ? "_s" : "_u");
- }
- restoreNormalColor(o);
- if (offset) {
- o << " offset=" << offset;
- }
- if (align) {
- o << " align=" << align;
- }
- incIndent(o, indent);
- printFullLine(o, indent, ptr);
- return decIndent(o, indent);
- }
};
class Store : public Expression {
@@ -1143,33 +941,6 @@ public:
uint32_t offset;
unsigned align;
Expression *ptr, *value;
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- o << '(';
- prepareColor(o) << printWasmType(type) << ".store";
- if (bytes < 4 || (type == i64 && bytes < 8)) {
- if (bytes == 1) {
- o << '8';
- } else if (bytes == 2) {
- o << "16";
- } else if (bytes == 4) {
- o << "32";
- } else {
- abort();
- }
- }
- restoreNormalColor(o);
- if (offset) {
- o << " offset=" << offset;
- }
- if (align) {
- o << " align=" << align;
- }
- incIndent(o, indent);
- printFullLine(o, indent, ptr);
- printFullLine(o, indent, value);
- return decIndent(o, indent);
- }
};
class Const : public Expression {
@@ -1183,10 +954,6 @@ public:
type = value.type;
return this;
}
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- return o << value;
- }
};
class Unary : public Expression {
@@ -1195,42 +962,6 @@ public:
UnaryOp op;
Expression *value;
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- o << '(';
- prepareColor(o) << printWasmType(type) << '.';
- switch (op) {
- case Clz: o << "clz"; break;
- case Ctz: o << "ctz"; break;
- case Popcnt: o << "popcnt"; break;
- case Neg: o << "neg"; break;
- case Abs: o << "abs"; break;
- case Ceil: o << "ceil"; break;
- case Floor: o << "floor"; break;
- case Trunc: o << "trunc"; break;
- case Nearest: o << "nearest"; break;
- case Sqrt: o << "sqrt"; break;
- case ExtendSInt32: o << "extend_s/i32"; break;
- case ExtendUInt32: o << "extend_u/i32"; break;
- case WrapInt64: o << "wrap/i64"; break;
- case TruncSFloat32: o << "trunc_s/f32"; break;
- case TruncUFloat32: o << "trunc_u/f32"; break;
- case TruncSFloat64: o << "trunc_s/f64"; break;
- case TruncUFloat64: o << "trunc_u/f64"; break;
- case ReinterpretFloat: o << "reinterpret/" << (type == i64 ? "f64" : "f32"); break;
- case ConvertUInt32: o << "convert_u/i32"; break;
- case ConvertSInt32: o << "convert_s/i32"; break;
- case ConvertUInt64: o << "convert_u/i64"; break;
- case ConvertSInt64: o << "convert_s/i64"; break;
- case PromoteFloat32: o << "promote/f32"; break;
- case DemoteFloat64: o << "demote/f64"; break;
- case ReinterpretInt: o << "reinterpret/" << (type == f64 ? "i64" : "i32"); break;
- default: abort();
- }
- incIndent(o, indent);
- printFullLine(o, indent, value);
- return decIndent(o, indent);
- }
};
class Binary : public Expression {
@@ -1240,50 +971,6 @@ public:
BinaryOp op;
Expression *left, *right;
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- o << '(';
- prepareColor(o) << printWasmType(isRelational() ? left->type : type) << '.';
- switch (op) {
- case Add: o << "add"; break;
- case Sub: o << "sub"; break;
- case Mul: o << "mul"; break;
- case DivS: o << "div_s"; break;
- case DivU: o << "div_u"; break;
- case RemS: o << "rem_s"; break;
- case RemU: o << "rem_u"; break;
- case And: o << "and"; break;
- case Or: o << "or"; break;
- case Xor: o << "xor"; break;
- case Shl: o << "shl"; break;
- case ShrU: o << "shr_u"; break;
- case ShrS: o << "shr_s"; break;
- case Div: o << "div"; break;
- case CopySign: o << "copysign"; break;
- case Min: o << "min"; break;
- case Max: o << "max"; break;
- case Eq: o << "eq"; break;
- case Ne: o << "ne"; break;
- case LtS: o << "lt_s"; break;
- case LtU: o << "lt_u"; break;
- case LeS: o << "le_s"; break;
- case LeU: o << "le_u"; break;
- case GtS: o << "gt_s"; break;
- case GtU: o << "gt_u"; break;
- case GeS: o << "ge_s"; break;
- case GeU: o << "ge_u"; break;
- case Lt: o << "lt"; break;
- case Le: o << "le"; break;
- case Gt: o << "gt"; break;
- case Ge: o << "ge"; break;
- default: abort();
- }
- restoreNormalColor(o);
- incIndent(o, indent);
- printFullLine(o, indent, left);
- printFullLine(o, indent, right);
- return decIndent(o, indent);
- }
-
// the type is always the type of the operands,
// except for relationals
@@ -1305,16 +992,6 @@ public:
Expression *ifTrue, *ifFalse, *condition;
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- o << '(';
- prepareColor(o) << printWasmType(type) << ".select";
- incIndent(o, indent);
- printFullLine(o, indent, ifTrue);
- printFullLine(o, indent, ifFalse);
- printFullLine(o, indent, condition);
- return decIndent(o, indent);
- }
-
void finalize() {
type = getReachableWasmType(ifTrue->type, ifFalse->type);
}
@@ -1327,18 +1004,6 @@ public:
Return() : Expression(ReturnId), value(nullptr) {
type = unreachable;
}
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- printOpening(o, "return");
- if (!value || value->is<Nop>()) {
- // avoid a new line just for the parens
- o << ")";
- return o;
- }
- incIndent(o, indent);
- printFullLine(o, indent, value);
- return decIndent(o, indent);
- }
};
class Host : public Expression {
@@ -1349,23 +1014,6 @@ public:
Name nameOperand;
ExpressionList operands;
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- switch (op) {
- case PageSize: printOpening(o, "pagesize") << ')'; break;
- case MemorySize: printOpening(o, "memory_size") << ')'; break;
- case GrowMemory: {
- printOpening(o, "grow_memory");
- incIndent(o, indent);
- printFullLine(o, indent, operands[0]);
- decIndent(o, indent);
- break;
- }
- case HasFeature: printOpening(o, "hasfeature ") << nameOperand << ')'; break;
- default: abort();
- }
- return o;
- }
-
void finalize() {
switch (op) {
case PageSize: case MemorySize: case HasFeature: {
@@ -1386,10 +1034,6 @@ public:
Unreachable() : Expression(UnreachableId) {
type = unreachable;
}
-
- std::ostream& doPrint(std::ostream &o, unsigned indent) {
- return printMinorOpening(o, "unreachable") << ')';
- }
};
// Globals
@@ -1411,39 +1055,6 @@ public:
Expression *body;
Function() : result(none) {}
-
- std::ostream& print(std::ostream &o, unsigned indent) {
- printOpening(o, "func ", true) << name;
- if (type.is()) {
- o << " (type " << type << ')';
- }
- if (params.size() > 0) {
- for (auto& param : params) {
- o << ' ';
- printMinorOpening(o, "param ") << param.name << ' ' << printWasmType(param.type) << ")";
- }
- }
- if (result != none) {
- o << ' ';
- printMinorOpening(o, "result ") << printWasmType(result) << ")";
- }
- incIndent(o, indent);
- for (auto& local : locals) {
- doIndent(o, indent);
- printMinorOpening(o, "local ") << local.name << ' ' << printWasmType(local.type) << ")\n";
- }
- // It is ok to emit a block here, as a function can directly contain a list, even if our
- // ast avoids that for simplicity. We can just do that optimization here..
- if (body->is<Block>() && body->cast<Block>()->name.isNull()) {
- Block* block = body->cast<Block>();
- for (auto item : block->list) {
- Expression::printFullLine(o, indent, item);
- }
- } else {
- Expression::printFullLine(o, indent, body);
- }
- return decIndent(o, indent);
- }
};
class Import {
@@ -1452,38 +1063,17 @@ public:
FunctionType* type;
Import() : type(nullptr) {}
-
- std::ostream& print(std::ostream &o, unsigned indent) {
- printOpening(o, "import ") << name << ' ';
- printText(o, module.str) << ' ';
- printText(o, base.str);
- if (type) type->print(o, indent);
- return o << ')';
- }
};
class Export {
public:
Name name; // exported name
Name value; // internal name
-
- std::ostream& print(std::ostream &o, unsigned indent) {
- printOpening(o, "export ");
- return printText(o, name.str) << ' ' << value << ')';
- }
};
class Table {
public:
std::vector<Name> names;
-
- std::ostream& print(std::ostream &o, unsigned indent) {
- printOpening(o, "table");
- for (auto name : names) {
- o << ' ' << name;
- }
- return o << ')';
- }
};
class Memory {
@@ -1575,71 +1165,6 @@ public:
importsMap.erase(name);
}
- 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") << " " << module.memory.initial;
- if (module.memory.max && module.memory.max != (uint32_t)-1) o << " " << module.memory.max;
- for (auto segment : module.memory.segments) {
- o << "\n (segment " << segment.offset << " \"";
- for (size_t i = 0; i < segment.size; i++) {
- unsigned char c = segment.data[i];
- switch (c) {
- case '\n': o << "\\n"; break;
- case '\r': o << "\\0d"; break;
- case '\t': o << "\\t"; break;
- case '\f': o << "\\0c"; break;
- case '\b': o << "\\08"; break;
- case '\\': o << "\\\\"; break;
- case '"' : o << "\\\""; break;
- case '\'' : o << "\\'"; break;
- default: {
- if (c >= 32 && c < 127) {
- o << c;
- } else {
- o << std::hex << '\\' << (c/16) << (c%16) << std::dec;
- }
- }
- }
- }
- o << "\")";
- }
- o << (module.memory.segments.size() > 0 ? "\n " : "") << ")\n";
- if (module.start.is()) {
- doIndent(o, indent);
- printOpening(o, "start") << " " << module.start << ")\n";
- }
- for (auto& curr : module.functionTypes) {
- doIndent(o, indent);
- curr->print(o, indent, true);
- o << '\n';
- }
- for (auto& curr : module.imports) {
- doIndent(o, indent);
- curr->print(o, indent);
- o << '\n';
- }
- for (auto& curr : module.exports) {
- doIndent(o, indent);
- curr->print(o, indent);
- o << '\n';
- }
- if (module.table.names.size() > 0) {
- doIndent(o, indent);
- module.table.print(o, indent);
- o << '\n';
- }
- for (auto& curr : module.functions) {
- doIndent(o, indent);
- curr->print(o, indent);
- o << '\n';
- }
- decIndent(o, indent);
- return o << '\n';
- }
-
private:
size_t functionTypeIndex, importIndex, exportIndex, functionIndex;
};
@@ -1726,40 +1251,6 @@ struct WasmVisitor {
}
};
-std::ostream& Expression::print(std::ostream &o, unsigned indent) {
- struct ExpressionPrinter : public WasmVisitor<ExpressionPrinter, void> {
- std::ostream &o;
- unsigned indent;
-
- ExpressionPrinter(std::ostream &o, unsigned indent) : o(o), indent(indent) {}
-
- void visitBlock(Block *curr) { curr->doPrint(o, indent); }
- void visitIf(If *curr) { curr->doPrint(o, indent); }
- void visitLoop(Loop *curr) { curr->doPrint(o, indent); }
- void visitBreak(Break *curr) { curr->doPrint(o, indent); }
- void visitSwitch(Switch *curr) { curr->doPrint(o, indent); }
- void visitCall(Call *curr) { curr->doPrint(o, indent); }
- void visitCallImport(CallImport *curr) { curr->doPrint(o, indent); }
- void visitCallIndirect(CallIndirect *curr) { curr->doPrint(o, indent); }
- void visitGetLocal(GetLocal *curr) { curr->doPrint(o, indent); }
- void visitSetLocal(SetLocal *curr) { curr->doPrint(o, indent); }
- void visitLoad(Load *curr) { curr->doPrint(o, indent); }
- void visitStore(Store *curr) { curr->doPrint(o, indent); }
- void visitConst(Const *curr) { curr->doPrint(o, indent); }
- void visitUnary(Unary *curr) { curr->doPrint(o, indent); }
- void visitBinary(Binary *curr) { curr->doPrint(o, indent); }
- void visitSelect(Select *curr) { curr->doPrint(o, indent); }
- void visitReturn(Return *curr) { curr->doPrint(o, indent); }
- void visitHost(Host *curr) { curr->doPrint(o, indent); }
- void visitNop(Nop *curr) { curr->doPrint(o, indent); }
- void visitUnreachable(Unreachable *curr) { curr->doPrint(o, indent); }
- };
-
- ExpressionPrinter(o, indent).visit(this);
-
- return o;
-}
-
//
// Base class for all WasmWalkers
//