summaryrefslogtreecommitdiff
path: root/src/passes/Print.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/passes/Print.cpp')
-rw-r--r--src/passes/Print.cpp933
1 files changed, 593 insertions, 340 deletions
diff --git a/src/passes/Print.cpp b/src/passes/Print.cpp
index dfdfa46d4..28e7cc34f 100644
--- a/src/passes/Print.cpp
+++ b/src/passes/Print.cpp
@@ -20,6 +20,7 @@
#include <wasm.h>
#include <wasm-printing.h>
+#include <wasm-stack.h>
#include <pass.h>
#include <pretty_printing.h>
#include <ir/module-utils.h>
@@ -33,294 +34,108 @@ static bool isFullForced() {
return false;
}
-struct PrintSExpression : public Visitor<PrintSExpression> {
- std::ostream& o;
- unsigned indent = 0;
-
- bool minify;
- const char *maybeSpace;
- const char *maybeNewLine;
-
- bool full = false; // whether to not elide nodes in output when possible
- // (like implicit blocks) and to emit types
-
- Module* currModule = nullptr;
- Function* currFunction = nullptr;
- Function::DebugLocation lastPrintedLocation;
-
- std::unordered_map<Name, Index> functionIndexes;
-
- PrintSExpression(std::ostream& o) : o(o) {
- setMinify(false);
- if (!full) full = isFullForced();
+static std::ostream& printName(Name name, std::ostream& o) {
+ // we need to quote names if they have tricky chars
+ if (strpbrk(name.str, "()")) {
+ o << '"' << name << '"';
+ } else {
+ o << name;
}
+ return o;
+}
- void visit(Expression* curr) {
- if (currFunction) {
- // show an annotation, if there is one
- auto& debugLocations = currFunction->debugLocations;
- auto iter = debugLocations.find(curr);
- if (iter != debugLocations.end()) {
- auto fileName = currModule->debugInfoFileNames[iter->second.fileIndex];
- if (lastPrintedLocation != iter->second) {
- lastPrintedLocation = iter->second;
- o << ";;@ " << fileName << ":" << iter->second.lineNumber << ":" << iter->second.columnNumber << '\n';
- doIndent(o, indent);
- }
- }
- }
- Visitor<PrintSExpression>::visit(curr);
+static Name printableLocal(Index index, Function* func) {
+ Name name;
+ if (func) {
+ name = func->getLocalNameOrDefault(index);
}
-
- void setMinify(bool minify_) {
- minify = minify_;
- maybeSpace = minify ? "" : " ";
- maybeNewLine = minify ? "" : "\n";
+ if (!name.is()) {
+ name = Name::fromInt(index);
}
+ return name;
+}
- void setFull(bool full_) { full = full_; }
-
- void incIndent() {
- if (minify) return;
- o << '\n';
- indent++;
- }
- void decIndent() {
- if (!minify) {
- indent--;
- doIndent(o, indent);
- }
- o << ')';
- }
- void printFullLine(Expression *expression) {
- !minify && doIndent(o, indent);
- if (full) {
- o << "[" << printType(expression->type) << "] ";
- }
- visit(expression);
- o << maybeNewLine;
- }
- Name printableLocal(Index index) {
- Name name;
- if (currFunction) {
- name = currFunction->getLocalNameOrDefault(index);
- }
- if (!name.is()) {
- name = Name::fromInt(index);
- }
- return name;
- }
+// Prints the internal contents of an expression: everything but
+// the children.
+struct PrintExpressionContents : public Visitor<PrintExpressionContents> {
+ Function* currFunction = nullptr;
+ std::ostream& o;
- std::ostream& printName(Name name) {
- // we need to quote names if they have tricky chars
- if (strpbrk(name.str, "()")) {
- o << '"' << name << '"';
- } else {
- o << name;
- }
- return o;
- }
+ PrintExpressionContents(Function* currFunction, std::ostream& o) :
+ currFunction(currFunction), o(o) {}
- void visitBlock(Block *curr) {
- // special-case Block, because Block nesting (in their first element) can be incredibly deep
- std::vector<Block*> stack;
- while (1) {
- if (stack.size() > 0) doIndent(o, indent);
- stack.push_back(curr);
- if (full) {
- o << "[" << printType(curr->type) << "] ";
- }
- printOpening(o, "block");
- if (curr->name.is()) {
- o << ' ';
- printName(curr->name);
- }
- if (isConcreteType(curr->type)) {
- o << " (result " << printType(curr->type) << ')';
- }
- incIndent();
- if (curr->list.size() > 0 && curr->list[0]->is<Block>()) {
- // recurse into the first element
- curr = curr->list[0]->cast<Block>();
- continue;
- } else {
- break; // that's all we can recurse, start to unwind
- }
- }
- auto* top = stack.back();
- while (stack.size() > 0) {
- curr = stack.back();
- stack.pop_back();
- auto& list = curr->list;
- for (size_t i = 0; i < list.size(); i++) {
- if (curr != top && i == 0) {
- // one of the block recursions we already handled
- decIndent();
- if (full) {
- o << " ;; end block";
- auto* child = list[0]->cast<Block>();
- if (child->name.is()) {
- o << ' ' << child->name;
- }
- }
- o << '\n';
- continue;
- }
- printFullLine(list[i]);
- }
+ void visitBlock(Block* curr) {
+ printMedium(o, "block");
+ if (curr->name.is()) {
+ o << ' ';
+ printName(curr->name, o);
}
- decIndent();
- if (full) {
- o << " ;; end block";
- if (curr->name.is()) {
- o << ' ' << curr->name;
- }
+ if (isConcreteType(curr->type)) {
+ o << " (result " << printType(curr->type) << ')';
}
}
- void visitIf(If *curr) {
- printOpening(o, "if");
+ void visitIf(If* curr) {
+ printMedium(o, "if");
if (isConcreteType(curr->type)) {
o << " (result " << printType(curr->type) << ')';
}
- incIndent();
- printFullLine(curr->condition);
- // ifTrue and False have implict blocks, avoid printing them if possible
- if (!full && curr->ifTrue->is<Block>() && curr->ifTrue->dynCast<Block>()->name.isNull() && curr->ifTrue->dynCast<Block>()->list.size() == 1) {
- printFullLine(curr->ifTrue->dynCast<Block>()->list.back());
- } else {
- printFullLine(curr->ifTrue);
- }
- if (curr->ifFalse) {
- if (!full && curr->ifFalse->is<Block>() && curr->ifFalse->dynCast<Block>()->name.isNull() && curr->ifFalse->dynCast<Block>()->list.size() == 1) {
- printFullLine(curr->ifFalse->dynCast<Block>()->list.back());
- } else {
- printFullLine(curr->ifFalse);
- }
- }
- decIndent();
- if (full) {
- o << " ;; end if";
- }
}
- void visitLoop(Loop *curr) {
- printOpening(o, "loop");
+ void visitLoop(Loop* curr) {
+ printMedium(o, "loop");
if (curr->name.is()) {
o << ' ' << curr->name;
}
if (isConcreteType(curr->type)) {
o << " (result " << printType(curr->type) << ')';
}
- incIndent();
- auto block = curr->body->dynCast<Block>();
- if (!full && 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();
- if (full) {
- o << " ;; end loop";
- if (curr->name.is()) {
- o << ' ' << curr->name;
- }
- }
}
- void visitBreak(Break *curr) {
+ void visitBreak(Break* curr) {
if (curr->condition) {
- printOpening(o, "br_if ");
- printName(curr->name);
- incIndent();
+ printMedium(o, "br_if ");
} else {
- printOpening(o, "br ");
- printName(curr->name);
- if (!curr->value || curr->value->is<Nop>()) {
- // avoid a new line just for the parens
- o << ')';
- return;
- }
- incIndent();
- }
- if (curr->value && !curr->value->is<Nop>()) printFullLine(curr->value);
- if (curr->condition) {
- printFullLine(curr->condition);
+ printMedium(o, "br ");
}
- decIndent();
+ printName(curr->name, o);
}
- void visitSwitch(Switch *curr) {
- printOpening(o, "br_table");
+ void visitSwitch(Switch* curr) {
+ printMedium(o, "br_table");
for (auto& t : curr->targets) {
o << ' ' << t;
}
o << ' ' << curr->default_;
- incIndent();
- if (curr->value && !curr->value->is<Nop>()) printFullLine(curr->value);
- printFullLine(curr->condition);
- decIndent();
}
-
- template<typename CallBase>
- void printCallBody(CallBase* curr) {
- printName(curr->target);
- if (curr->operands.size() > 0) {
- incIndent();
- for (auto operand : curr->operands) {
- printFullLine(operand);
- }
- decIndent();
- } else {
- o << ')';
- }
- }
-
- void visitCall(Call *curr) {
- printOpening(o, "call ");
- printCallBody(curr);
+ void visitCall(Call* curr) {
+ printMedium(o, "call ");
+ printName(curr->target, o);
}
- void visitCallImport(CallImport *curr) {
- printOpening(o, "call ");
- printCallBody(curr);
+ void visitCallImport(CallImport* curr) {
+ printMedium(o, "call ");
+ printName(curr->target, o);
}
- void visitCallIndirect(CallIndirect *curr) {
- printOpening(o, "call_indirect (type ") << curr->fullType << ')';
- incIndent();
- for (auto operand : curr->operands) {
- printFullLine(operand);
- }
- printFullLine(curr->target);
- decIndent();
+ void visitCallIndirect(CallIndirect* curr) {
+ printMedium(o, "call_indirect (type ") << curr->fullType << ')';
}
- void visitGetLocal(GetLocal *curr) {
- printOpening(o, "get_local ") << printableLocal(curr->index) << ')';
+ void visitGetLocal(GetLocal* curr) {
+ printMedium(o, "get_local ") << printableLocal(curr->index, currFunction);
}
- void visitSetLocal(SetLocal *curr) {
+ void visitSetLocal(SetLocal* curr) {
if (curr->isTee()) {
- printOpening(o, "tee_local ");
+ printMedium(o, "tee_local ");
} else {
- printOpening(o, "set_local ");
+ printMedium(o, "set_local ");
}
- o << printableLocal(curr->index);
- incIndent();
- printFullLine(curr->value);
- decIndent();
+ o << printableLocal(curr->index, currFunction);
}
- void visitGetGlobal(GetGlobal *curr) {
- printOpening(o, "get_global ");
- printName(curr->name) << ')';
+ void visitGetGlobal(GetGlobal* curr) {
+ printMedium(o, "get_global ");
+ printName(curr->name, o);
}
- void visitSetGlobal(SetGlobal *curr) {
- printOpening(o, "set_global ");
- printName(curr->name);
- incIndent();
- printFullLine(curr->value);
- decIndent();
+ void visitSetGlobal(SetGlobal* curr) {
+ printMedium(o, "set_global ");
+ printName(curr->name, o);
}
- void visitLoad(Load *curr) {
- o << '(';
+ void visitLoad(Load* curr) {
prepareColor(o) << printType(curr->type);
if (curr->isAtomic) o << ".atomic";
o << ".load";
@@ -343,12 +158,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
if (curr->align != curr->bytes) {
o << " align=" << curr->align;
}
- incIndent();
- printFullLine(curr->ptr);
- decIndent();
}
- void visitStore(Store *curr) {
- o << '(';
+ void visitStore(Store* curr) {
prepareColor(o) << printType(curr->valueType);
if (curr->isAtomic) o << ".atomic";
o << ".store";
@@ -370,10 +181,6 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
if (curr->align != curr->bytes) {
o << " align=" << curr->align;
}
- incIndent();
- printFullLine(curr->ptr);
- printFullLine(curr->value);
- decIndent();
}
static void printRMWSize(std::ostream& o, Type type, uint8_t bytes) {
prepareColor(o) << printType(type) << ".atomic.rmw";
@@ -394,7 +201,6 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
o << '.';
}
void visitAtomicRMW(AtomicRMW* curr) {
- o << '(';
prepareColor(o);
printRMWSize(o, curr->type, curr->bytes);
switch (curr->op) {
@@ -409,13 +215,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
if (curr->offset) {
o << " offset=" << curr->offset;
}
- incIndent();
- printFullLine(curr->ptr);
- printFullLine(curr->value);
- decIndent();
}
void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
- o << '(';
prepareColor(o);
printRMWSize(o, curr->type, curr->bytes);
o << "cmpxchg";
@@ -423,41 +224,24 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
if (curr->offset) {
o << " offset=" << curr->offset;
}
- incIndent();
- printFullLine(curr->ptr);
- printFullLine(curr->expected);
- printFullLine(curr->replacement);
- decIndent();
}
void visitAtomicWait(AtomicWait* curr) {
- o << '(' ;
prepareColor(o);
o << printType(curr->expectedType) << ".wait";
if (curr->offset) {
o << " offset=" << curr->offset;
}
- restoreNormalColor(o);
- incIndent();
- printFullLine(curr->ptr);
- printFullLine(curr->expected);
- printFullLine(curr->timeout);
- decIndent();
}
void visitAtomicWake(AtomicWake* curr) {
- printOpening(o, "wake");
+ printMedium(o, "wake");
if (curr->offset) {
o << " offset=" << curr->offset;
}
- incIndent();
- printFullLine(curr->ptr);
- printFullLine(curr->wakeCount);
- decIndent();
}
- void visitConst(Const *curr) {
+ void visitConst(Const* curr) {
o << curr->value;
}
- void visitUnary(Unary *curr) {
- o << '(';
+ void visitUnary(Unary* curr) {
prepareColor(o);
switch (curr->op) {
case ClzInt32: o << "i32.clz"; break;
@@ -514,12 +298,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
case ExtendS32Int64: o << "i64.extend32_s"; break;
default: abort();
}
- incIndent();
- printFullLine(curr->value);
- decIndent();
}
- void visitBinary(Binary *curr) {
- o << '(';
+ void visitBinary(Binary* curr) {
prepareColor(o);
switch (curr->op) {
case AddInt32: o << "i32.add"; break;
@@ -605,28 +385,375 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
default: abort();
}
restoreNormalColor(o);
+ }
+ void visitSelect(Select* curr) {
+ prepareColor(o) << "select";
+ }
+ void visitDrop(Drop* curr) {
+ printMedium(o, "drop");
+ }
+ void visitReturn(Return* curr) {
+ printMedium(o, "return");
+ }
+ void visitHost(Host* curr) {
+ switch (curr->op) {
+ case PageSize: printMedium(o, "pagesize"); break;
+ case CurrentMemory: printMedium(o, "current_memory"); break;
+ case GrowMemory: printMedium(o, "grow_memory"); break;
+ case HasFeature: printMedium(o, "hasfeature ") << curr->nameOperand; break;
+ default: WASM_UNREACHABLE();
+ }
+ }
+ void visitNop(Nop* curr) {
+ printMinor(o, "nop");
+ }
+ void visitUnreachable(Unreachable* curr) {
+ printMinor(o, "unreachable");
+ }
+};
+
+// Prints an expression in s-expr format, including both the
+// internal contents and the nested children.
+struct PrintSExpression : public Visitor<PrintSExpression> {
+ std::ostream& o;
+ unsigned indent = 0;
+
+ bool minify;
+ const char *maybeSpace;
+ const char *maybeNewLine;
+
+ bool full = false; // whether to not elide nodes in output when possible
+ // (like implicit blocks) and to emit types
+ bool printStackIR = false; // whether to print stack IR if it is present
+ // (if false, and Stack IR is there, we just
+ // note it exists)
+
+ Module* currModule = nullptr;
+ Function* currFunction = nullptr;
+ Function::DebugLocation lastPrintedLocation;
+
+ std::unordered_map<Name, Index> functionIndexes;
+
+ PrintSExpression(std::ostream& o) : o(o) {
+ setMinify(false);
+ if (!full) full = isFullForced();
+ }
+
+ void visit(Expression* curr) {
+ if (currFunction) {
+ // show an annotation, if there is one
+ auto& debugLocations = currFunction->debugLocations;
+ auto iter = debugLocations.find(curr);
+ if (iter != debugLocations.end()) {
+ auto fileName = currModule->debugInfoFileNames[iter->second.fileIndex];
+ if (lastPrintedLocation != iter->second) {
+ lastPrintedLocation = iter->second;
+ o << ";;@ " << fileName << ":" << iter->second.lineNumber << ":" << iter->second.columnNumber << '\n';
+ doIndent(o, indent);
+ }
+ }
+ }
+ Visitor<PrintSExpression>::visit(curr);
+ }
+
+ void setMinify(bool minify_) {
+ minify = minify_;
+ maybeSpace = minify ? "" : " ";
+ maybeNewLine = minify ? "" : "\n";
+ }
+
+ void setFull(bool full_) { full = full_; }
+
+ void incIndent() {
+ if (minify) return;
+ o << '\n';
+ indent++;
+ }
+ void decIndent() {
+ if (!minify) {
+ indent--;
+ doIndent(o, indent);
+ }
+ o << ')';
+ }
+ void printFullLine(Expression *expression) {
+ !minify && doIndent(o, indent);
+ if (full) {
+ o << "[" << printType(expression->type) << "] ";
+ }
+ visit(expression);
+ o << maybeNewLine;
+ }
+
+ void visitBlock(Block* curr) {
+ // special-case Block, because Block nesting (in their first element) can be incredibly deep
+ std::vector<Block*> stack;
+ while (1) {
+ if (stack.size() > 0) doIndent(o, indent);
+ stack.push_back(curr);
+ if (full) {
+ o << "[" << printType(curr->type) << "] ";
+ }
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ if (curr->list.size() > 0 && curr->list[0]->is<Block>()) {
+ // recurse into the first element
+ curr = curr->list[0]->cast<Block>();
+ continue;
+ } else {
+ break; // that's all we can recurse, start to unwind
+ }
+ }
+ auto* top = stack.back();
+ while (stack.size() > 0) {
+ curr = stack.back();
+ stack.pop_back();
+ auto& list = curr->list;
+ for (size_t i = 0; i < list.size(); i++) {
+ if (curr != top && i == 0) {
+ // one of the block recursions we already handled
+ decIndent();
+ if (full) {
+ o << " ;; end block";
+ auto* child = list[0]->cast<Block>();
+ if (child->name.is()) {
+ o << ' ' << child->name;
+ }
+ }
+ o << '\n';
+ continue;
+ }
+ printFullLine(list[i]);
+ }
+ }
+ decIndent();
+ if (full) {
+ o << " ;; end block";
+ if (curr->name.is()) {
+ o << ' ' << curr->name;
+ }
+ }
+ }
+ void visitIf(If* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->condition);
+ // ifTrue and False have implict blocks, avoid printing them if possible
+ if (!full && curr->ifTrue->is<Block>() && curr->ifTrue->dynCast<Block>()->name.isNull() && curr->ifTrue->dynCast<Block>()->list.size() == 1) {
+ printFullLine(curr->ifTrue->dynCast<Block>()->list.back());
+ } else {
+ printFullLine(curr->ifTrue);
+ }
+ if (curr->ifFalse) {
+ if (!full && curr->ifFalse->is<Block>() && curr->ifFalse->dynCast<Block>()->name.isNull() && curr->ifFalse->dynCast<Block>()->list.size() == 1) {
+ printFullLine(curr->ifFalse->dynCast<Block>()->list.back());
+ } else {
+ printFullLine(curr->ifFalse);
+ }
+ }
+ decIndent();
+ if (full) {
+ o << " ;; end if";
+ }
+ }
+ void visitLoop(Loop* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ auto block = curr->body->dynCast<Block>();
+ if (!full && 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();
+ if (full) {
+ o << " ;; end loop";
+ if (curr->name.is()) {
+ o << ' ' << curr->name;
+ }
+ }
+ }
+ void visitBreak(Break* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ if (curr->condition) {
+ incIndent();
+ } else {
+ if (!curr->value || curr->value->is<Nop>()) {
+ // avoid a new line just for the parens
+ o << ')';
+ return;
+ }
+ incIndent();
+ }
+ if (curr->value && !curr->value->is<Nop>()) printFullLine(curr->value);
+ if (curr->condition) {
+ printFullLine(curr->condition);
+ }
+ decIndent();
+ }
+ void visitSwitch(Switch* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ if (curr->value && !curr->value->is<Nop>()) printFullLine(curr->value);
+ printFullLine(curr->condition);
+ decIndent();
+ }
+
+ template<typename CallBase>
+ void printCallOperands(CallBase* curr) {
+ if (curr->operands.size() > 0) {
+ incIndent();
+ for (auto operand : curr->operands) {
+ printFullLine(operand);
+ }
+ decIndent();
+ } else {
+ o << ')';
+ }
+ }
+
+ void visitCall(Call* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ printCallOperands(curr);
+ }
+ void visitCallImport(CallImport* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ printCallOperands(curr);
+ }
+ void visitCallIndirect(CallIndirect* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ for (auto operand : curr->operands) {
+ printFullLine(operand);
+ }
+ printFullLine(curr->target);
+ decIndent();
+ }
+ void visitGetLocal(GetLocal* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ o << ')';
+ }
+ void visitSetLocal(SetLocal* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->value);
+ decIndent();
+ }
+ void visitGetGlobal(GetGlobal* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ o << ')';
+ }
+ void visitSetGlobal(SetGlobal* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->value);
+ decIndent();
+ }
+ void visitLoad(Load* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->ptr);
+ decIndent();
+ }
+ void visitStore(Store* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->ptr);
+ printFullLine(curr->value);
+ decIndent();
+ }
+ void visitAtomicRMW(AtomicRMW* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->ptr);
+ printFullLine(curr->value);
+ decIndent();
+ }
+ void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->ptr);
+ printFullLine(curr->expected);
+ printFullLine(curr->replacement);
+ decIndent();
+ }
+ void visitAtomicWait(AtomicWait* curr) {
+ o << '(' ;
+ PrintExpressionContents(currFunction, o).visit(curr);
+ restoreNormalColor(o);
+ incIndent();
+ printFullLine(curr->ptr);
+ printFullLine(curr->expected);
+ printFullLine(curr->timeout);
+ decIndent();
+ }
+ void visitAtomicWake(AtomicWake* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->ptr);
+ printFullLine(curr->wakeCount);
+ decIndent();
+ }
+ void visitConst(Const* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ o << ')';
+ }
+ void visitUnary(Unary* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ incIndent();
+ printFullLine(curr->value);
+ decIndent();
+ }
+ void visitBinary(Binary* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
incIndent();
printFullLine(curr->left);
printFullLine(curr->right);
decIndent();
}
- void visitSelect(Select *curr) {
+ void visitSelect(Select* curr) {
o << '(';
- prepareColor(o) << "select";
+ PrintExpressionContents(currFunction, o).visit(curr);
incIndent();
printFullLine(curr->ifTrue);
printFullLine(curr->ifFalse);
printFullLine(curr->condition);
decIndent();
}
- void visitDrop(Drop *curr) {
- printOpening(o, "drop");
+ void visitDrop(Drop* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
incIndent();
printFullLine(curr->value);
decIndent();
}
- void visitReturn(Return *curr) {
- printOpening(o, "return");
+ void visitReturn(Return* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
if (!curr->value) {
// avoid a new line just for the parens
o << ')';
@@ -636,34 +763,44 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
printFullLine(curr->value);
decIndent();
}
- void visitHost(Host *curr) {
+ void visitHost(Host* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
switch (curr->op) {
- case PageSize: printOpening(o, "pagesize") << ')'; break;
- case CurrentMemory: printOpening(o, "current_memory") << ')'; break;
case GrowMemory: {
- printOpening(o, "grow_memory");
incIndent();
printFullLine(curr->operands[0]);
decIndent();
break;
}
- case HasFeature: printOpening(o, "hasfeature ") << curr->nameOperand << ')'; break;
- default: abort();
+ case HasFeature: {
+ o << curr->nameOperand;
+ o << ')';
+ break;
+ }
+ default: {
+ o << ')';
+ }
}
}
- void visitNop(Nop *curr) {
- printMinorOpening(o, "nop") << ')';
+ void visitNop(Nop* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ o << ')';
}
- void visitUnreachable(Unreachable *curr) {
- printMinorOpening(o, "unreachable") << ')';
+ void visitUnreachable(Unreachable* curr) {
+ o << '(';
+ PrintExpressionContents(currFunction, o).visit(curr);
+ o << ')';
}
// Module-level visitors
- void visitFunctionType(FunctionType *curr, Name* internalName = nullptr) {
+ void visitFunctionType(FunctionType* curr, Name* internalName = nullptr) {
o << "(func";
if (internalName) o << ' ' << *internalName;
if (curr->params.size() > 0) {
o << maybeSpace;
- printMinorOpening(o, "param");
+ o << '(';
+ printMinor(o, "param");
for (auto& param : curr->params) {
o << ' ' << printType(param);
}
@@ -671,12 +808,14 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
if (curr->result != none) {
o << maybeSpace;
- printMinorOpening(o, "result ") << printType(curr->result) << ')';
+ o << '(';
+ printMinor(o, "result ") << printType(curr->result) << ')';
}
o << ")";
}
- void visitImport(Import *curr) {
- printOpening(o, "import ");
+ void visitImport(Import* curr) {
+ o << '(';
+ printMedium(o, "import ");
printText(o, curr->module.str) << ' ';
printText(o, curr->base.str) << ' ';
switch (curr->kind) {
@@ -688,8 +827,9 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
o << ')';
}
- void visitExport(Export *curr) {
- printOpening(o, "export ");
+ void visitExport(Export* curr) {
+ o << '(';
+ printMedium(o, "export ");
printText(o, curr->name.str) << " (";
switch (curr->kind) {
case ExternalKind::Function: o << "func"; break;
@@ -699,11 +839,12 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
default: WASM_UNREACHABLE();
}
o << ' ';
- printName(curr->value) << "))";
+ printName(curr->value, o) << "))";
}
- void visitGlobal(Global *curr) {
- printOpening(o, "global ");
- printName(curr->name) << ' ';
+ void visitGlobal(Global* curr) {
+ o << '(';
+ printMedium(o, "global ");
+ printName(curr->name, o) << ' ';
if (curr->mutable_) {
o << "(mut " << printType(curr->type) << ") ";
} else {
@@ -712,11 +853,12 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
visit(curr->init);
o << ')';
}
- void visitFunction(Function *curr) {
+ void visitFunction(Function* curr) {
currFunction = curr;
lastPrintedLocation = { 0, 0, 0 };
- printOpening(o, "func ", true);
- printName(curr->name);
+ o << '(';
+ printMajor(o, "func ");
+ printName(curr->name, o);
if (currModule && !minify) {
// emit the function index in a comment
if (functionIndexes.empty()) {
@@ -734,38 +876,48 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
if (curr->params.size() > 0) {
for (size_t i = 0; i < curr->params.size(); i++) {
o << maybeSpace;
- printMinorOpening(o, "param ") << printableLocal(i) << ' ' << printType(curr->getLocalType(i)) << ')';
+ o << '(';
+ printMinor(o, "param ") << printableLocal(i, currFunction) << ' ' << printType(curr->getLocalType(i)) << ')';
}
}
if (curr->result != none) {
o << maybeSpace;
- printMinorOpening(o, "result ") << printType(curr->result) << ')';
+ o << '(';
+ printMinor(o, "result ") << printType(curr->result) << ')';
}
incIndent();
for (size_t i = curr->getVarIndexBase(); i < curr->getNumLocals(); i++) {
doIndent(o, indent);
- printMinorOpening(o, "local ") << printableLocal(i) << ' ' << printType(curr->getLocalType(i)) << ')';
+ o << '(';
+ printMinor(o, "local ") << printableLocal(i, currFunction) << ' ' << printType(curr->getLocalType(i)) << ')';
o << maybeNewLine;
}
- // 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 (!full && curr->body->is<Block>() && curr->body->cast<Block>()->name.isNull()) {
- Block* block = curr->body->cast<Block>();
- for (auto item : block->list) {
- printFullLine(item);
+ // Print the body.
+ if (!printStackIR || !curr->stackIR) {
+ // 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 (!full && 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);
}
} else {
- printFullLine(curr->body);
+ // Print the stack IR.
+ WasmPrinter::printStackIR(curr->stackIR.get(), o, curr);
}
decIndent();
}
void printTableHeader(Table* curr) {
- printOpening(o, "table") << ' ';
+ o << '(';
+ printMedium(o, "table") << ' ';
o << curr->initial;
if (curr->hasMax()) o << ' ' << curr->max;
o << " anyfunc)";
}
- void visitTable(Table *curr) {
+ void visitTable(Table* curr) {
if (!curr->exists) return;
// if table wasn't imported, declare it
if (!curr->imported) {
@@ -777,19 +929,24 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
// Don't print empty segments
if (segment.data.empty()) continue;
doIndent(o, indent);
- printOpening(o, "elem ", true);
+ o << '(';
+ printMajor(o, "elem ");
visit(segment.offset);
for (auto name : segment.data) {
o << ' ';
- printName(name);
+ printName(name, o);
}
o << ")\n";
}
}
void printMemoryHeader(Memory* curr) {
- printOpening(o, "memory") << ' ';
- printName(curr->name) << ' ';
- if (curr->shared) printOpening(o, "shared ");
+ o << '(';
+ printMedium(o, "memory") << ' ';
+ printName(curr->name, o) << ' ';
+ if (curr->shared) {
+ o << '(';
+ printMedium(o, "shared ");
+ }
o << curr->initial;
if (curr->hasMax()) o << ' ' << curr->max;
if (curr->shared) o << ")";
@@ -805,7 +962,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
for (auto segment : curr->segments) {
doIndent(o, indent);
- printOpening(o, "data ", true);
+ o << '(';
+ printMajor(o, "data ");
visit(segment.offset);
o << " \"";
for (size_t i = 0; i < segment.data.size(); i++) {
@@ -831,14 +989,16 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
o << "\")\n";
}
}
- void visitModule(Module *curr) {
+ void visitModule(Module* curr) {
currModule = curr;
- printOpening(o, "module", true);
+ o << '(';
+ printMajor(o, "module");
incIndent();
for (auto& child : curr->functionTypes) {
doIndent(o, indent);
- printOpening(o, "type") << ' ';
- printName(child->name) << ' ';
+ o << '(';
+ printMedium(o, "type") << ' ';
+ printName(child->name, o) << ' ';
visitFunctionType(child.get());
o << ")" << maybeNewLine;
}
@@ -863,7 +1023,8 @@ struct PrintSExpression : public Visitor<PrintSExpression> {
}
if (curr->start.is()) {
doIndent(o, indent);
- printOpening(o, "start") << ' ' << curr->start << ')';
+ o << '(';
+ printMedium(o, "start") << ' ' << curr->start << ')';
o << maybeNewLine;
}
for (auto& child : curr->functions) {
@@ -939,6 +1100,24 @@ Pass *createFullPrinterPass() {
return new FullPrinter();
}
+// Print Stack IR (if present)
+
+class PrintStackIR : public Printer {
+public:
+ PrintStackIR() : Printer() {}
+ PrintStackIR(std::ostream* o) : Printer(o) {}
+
+ void run(PassRunner* runner, Module* module) override {
+ PrintSExpression print(o);
+ print.printStackIR = true;
+ print.visitModule(module);
+ }
+};
+
+Pass* createPrintStackIRPass() {
+ return new PrintStackIR();
+}
+
// Print individual expressions
std::ostream& WasmPrinter::printModule(Module* module, std::ostream& o) {
@@ -969,4 +1148,78 @@ std::ostream& WasmPrinter::printExpression(Expression* expression, std::ostream&
return o;
}
+std::ostream& WasmPrinter::printStackInst(StackInst* inst, std::ostream& o, Function* func) {
+ switch (inst->op) {
+ case StackInst::Basic: {
+ PrintExpressionContents(func, o).visit(inst->origin);
+ break;
+ }
+ case StackInst::BlockBegin:
+ case StackInst::IfBegin:
+ case StackInst::LoopBegin: {
+ o << getExpressionName(inst->origin);
+ break;
+ }
+ case StackInst::BlockEnd:
+ case StackInst::IfEnd:
+ case StackInst::LoopEnd: {
+ o << "end (" << printType(inst->type) << ')';
+ break;
+ }
+ case StackInst::IfElse: {
+ o << "else";
+ break;
+ }
+ default: WASM_UNREACHABLE();
+ }
+ return o;
+}
+
+std::ostream& WasmPrinter::printStackIR(StackIR* ir, std::ostream& o, Function* func) {
+ size_t indent = func ? 2 : 0;
+ auto doIndent = [&indent, &o]() {
+ for (size_t j = 0; j < indent; j++) {
+ o << ' ';
+ }
+ };
+ for (Index i = 0; i < (*ir).size(); i++) {
+ auto* inst = (*ir)[i];
+ if (!inst) continue;
+ switch (inst->op) {
+ case StackInst::Basic: {
+ doIndent();
+ PrintExpressionContents(func, o).visit(inst->origin);
+ break;
+ }
+ case StackInst::BlockBegin:
+ case StackInst::IfBegin:
+ case StackInst::LoopBegin: {
+ doIndent();
+ PrintExpressionContents(func, o).visit(inst->origin);
+ indent++;
+ break;
+ }
+ case StackInst::BlockEnd:
+ case StackInst::IfEnd:
+ case StackInst::LoopEnd: {
+ indent--;
+ doIndent();
+ o << "end";
+ break;
+ }
+ case StackInst::IfElse: {
+ indent--;
+ doIndent();
+ o << "else";
+ indent++;
+ doIndent();
+ break;
+ }
+ default: WASM_UNREACHABLE();
+ }
+ std::cout << '\n';
+ }
+ return o;
+}
+
} // namespace wasm