Skip to content

Optimize stack writer on deeply nested blocks, fixes #1903 #1905

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 12, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 55 additions & 43 deletions src/wasm-stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -359,24 +359,62 @@ void StackWriter<Mode, Parent>::visitChild(Expression* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitBlock(Block* curr) {
if (Mode == StackWriterMode::Binaryen2Stack) {
stackIR.push_back(makeStackInst(StackInst::BlockBegin, curr));
} else {
if (debug) std::cerr << "zz node: Block" << std::endl;
o << int8_t(BinaryConsts::Block);
o << binaryType(curr->type != unreachable ? curr->type : none);
}
breakStack.push_back(curr->name); // TODO: we don't need to do this in Binaryen2Stack
Index i = 0;
for (auto* child : curr->list) {
if (debug) std::cerr << " " << size_t(curr) << "\n zz Block element " << i++ << std::endl;
visitChild(child);
}
// in Stack2Binary the block ending is in the stream later on
if (Mode == StackWriterMode::Stack2Binary) {
return;
auto tilChildren = [this](Block* curr) {
if (Mode == StackWriterMode::Binaryen2Stack) {
stackIR.push_back(makeStackInst(StackInst::BlockBegin, curr));
} else {
o << int8_t(BinaryConsts::Block);
o << binaryType(curr->type != unreachable ? curr->type : none);
}
breakStack.push_back(curr->name); // TODO: we don't need to do this in Binaryen2Stack
};
auto visitChildren = [this](Block* curr, Index from) {
auto& list = curr->list;
while (from < list.size()) {
visitChild(list[from++]);
}
};
auto afterChildren = [this](Block* curr) {
// in Stack2Binary the block ending is in the stream later on
if (Mode != StackWriterMode::Stack2Binary) {
visitBlockEnd(curr);
}
};
// Handle very deeply nested blocks in the first position efficiently,
// avoiding heavy recursion.
// We only start to do this if we see it will help us (to avoid allocation
// of the vector).
// Note that Stack2Binary mode we don't need to visit children anyhow, so
// we don't need this optimization.
if (Mode != StackWriterMode::Stack2Binary) {
if (!curr->list.empty() && curr->list[0]->is<Block>()) {
std::vector<Block*> parents;
Block* child;
while (!curr->list.empty() &&
(child = curr->list[0]->dynCast<Block>())) {
parents.push_back(curr);
tilChildren(curr);
curr = child;
}
// Emit the current block, which does not have a block as
// a child in the first position.
tilChildren(curr);
visitChildren(curr, 0);
afterChildren(curr);
// Finish the later parts of all the parent blocks.
while (!parents.empty()) {
auto* parent = parents.back();
parents.pop_back();
visitChildren(parent, 1);
afterChildren(parent);
}
return;
}
}
visitBlockEnd(curr);
// Simple case of not having a nested block in the first position.
tilChildren(curr);
visitChildren(curr, 0);
afterChildren(curr);
}

template<StackWriterMode Mode, typename Parent>
Expand All @@ -403,7 +441,6 @@ void StackWriter<Mode, Parent>::visitBlockEnd(Block* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitIf(If* curr) {
if (debug) std::cerr << "zz node: If" << std::endl;
if (curr->condition->type == unreachable) {
// this if-else is unreachable because of the condition, i.e., the condition
// does not exit. So don't emit the if, but do consume the condition
Expand Down Expand Up @@ -465,7 +502,6 @@ void StackWriter<Mode, Parent>::visitIfEnd(If* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitLoop(Loop* curr) {
if (debug) std::cerr << "zz node: Loop" << std::endl;
if (Mode == StackWriterMode::Binaryen2Stack) {
stackIR.push_back(makeStackInst(StackInst::LoopBegin, curr));
} else {
Expand Down Expand Up @@ -502,7 +538,6 @@ void StackWriter<Mode, Parent>::visitLoopEnd(Loop* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitBreak(Break* curr) {
if (debug) std::cerr << "zz node: Break" << std::endl;
if (curr->value) {
visitChild(curr->value);
}
Expand All @@ -525,7 +560,6 @@ void StackWriter<Mode, Parent>::visitBreak(Break* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSwitch(Switch* curr) {
if (debug) std::cerr << "zz node: Switch" << std::endl;
if (curr->value) {
visitChild(curr->value);
}
Expand All @@ -547,7 +581,6 @@ void StackWriter<Mode, Parent>::visitSwitch(Switch* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitCall(Call* curr) {
if (debug) std::cerr << "zz node: Call" << std::endl;
for (auto* operand : curr->operands) {
visitChild(operand);
}
Expand All @@ -561,7 +594,6 @@ void StackWriter<Mode, Parent>::visitCall(Call* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitCallIndirect(CallIndirect* curr) {
if (debug) std::cerr << "zz node: CallIndirect" << std::endl;
for (auto* operand : curr->operands) {
visitChild(operand);
}
Expand All @@ -578,14 +610,12 @@ void StackWriter<Mode, Parent>::visitCallIndirect(CallIndirect* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitGetLocal(GetLocal* curr) {
if (debug) std::cerr << "zz node: GetLocal " << (o.size() + 1) << std::endl;
if (justAddToStack(curr)) return;
o << int8_t(BinaryConsts::GetLocal) << U32LEB(mappedLocals[curr->index]);
}

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSetLocal(SetLocal* curr) {
if (debug) std::cerr << "zz node: Set|TeeLocal" << std::endl;
visitChild(curr->value);
if (!justAddToStack(curr)) {
o << int8_t(curr->isTee() ? BinaryConsts::TeeLocal : BinaryConsts::SetLocal) << U32LEB(mappedLocals[curr->index]);
Expand All @@ -597,22 +627,19 @@ void StackWriter<Mode, Parent>::visitSetLocal(SetLocal* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitGetGlobal(GetGlobal* curr) {
if (debug) std::cerr << "zz node: GetGlobal " << (o.size() + 1) << std::endl;
if (justAddToStack(curr)) return;
o << int8_t(BinaryConsts::GetGlobal) << U32LEB(parent.getGlobalIndex(curr->name));
}

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSetGlobal(SetGlobal* curr) {
if (debug) std::cerr << "zz node: SetGlobal" << std::endl;
visitChild(curr->value);
if (justAddToStack(curr)) return;
o << int8_t(BinaryConsts::SetGlobal) << U32LEB(parent.getGlobalIndex(curr->name));
}

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitLoad(Load* curr) {
if (debug) std::cerr << "zz node: Load" << std::endl;
visitChild(curr->ptr);
if (curr->type == unreachable) {
// don't even emit it; we don't know the right type
Expand Down Expand Up @@ -678,7 +705,6 @@ void StackWriter<Mode, Parent>::visitLoad(Load* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitStore(Store* curr) {
if (debug) std::cerr << "zz node: Store" << std::endl;
visitChild(curr->ptr);
visitChild(curr->value);
if (curr->type == unreachable) {
Expand Down Expand Up @@ -744,7 +770,6 @@ void StackWriter<Mode, Parent>::visitStore(Store* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitAtomicRMW(AtomicRMW* curr) {
if (debug) std::cerr << "zz node: AtomicRMW" << std::endl;
visitChild(curr->ptr);
// stop if the rest isn't reachable anyhow
if (curr->ptr->type == unreachable) return;
Expand Down Expand Up @@ -799,7 +824,6 @@ void StackWriter<Mode, Parent>::visitAtomicRMW(AtomicRMW* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitAtomicCmpxchg(AtomicCmpxchg* curr) {
if (debug) std::cerr << "zz node: AtomicCmpxchg" << std::endl;
visitChild(curr->ptr);
// stop if the rest isn't reachable anyhow
if (curr->ptr->type == unreachable) return;
Expand Down Expand Up @@ -840,7 +864,6 @@ void StackWriter<Mode, Parent>::visitAtomicCmpxchg(AtomicCmpxchg* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitAtomicWait(AtomicWait* curr) {
if (debug) std::cerr << "zz node: AtomicWait" << std::endl;
visitChild(curr->ptr);
// stop if the rest isn't reachable anyhow
if (curr->ptr->type == unreachable) return;
Expand Down Expand Up @@ -868,7 +891,6 @@ void StackWriter<Mode, Parent>::visitAtomicWait(AtomicWait* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitAtomicWake(AtomicWake* curr) {
if (debug) std::cerr << "zz node: AtomicWake" << std::endl;
visitChild(curr->ptr);
// stop if the rest isn't reachable anyhow
if (curr->ptr->type == unreachable) return;
Expand Down Expand Up @@ -1001,7 +1023,6 @@ void StackWriter<Mode, Parent>::visitMemoryFill(MemoryFill* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitConst(Const* curr) {
if (debug) std::cerr << "zz node: Const" << curr << " : " << curr->type << std::endl;
if (justAddToStack(curr)) return;
switch (curr->type) {
case i32: {
Expand Down Expand Up @@ -1032,12 +1053,10 @@ void StackWriter<Mode, Parent>::visitConst(Const* curr) {
case unreachable:
WASM_UNREACHABLE();
}
if (debug) std::cerr << "zz const node done.\n";
}

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitUnary(Unary* curr) {
if (debug) std::cerr << "zz node: Unary" << std::endl;
visitChild(curr->value);
if (curr->type == unreachable) {
emitExtraUnreachable();
Expand Down Expand Up @@ -1144,7 +1163,6 @@ void StackWriter<Mode, Parent>::visitUnary(Unary* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitBinary(Binary* curr) {
if (debug) std::cerr << "zz node: Binary" << std::endl;
visitChild(curr->left);
visitChild(curr->right);
if (curr->type == unreachable) {
Expand Down Expand Up @@ -1317,7 +1335,6 @@ void StackWriter<Mode, Parent>::visitBinary(Binary* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitSelect(Select* curr) {
if (debug) std::cerr << "zz node: Select" << std::endl;
visitChild(curr->ifTrue);
visitChild(curr->ifFalse);
visitChild(curr->condition);
Expand All @@ -1331,7 +1348,6 @@ void StackWriter<Mode, Parent>::visitSelect(Select* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitReturn(Return* curr) {
if (debug) std::cerr << "zz node: Return" << std::endl;
if (curr->value) {
visitChild(curr->value);
}
Expand All @@ -1342,7 +1358,6 @@ void StackWriter<Mode, Parent>::visitReturn(Return* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitHost(Host* curr) {
if (debug) std::cerr << "zz node: Host" << std::endl;
switch (curr->op) {
case CurrentMemory: {
break;
Expand All @@ -1368,21 +1383,18 @@ void StackWriter<Mode, Parent>::visitHost(Host* curr) {

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitNop(Nop* curr) {
if (debug) std::cerr << "zz node: Nop" << std::endl;
if (justAddToStack(curr)) return;
o << int8_t(BinaryConsts::Nop);
}

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitUnreachable(Unreachable* curr) {
if (debug) std::cerr << "zz node: Unreachable" << std::endl;
if (justAddToStack(curr)) return;
o << int8_t(BinaryConsts::Unreachable);
}

template<StackWriterMode Mode, typename Parent>
void StackWriter<Mode, Parent>::visitDrop(Drop* curr) {
if (debug) std::cerr << "zz node: Drop" << std::endl;
visitChild(curr->value);
if (justAddToStack(curr)) return;
o << int8_t(BinaryConsts::Drop);
Expand Down