summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2016-01-08 15:05:46 -0800
committerAlon Zakai <alonzakai@gmail.com>2016-01-08 15:05:46 -0800
commit382ea607d99c73a6e893f4f92b0b63bde698e487 (patch)
treee284f4acd600e141679540b5b1f1f8e8de04f293 /src
parenta695f82586d452dfc7ba51c18a5b76aa0cd8fb22 (diff)
downloadbinaryen-382ea607d99c73a6e893f4f92b0b63bde698e487.tar.gz
binaryen-382ea607d99c73a6e893f4f92b0b63bde698e487.tar.bz2
binaryen-382ea607d99c73a6e893f4f92b0b63bde698e487.zip
improve RemoveUnusedBrs: unify an if-else's brs into one br outside
Diffstat (limited to 'src')
-rw-r--r--src/passes/RemoveUnusedBrs.cpp63
1 files changed, 39 insertions, 24 deletions
diff --git a/src/passes/RemoveUnusedBrs.cpp b/src/passes/RemoveUnusedBrs.cpp
index 0ff48381f..a89c69312 100644
--- a/src/passes/RemoveUnusedBrs.cpp
+++ b/src/passes/RemoveUnusedBrs.cpp
@@ -24,6 +24,45 @@
namespace wasm {
struct RemoveUnusedBrs : public Pass {
+ // preparation: try to unify branches, as the fewer there are, the higher a chance we can remove them
+ // specifically for if-else, turn an if-else with branches to the same target at the end of each
+ // child, and with a value, to a branch to that target containing the if-else
+ void visitIf(If* curr) override {
+ if (!curr->ifFalse) return;
+ if (curr->type != none) return; // already has a returned value
+ // an if_else that indirectly returns a value by breaking to the same target can potentially remove both breaks, and break outside once
+ auto getLast = [](Expression *side) -> Expression* {
+ Block* b = side->dyn_cast<Block>();
+ if (!b) return nullptr;
+ if (b->list.size() == 0) return nullptr;
+ return b->list.back();
+ };
+ auto process = [&](Expression *side, bool doIt) {
+ Expression* last = getLast(side);
+ if (!last) return Name();
+ Block* b = side->cast<Block>();
+ Break* br = last->dyn_cast<Break>();
+ if (!br) return Name();
+ if (br->condition) return Name();
+ if (!br->value) return Name();
+ if (doIt) {
+ b->list[b->list.size()-1] = br->value;
+ }
+ return br->name;
+ };
+ // do both, or none
+ if (process(curr->ifTrue, false).is() && process(curr->ifTrue, false) == process(curr->ifFalse, false)) {
+ auto br = getLast(curr->ifTrue)->cast<Break>(); // we are about to discard this, so why not reuse it!
+ process(curr->ifTrue, true);
+ process(curr->ifFalse, true);
+ curr->type = br->value->type; // if_else now returns a value
+ br->value = curr;
+ // no need to change anything else in the br - target is correct already
+ replaceCurrent(br);
+ }
+ }
+
+ // main portion
void visitBlock(Block *curr) override {
if (curr->name.isNull()) return;
if (curr->list.size() == 0) return;
@@ -37,30 +76,6 @@ struct RemoveUnusedBrs : public Pass {
curr->list[curr->list.size()-1] = br->value; // can replace with the value
}
}
- } else if (If* ifelse = curr->list.back()->dyn_cast<If>()) {
- if (!ifelse->ifFalse) return;
- if (ifelse->type != none) return;
- // an if_else that indirectly returns a value by breaking to this block can potentially remove both breaks
- auto process = [&curr](Expression *side, bool doIt) {
- Block* b = side->dyn_cast<Block>();
- if (!b) return false;
- Expression* last = b->list.back();
- Break* br = last->dyn_cast<Break>();
- if (!br) return false;
- if (br->condition) return false;
- if (!br->value) return false;
- if (br->name != curr->name) return false;
- if (doIt) {
- b->list[b->list.size()-1] = br->value;
- }
- return true;
- };
- // do both, or none
- if (process(ifelse->ifTrue, false) && process(ifelse->ifFalse, false)) {
- process(ifelse->ifTrue, true);
- process(ifelse->ifFalse, true);
- ifelse->type = curr->type; // if_else now returns a value
- }
}
}
};