summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-07-20 20:05:28 -0700
committerAlon Zakai <alonzakai@gmail.com>2016-07-20 20:05:28 -0700
commitfa60ade30e03c6a13bbce26ff81c03ed1ae4da0b (patch)
treed45b2b08645ac004645dde875d22d1c66b15187d /src
parent56901f8cb6fb6db4622937479d3a375744289ff0 (diff)
downloadbinaryen-fa60ade30e03c6a13bbce26ff81c03ed1ae4da0b.tar.gz
binaryen-fa60ade30e03c6a13bbce26ff81c03ed1ae4da0b.tar.bz2
binaryen-fa60ade30e03c6a13bbce26ff81c03ed1ae4da0b.zip
more RemoveUnusedName opts: merge names when possible, and do block/loop merging based on their names
Diffstat (limited to 'src')
-rw-r--r--src/passes/RemoveUnusedNames.cpp47
1 files changed, 42 insertions, 5 deletions
diff --git a/src/passes/RemoveUnusedNames.cpp b/src/passes/RemoveUnusedNames.cpp
index 5145cc744..9c6743479 100644
--- a/src/passes/RemoveUnusedNames.cpp
+++ b/src/passes/RemoveUnusedNames.cpp
@@ -15,7 +15,8 @@
*/
//
-// Removes names from locations that are never branched to.
+// Removes names from locations that are never branched to, and
+// merge names when possible (by merging their blocks)
//
#include <wasm.h>
@@ -30,17 +31,17 @@ struct RemoveUnusedNames : public WalkerPass<PostWalker<RemoveUnusedNames, Visit
// We maintain a list of branches that we saw in children, then when we reach
// a parent block, we know if it was branched to
- std::set<Name> branchesSeen;
+ std::map<Name, std::set<Expression*>> branchesSeen;
void visitBreak(Break *curr) {
- branchesSeen.insert(curr->name);
+ branchesSeen[curr->name].insert(curr);
}
void visitSwitch(Switch *curr) {
for (auto name : curr->targets) {
- branchesSeen.insert(name);
+ branchesSeen[name].insert(curr);
}
- branchesSeen.insert(curr->default_);
+ branchesSeen[curr->default_].insert(curr);
}
void handleBreakTarget(Name& name) {
@@ -54,7 +55,35 @@ struct RemoveUnusedNames : public WalkerPass<PostWalker<RemoveUnusedNames, Visit
}
void visitBlock(Block *curr) {
+ if (curr->name.is() && curr->list.size() == 1) {
+ auto* child = curr->list[0]->dynCast<Block>();
+ if (child && child->name.is()) {
+ // we have just one child, this block, so breaking out of it goes to the same place as breaking out of us, we just need one name (and block)
+ auto& branches = branchesSeen[curr->name];
+ for (auto* branch : branches) {
+ if (Break* br = branch->dynCast<Break>()) {
+ if (br->name == curr->name) br->name = child->name;
+ } else if (Switch* sw = branch->dynCast<Switch>()) {
+ for (auto& target : sw->targets) {
+ if (target == curr->name) target = child->name;
+ }
+ if (sw->default_ == curr->name) sw->default_ = child->name;
+ } else {
+ WASM_UNREACHABLE();
+ }
+ }
+ replaceCurrent(child);
+ }
+ }
handleBreakTarget(curr->name);
+ if (curr->name.is() && curr->list.size() == 1) {
+ auto* child = curr->list[0]->dynCast<Loop>();
+ if (child && !child->out.is()) {
+ // we have just one child, this loop, and it lacks an out label. So this block's name is doing just that!
+ child->out = curr->name;
+ replaceCurrent(child);
+ }
+ }
}
void visitLoop(Loop *curr) {
@@ -68,6 +97,14 @@ struct RemoveUnusedNames : public WalkerPass<PostWalker<RemoveUnusedNames, Visit
block->list.push_back(curr->body);
replaceCurrent(block);
}
+ if (curr->in.is() && !curr->out.is()) {
+ auto* child = curr->body->dynCast<Block>();
+ if (child && child->name.is()) {
+ // we have just one child, this block, and we lack an out label. So we can take the block's!
+ curr->out = child->name;
+ child->name = Name();
+ }
+ }
}
void visitFunction(Function *curr) {