summaryrefslogtreecommitdiff
path: root/src/wasm-traversal.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm-traversal.h')
-rw-r--r--src/wasm-traversal.h634
1 files changed, 306 insertions, 328 deletions
diff --git a/src/wasm-traversal.h b/src/wasm-traversal.h
index 24ec4905c..d1fff2753 100644
--- a/src/wasm-traversal.h
+++ b/src/wasm-traversal.h
@@ -31,47 +31,47 @@
namespace wasm {
-template<typename SubType, typename ReturnType>
-struct WasmVisitor {
- virtual ~WasmVisitor() {}
+template<typename SubType, typename ReturnType = void>
+struct Visitor {
+ virtual ~Visitor() {}
// Expression visitors
- ReturnType visitBlock(Block *curr) { abort(); }
- ReturnType visitIf(If *curr) { abort(); }
- ReturnType visitLoop(Loop *curr) { abort(); }
- ReturnType visitBreak(Break *curr) { abort(); }
- ReturnType visitSwitch(Switch *curr) { abort(); }
- ReturnType visitCall(Call *curr) { abort(); }
- ReturnType visitCallImport(CallImport *curr) { abort(); }
- ReturnType visitCallIndirect(CallIndirect *curr) { abort(); }
- ReturnType visitGetLocal(GetLocal *curr) { abort(); }
- ReturnType visitSetLocal(SetLocal *curr) { abort(); }
- ReturnType visitLoad(Load *curr) { abort(); }
- ReturnType visitStore(Store *curr) { abort(); }
- ReturnType visitConst(Const *curr) { abort(); }
- ReturnType visitUnary(Unary *curr) { abort(); }
- ReturnType visitBinary(Binary *curr) { abort(); }
- ReturnType visitSelect(Select *curr) { abort(); }
- ReturnType visitReturn(Return *curr) { abort(); }
- ReturnType visitHost(Host *curr) { abort(); }
- ReturnType visitNop(Nop *curr) { abort(); }
- ReturnType visitUnreachable(Unreachable *curr) { abort(); }
+ ReturnType visitBlock(Block *curr) {}
+ ReturnType visitIf(If *curr) {}
+ ReturnType visitLoop(Loop *curr) {}
+ ReturnType visitBreak(Break *curr) {}
+ ReturnType visitSwitch(Switch *curr) {}
+ ReturnType visitCall(Call *curr) {}
+ ReturnType visitCallImport(CallImport *curr) {}
+ ReturnType visitCallIndirect(CallIndirect *curr) {}
+ ReturnType visitGetLocal(GetLocal *curr) {}
+ ReturnType visitSetLocal(SetLocal *curr) {}
+ ReturnType visitLoad(Load *curr) {}
+ ReturnType visitStore(Store *curr) {}
+ ReturnType visitConst(Const *curr) {}
+ ReturnType visitUnary(Unary *curr) {}
+ ReturnType visitBinary(Binary *curr) {}
+ ReturnType visitSelect(Select *curr) {}
+ ReturnType visitReturn(Return *curr) {}
+ ReturnType visitHost(Host *curr) {}
+ ReturnType visitNop(Nop *curr) {}
+ ReturnType visitUnreachable(Unreachable *curr) {}
// Module-level visitors
- ReturnType visitFunctionType(FunctionType *curr) { abort(); }
- ReturnType visitImport(Import *curr) { abort(); }
- ReturnType visitExport(Export *curr) { abort(); }
- ReturnType visitFunction(Function *curr) { abort(); }
- ReturnType visitTable(Table *curr) { abort(); }
- ReturnType visitMemory(Memory *curr) { abort(); }
- ReturnType visitModule(Module *curr) { abort(); }
-
-#define DELEGATE(CLASS_TO_VISIT) \
- return static_cast<SubType*>(this)-> \
- visit##CLASS_TO_VISIT(static_cast<CLASS_TO_VISIT*>(curr))
+ ReturnType visitFunctionType(FunctionType *curr) {}
+ ReturnType visitImport(Import *curr) {}
+ ReturnType visitExport(Export *curr) {}
+ ReturnType visitFunction(Function *curr) {}
+ ReturnType visitTable(Table *curr) {}
+ ReturnType visitMemory(Memory *curr) {}
+ ReturnType visitModule(Module *curr) {}
ReturnType visit(Expression *curr) {
assert(curr);
+
+ #define DELEGATE(CLASS_TO_VISIT) \
+ return static_cast<SubType*>(this)-> \
+ visit##CLASS_TO_VISIT(static_cast<CLASS_TO_VISIT*>(curr))
+
switch (curr->_id) {
- case Expression::Id::InvalidId: abort();
case Expression::Id::BlockId: DELEGATE(Block);
case Expression::Id::IfId: DELEGATE(If);
case Expression::Id::LoopId: DELEGATE(Loop);
@@ -92,49 +92,41 @@ struct WasmVisitor {
case Expression::Id::HostId: DELEGATE(Host);
case Expression::Id::NopId: DELEGATE(Nop);
case Expression::Id::UnreachableId: DELEGATE(Unreachable);
+ case Expression::Id::InvalidId:
default: WASM_UNREACHABLE();
}
- }
-#undef DELEGATE
-
- // Helper method to de-recurse blocks, which often nest in their first position very heavily
- void derecurseBlocks(Block* block, std::function<void (Block*)> preBlock,
- std::function<void (Block*, Expression*&)> onChild,
- std::function<void (Block*)> postBlock) {
- std::vector<Block*> stack;
- stack.push_back(block);
- while (block->list.size() > 0 && block->list[0]->is<Block>()) {
- block = block->list[0]->cast<Block>();
- stack.push_back(block);
- }
- for (size_t i = 0; i < stack.size(); i++) {
- preBlock(stack[i]);
- }
- for (int i = int(stack.size()) - 1; i >= 0; i--) {
- auto* block = stack[i];
- auto& list = block->list;
- for (size_t j = 0; j < list.size(); j++) {
- if (i < int(stack.size()) - 1 && j == 0) {
- // nested block, we already called its pre
- } else {
- onChild(block, list[j]);
- }
- }
- postBlock(block);
- }
+ #undef DELEGATE
}
};
//
-// Base class for all WasmWalkers
+// Base class for all WasmWalkers, which can traverse an AST
+// and provide the option to replace nodes while doing so.
//
-template<typename SubType, typename ReturnType = void>
-struct WasmWalkerBase : public WasmVisitor<SubType, ReturnType> {
- virtual void walk(Expression*& curr) { abort(); }
+// Subclass and implement the visit*()
+// calls to run code on different node types.
+//
+template<typename SubType>
+struct Walker : public Visitor<SubType> {
+ // Extra generic visitor, called before each node's specific visitor. Useful for
+ // passes that need to do the same thing for every node type.
+ void visitExpression(Expression* curr) {}
+
+ // Node replacing as we walk - call replaceCurrent from
+ // your visitors.
+
+ Expression *replace = nullptr;
+
+ void replaceCurrent(Expression *expression) {
+ replace = expression;
+ }
+
+ // Walk starting
void startWalk(Function *func) {
- walk(func->body);
+ SubType* self = static_cast<SubType*>(this);
+ self->walk(func->body);
}
void startWalk(Module *module) {
@@ -157,185 +149,209 @@ struct WasmWalkerBase : public WasmVisitor<SubType, ReturnType> {
self->visitMemory(&module->memory);
self->visitModule(module);
}
-};
-template<typename ParentType>
-struct ChildWalker : public WasmWalkerBase<ChildWalker<ParentType>> {
- ParentType& parent;
+ // Walk implementation. We don't use recursion as ASTs may be highly
+ // nested.
- ChildWalker(ParentType& parent) : parent(parent) {}
+ // Tasks receive the this pointer and a pointer to the pointer to operate on
+ typedef void (*TaskFunc)(SubType*, Expression**);
- void visitBlock(Block *curr) {
- ExpressionList& list = curr->list;
- for (size_t z = 0; z < list.size(); z++) {
- parent.walk(list[z]);
- }
- }
- void visitIf(If *curr) {
- parent.walk(curr->condition);
- parent.walk(curr->ifTrue);
- parent.walk(curr->ifFalse);
- }
- void visitLoop(Loop *curr) {
- parent.walk(curr->body);
- }
- void visitBreak(Break *curr) {
- parent.walk(curr->condition);
- parent.walk(curr->value);
- }
- void visitSwitch(Switch *curr) {
- parent.walk(curr->condition);
- if (curr->value) parent.walk(curr->value);
- }
- void visitCall(Call *curr) {
- ExpressionList& list = curr->operands;
- for (size_t z = 0; z < list.size(); z++) {
- parent.walk(list[z]);
- }
- }
- void visitCallImport(CallImport *curr) {
- ExpressionList& list = curr->operands;
- for (size_t z = 0; z < list.size(); z++) {
- parent.walk(list[z]);
- }
+ struct Task {
+ TaskFunc func;
+ Expression** currp;
+ Task(TaskFunc func, Expression** currp) : func(func), currp(currp) {}
+ };
+
+ std::vector<Task> stack;
+
+ void pushTask(TaskFunc func, Expression** currp) {
+ stack.emplace_back(func, currp);
}
- void visitCallIndirect(CallIndirect *curr) {
- parent.walk(curr->target);
- ExpressionList& list = curr->operands;
- for (size_t z = 0; z < list.size(); z++) {
- parent.walk(list[z]);
+ void maybePushTask(TaskFunc func, Expression** currp) {
+ if (*currp) {
+ stack.emplace_back(func, currp);
}
}
- void visitGetLocal(GetLocal *curr) {}
- void visitSetLocal(SetLocal *curr) {
- parent.walk(curr->value);
- }
- void visitLoad(Load *curr) {
- parent.walk(curr->ptr);
- }
- void visitStore(Store *curr) {
- parent.walk(curr->ptr);
- parent.walk(curr->value);
- }
- void visitConst(Const *curr) {}
- void visitUnary(Unary *curr) {
- parent.walk(curr->value);
- }
- void visitBinary(Binary *curr) {
- parent.walk(curr->left);
- parent.walk(curr->right);
- }
- void visitSelect(Select *curr) {
- parent.walk(curr->ifTrue);
- parent.walk(curr->ifFalse);
- parent.walk(curr->condition);
- }
- void visitReturn(Return *curr) {
- parent.walk(curr->value);
- }
- void visitHost(Host *curr) {
- ExpressionList& list = curr->operands;
- for (size_t z = 0; z < list.size(); z++) {
- parent.walk(list[z]);
+ Task popTask() {
+ auto ret = stack.back();
+ stack.pop_back();
+ return ret;
+ }
+
+ void walk(Expression*& root) {
+ assert(stack.size() == 0);
+ pushTask(SubType::scan, &root);
+ while (stack.size() > 0) {
+ auto task = popTask();
+ assert(*task.currp);
+ task.func(static_cast<SubType*>(this), task.currp);
+ if (replace) {
+ *task.currp = replace;
+ replace = nullptr;
+ }
}
}
- void visitNop(Nop *curr) {}
- void visitUnreachable(Unreachable *curr) {}
-};
-
-// Walker that allows replacements
-template<typename SubType, typename ReturnType = void>
-struct WasmReplacerWalker : public WasmWalkerBase<SubType, ReturnType> {
- Expression* replace = nullptr;
-
- // methods can call this to replace the current node
- void replaceCurrent(Expression *expression) {
- replace = expression;
- }
- void walk(Expression*& curr) override {
- if (!curr) return;
-
- this->visit(curr);
-
- if (replace) {
- curr = replace;
- replace = nullptr;
- }
- }
+ // subclasses implement this to define the proper order of execution
+ static void scan(SubType* self, Expression** currp) { abort(); }
+
+ // task hooks to call visitors
+
+ static void doVisitBlock(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitBlock((*currp)->cast<Block>()); }
+ static void doVisitIf(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitIf((*currp)->cast<If>()); }
+ static void doVisitLoop(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitLoop((*currp)->cast<Loop>()); }
+ static void doVisitBreak(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitBreak((*currp)->cast<Break>()); }
+ static void doVisitSwitch(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitSwitch((*currp)->cast<Switch>()); }
+ static void doVisitCall(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitCall((*currp)->cast<Call>()); }
+ static void doVisitCallImport(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitCallImport((*currp)->cast<CallImport>()); }
+ static void doVisitCallIndirect(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitCallIndirect((*currp)->cast<CallIndirect>()); }
+ static void doVisitGetLocal(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitGetLocal((*currp)->cast<GetLocal>()); }
+ static void doVisitSetLocal(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitSetLocal((*currp)->cast<SetLocal>()); }
+ static void doVisitLoad(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitLoad((*currp)->cast<Load>()); }
+ static void doVisitStore(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitStore((*currp)->cast<Store>()); }
+ static void doVisitConst(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitConst((*currp)->cast<Const>()); }
+ static void doVisitUnary(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitUnary((*currp)->cast<Unary>()); }
+ static void doVisitBinary(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitBinary((*currp)->cast<Binary>()); }
+ static void doVisitSelect(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitSelect((*currp)->cast<Select>()); }
+ static void doVisitReturn(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitReturn((*currp)->cast<Return>()); }
+ static void doVisitHost(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitHost((*currp)->cast<Host>()); }
+ static void doVisitNop(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitNop((*currp)->cast<Nop>()); }
+ static void doVisitUnreachable(SubType* self, Expression** currp) { self->visitExpression(*currp); self->visitUnreachable((*currp)->cast<Unreachable>()); }
};
-//
-// Simple WebAssembly children-first walking (i.e., post-order, if you look
-// at the children as subtrees of the current node), with the ability to replace
-// the current expression node. Useful for writing optimization passes.
-//
+// Walks in post-order, i.e., children first. When there isn't an obvious
+// order to operands, we follow them in order of execution.
-template<typename SubType, typename ReturnType = void>
-struct WasmWalker : public WasmReplacerWalker<SubType, ReturnType> {
- // By default, do nothing
- ReturnType visitBlock(Block *curr) {}
- ReturnType visitIf(If *curr) {}
- ReturnType visitLoop(Loop *curr) {}
- ReturnType visitBreak(Break *curr) {}
- ReturnType visitSwitch(Switch *curr) {}
- ReturnType visitCall(Call *curr) {}
- ReturnType visitCallImport(CallImport *curr) {}
- ReturnType visitCallIndirect(CallIndirect *curr) {}
- ReturnType visitGetLocal(GetLocal *curr) {}
- ReturnType visitSetLocal(SetLocal *curr) {}
- ReturnType visitLoad(Load *curr) {}
- ReturnType visitStore(Store *curr) {}
- ReturnType visitConst(Const *curr) {}
- ReturnType visitUnary(Unary *curr) {}
- ReturnType visitBinary(Binary *curr) {}
- ReturnType visitSelect(Select *curr) {}
- ReturnType visitReturn(Return *curr) {}
- ReturnType visitHost(Host *curr) {}
- ReturnType visitNop(Nop *curr) {}
- ReturnType visitUnreachable(Unreachable *curr) {}
+template<typename SubType>
+struct PostWalker : public Walker<SubType> {
- ReturnType visitFunctionType(FunctionType *curr) {}
- ReturnType visitImport(Import *curr) {}
- ReturnType visitExport(Export *curr) {}
- ReturnType visitFunction(Function *curr) {}
- ReturnType visitTable(Table *curr) {}
- ReturnType visitMemory(Memory *curr) {}
- ReturnType visitModule(Module *curr) {}
+ static void scan(SubType* self, Expression** currp) {
- // children-first
- void walk(Expression*& curr) override {
- if (!curr) return;
-
- // special-case Block, because Block nesting (in their first element) can be incredibly deep
- if (curr->is<Block>()) {
- auto* block = curr->dyn_cast<Block>();
- std::vector<Block*> stack;
- stack.push_back(block);
- while (block->list.size() > 0 && block->list[0]->is<Block>()) {
- block = block->list[0]->cast<Block>();
- stack.push_back(block);
+ Expression* curr = *currp;
+ switch (curr->_id) {
+ case Expression::Id::InvalidId: abort();
+ case Expression::Id::BlockId: {
+ self->pushTask(SubType::doVisitBlock, currp);
+ auto& list = curr->cast<Block>()->list;
+ for (int i = int(list.size()) - 1; i >= 0; i--) {
+ self->pushTask(SubType::scan, &list[i]);
+ }
+ break;
+ }
+ case Expression::Id::IfId: {
+ self->pushTask(SubType::doVisitIf, currp);
+ self->maybePushTask(SubType::scan, &curr->cast<If>()->ifFalse);
+ self->pushTask(SubType::scan, &curr->cast<If>()->ifTrue);
+ self->pushTask(SubType::scan, &curr->cast<If>()->condition);
+ break;
+ }
+ case Expression::Id::LoopId: {
+ self->pushTask(SubType::doVisitLoop, currp);
+ self->pushTask(SubType::scan, &curr->cast<Loop>()->body);
+ break;
+ }
+ case Expression::Id::BreakId: {
+ self->pushTask(SubType::doVisitBreak, currp);
+ self->maybePushTask(SubType::scan, &curr->cast<Break>()->condition);
+ self->maybePushTask(SubType::scan, &curr->cast<Break>()->value);
+ break;
+ }
+ case Expression::Id::SwitchId: {
+ self->pushTask(SubType::doVisitSwitch, currp);
+ self->maybePushTask(SubType::scan, &curr->cast<Switch>()->value);
+ self->pushTask(SubType::scan, &curr->cast<Switch>()->condition);
+ break;
+ }
+ case Expression::Id::CallId: {
+ self->pushTask(SubType::doVisitCall, currp);
+ auto& list = curr->cast<Call>()->operands;
+ for (int i = int(list.size()) - 1; i >= 0; i--) {
+ self->pushTask(SubType::scan, &list[i]);
+ }
+ break;
+ }
+ case Expression::Id::CallImportId: {
+ self->pushTask(SubType::doVisitCallImport, currp);
+ auto& list = curr->cast<CallImport>()->operands;
+ for (int i = int(list.size()) - 1; i >= 0; i--) {
+ self->pushTask(SubType::scan, &list[i]);
+ }
+ break;
+ }
+ case Expression::Id::CallIndirectId: {
+ self->pushTask(SubType::doVisitCallIndirect, currp);
+ auto& list = curr->cast<CallIndirect>()->operands;
+ for (int i = int(list.size()) - 1; i >= 0; i--) {
+ self->pushTask(SubType::scan, &list[i]);
+ }
+ self->pushTask(SubType::scan, &curr->cast<CallIndirect>()->target);
+ break;
+ }
+ case Expression::Id::GetLocalId: {
+ self->pushTask(SubType::doVisitGetLocal, currp); // TODO: optimize leaves with a direct call?
+ break;
+ }
+ case Expression::Id::SetLocalId: {
+ self->pushTask(SubType::doVisitSetLocal, currp);
+ self->pushTask(SubType::scan, &curr->cast<SetLocal>()->value);
+ break;
+ }
+ case Expression::Id::LoadId: {
+ self->pushTask(SubType::doVisitLoad, currp);
+ self->pushTask(SubType::scan, &curr->cast<Load>()->ptr);
+ break;
+ }
+ case Expression::Id::StoreId: {
+ self->pushTask(SubType::doVisitStore, currp);
+ self->pushTask(SubType::scan, &curr->cast<Store>()->value);
+ self->pushTask(SubType::scan, &curr->cast<Store>()->ptr);
+ break;
}
- // walk all the children
- for (int i = int(stack.size()) - 1; i >= 0; i--) {
- auto* block = stack[i];
- auto& children = block->list;
- for (size_t j = 0; j < children.size(); j++) {
- if (i < int(stack.size()) - 1 && j == 0) {
- // this is one of the stacked blocks, no need to walk its children, we are doing that ourselves
- WasmReplacerWalker<SubType, ReturnType>::walk(children[0]);
- } else {
- this->walk(children[j]);
- }
+ case Expression::Id::ConstId: {
+ self->pushTask(SubType::doVisitConst, currp);
+ break;
+ }
+ case Expression::Id::UnaryId: {
+ self->pushTask(SubType::doVisitUnary, currp);
+ self->pushTask(SubType::scan, &curr->cast<Unary>()->value);
+ break;
+ }
+ case Expression::Id::BinaryId: {
+ self->pushTask(SubType::doVisitBinary, currp);
+ self->pushTask(SubType::scan, &curr->cast<Binary>()->right);
+ self->pushTask(SubType::scan, &curr->cast<Binary>()->left);
+ break;
+ }
+ case Expression::Id::SelectId: {
+ self->pushTask(SubType::doVisitSelect, currp);
+ self->pushTask(SubType::scan, &curr->cast<Select>()->condition);
+ self->pushTask(SubType::scan, &curr->cast<Select>()->ifFalse);
+ self->pushTask(SubType::scan, &curr->cast<Select>()->ifTrue);
+ break;
+ }
+ case Expression::Id::ReturnId: {
+ self->pushTask(SubType::doVisitReturn, currp);
+ self->maybePushTask(SubType::scan, &curr->cast<Return>()->value);
+ break;
+ }
+ case Expression::Id::HostId: {
+ self->pushTask(SubType::doVisitHost, currp);
+ auto& list = curr->cast<Host>()->operands;
+ for (int i = int(list.size()) - 1; i >= 0; i--) {
+ self->pushTask(SubType::scan, &list[i]);
}
+ break;
+ }
+ case Expression::Id::NopId: {
+ self->pushTask(SubType::doVisitNop, currp);
+ break;
}
- // we walked all the children, and can rejoin later below to visit this node itself
- } else {
- // generic child-walking
- ChildWalker<WasmWalker<SubType, ReturnType>>(*this).visit(curr);
+ case Expression::Id::UnreachableId: {
+ self->pushTask(SubType::doVisitUnreachable, currp);
+ break;
+ }
+ default: WASM_UNREACHABLE();
}
-
- WasmReplacerWalker<SubType, ReturnType>::walk(curr);
}
};
@@ -350,111 +366,73 @@ struct WasmWalker : public WasmReplacerWalker<SubType, ReturnType> {
// to noteNonLinear().
template<typename SubType>
-struct FastExecutionWalker : public WasmReplacerWalker<SubType> {
- FastExecutionWalker() {}
+struct LinearExecutionWalker : public PostWalker<SubType> {
+ LinearExecutionWalker() {}
- void noteNonLinear() {}
+ // subclasses should implement this
+ void noteNonLinear() { abort(); }
-#define DELEGATE_noteNonLinear() \
- static_cast<SubType*>(this)->noteNonLinear()
-#define DELEGATE_walk(ARG) \
- static_cast<SubType*>(this)->walk(ARG)
-
- void visitBlock(Block *curr) {
- ExpressionList& list = curr->list;
- for (size_t z = 0; z < list.size(); z++) {
- DELEGATE_walk(list[z]);
- }
- }
- void visitIf(If *curr) {
- DELEGATE_walk(curr->condition);
- DELEGATE_noteNonLinear();
- DELEGATE_walk(curr->ifTrue);
- DELEGATE_noteNonLinear();
- DELEGATE_walk(curr->ifFalse);
- DELEGATE_noteNonLinear();
- }
- void visitLoop(Loop *curr) {
- DELEGATE_noteNonLinear();
- DELEGATE_walk(curr->body);
- }
- void visitBreak(Break *curr) {
- if (curr->value) DELEGATE_walk(curr->value);
- if (curr->condition) DELEGATE_walk(curr->condition);
- DELEGATE_noteNonLinear();
- }
- void visitSwitch(Switch *curr) {
- DELEGATE_walk(curr->condition);
- if (curr->value) DELEGATE_walk(curr->value);
- DELEGATE_noteNonLinear();
- }
- void visitCall(Call *curr) {
- ExpressionList& list = curr->operands;
- for (size_t z = 0; z < list.size(); z++) {
- DELEGATE_walk(list[z]);
- }
- }
- void visitCallImport(CallImport *curr) {
- ExpressionList& list = curr->operands;
- for (size_t z = 0; z < list.size(); z++) {
- DELEGATE_walk(list[z]);
- }
- }
- void visitCallIndirect(CallIndirect *curr) {
- DELEGATE_walk(curr->target);
- ExpressionList& list = curr->operands;
- for (size_t z = 0; z < list.size(); z++) {
- DELEGATE_walk(list[z]);
- }
+ static void doNoteNonLinear(SubType* self, Expression** currp) {
+ self->noteNonLinear();
}
- void visitGetLocal(GetLocal *curr) {}
- void visitSetLocal(SetLocal *curr) {
- DELEGATE_walk(curr->value);
- }
- void visitLoad(Load *curr) {
- DELEGATE_walk(curr->ptr);
- }
- void visitStore(Store *curr) {
- DELEGATE_walk(curr->ptr);
- DELEGATE_walk(curr->value);
- }
- void visitConst(Const *curr) {}
- void visitUnary(Unary *curr) {
- DELEGATE_walk(curr->value);
- }
- void visitBinary(Binary *curr) {
- DELEGATE_walk(curr->left);
- DELEGATE_walk(curr->right);
- }
- void visitSelect(Select *curr) {
- DELEGATE_walk(curr->ifTrue);
- DELEGATE_walk(curr->ifFalse);
- DELEGATE_walk(curr->condition);
- }
- void visitReturn(Return *curr) {
- DELEGATE_walk(curr->value);
- DELEGATE_noteNonLinear();
- }
- void visitHost(Host *curr) {
- ExpressionList& list = curr->operands;
- for (size_t z = 0; z < list.size(); z++) {
- DELEGATE_walk(list[z]);
- }
- }
- void visitNop(Nop *curr) {}
- void visitUnreachable(Unreachable *curr) {}
- void visitFunctionType(FunctionType *curr) {}
- void visitImport(Import *curr) {}
- void visitExport(Export *curr) {}
- void visitFunction(Function *curr) {}
- void visitTable(Table *curr) {}
- void visitMemory(Memory *curr) {}
- void visitModule(Module *curr) {}
+ static void scan(SubType* self, Expression** currp) {
-#undef DELEGATE_noteNonLinear
-#undef DELEGATE_walk
+ Expression* curr = *currp;
+ switch (curr->_id) {
+ case Expression::Id::InvalidId: abort();
+ case Expression::Id::BlockId: {
+ self->pushTask(SubType::doVisitBlock, currp);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ auto& list = curr->cast<Block>()->list;
+ for (int i = int(list.size()) - 1; i >= 0; i--) {
+ self->pushTask(SubType::scan, &list[i]);
+ }
+ break;
+ }
+ case Expression::Id::IfId: {
+ self->pushTask(SubType::doVisitIf, currp);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->maybePushTask(SubType::scan, &curr->cast<If>()->ifFalse);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->pushTask(SubType::scan, &curr->cast<If>()->ifTrue);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->pushTask(SubType::scan, &curr->cast<If>()->condition);
+ break;
+ }
+ case Expression::Id::LoopId: {
+ self->pushTask(SubType::doVisitLoop, currp);
+ self->pushTask(SubType::scan, &curr->cast<Loop>()->body);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ break;
+ }
+ case Expression::Id::BreakId: {
+ self->pushTask(SubType::doVisitBreak, currp);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->maybePushTask(SubType::scan, &curr->cast<Break>()->condition);
+ self->maybePushTask(SubType::scan, &curr->cast<Break>()->value);
+ break;
+ }
+ case Expression::Id::SwitchId: {
+ self->pushTask(SubType::doVisitSwitch, currp);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->maybePushTask(SubType::scan, &curr->cast<Switch>()->value);
+ self->pushTask(SubType::scan, &curr->cast<Switch>()->condition);
+ break;
+ }
+ case Expression::Id::ReturnId: {
+ self->pushTask(SubType::doVisitReturn, currp);
+ self->pushTask(SubType::doNoteNonLinear, currp);
+ self->maybePushTask(SubType::scan, &curr->cast<Return>()->value);
+ break;
+ }
+ default: {
+ // other node types do not have control flow, use regular post-order
+ PostWalker<SubType>::scan(self, currp);
+ }
+ }
+ }
};
} // namespace wasm