summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2018-11-15 13:43:49 -0800
committerGitHub <noreply@github.com>2018-11-15 13:43:49 -0800
commit991bd336973702b4996237fc4610ad52af6718a1 (patch)
tree0105d52f5149042aad59415bddc2ae765f698536 /src
parentec16a4d076d290f892fc00f598777631cdda5f09 (diff)
downloadbinaryen-991bd336973702b4996237fc4610ad52af6718a1.tar.gz
binaryen-991bd336973702b4996237fc4610ad52af6718a1.tar.bz2
binaryen-991bd336973702b4996237fc4610ad52af6718a1.zip
Optimize an if exit block into an if arm (#1749)
If an if is enclosed in a block which is only used to exit one arm, move it into that arm, so it can be better optimized. Similar to what we did for loops in #1736.
Diffstat (limited to 'src')
-rw-r--r--src/asm2wasm.h1
-rw-r--r--src/passes/MergeBlocks.cpp41
2 files changed, 41 insertions, 1 deletions
diff --git a/src/asm2wasm.h b/src/asm2wasm.h
index ebd740841..d143239cc 100644
--- a/src/asm2wasm.h
+++ b/src/asm2wasm.h
@@ -1458,6 +1458,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
// autodrop can add some garbage
passRunner.add("vacuum");
passRunner.add("remove-unused-brs");
+ passRunner.add("remove-unused-names");
passRunner.add("merge-blocks");
passRunner.add("optimize-instructions");
passRunner.add("post-emscripten");
diff --git a/src/passes/MergeBlocks.cpp b/src/passes/MergeBlocks.cpp
index accb16395..4999fd234 100644
--- a/src/passes/MergeBlocks.cpp
+++ b/src/passes/MergeBlocks.cpp
@@ -338,6 +338,24 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
// If the block has a single child which is a loop, and the block is named,
// then it is the exit for the loop. It's better to move it into the loop,
// where it can be better optimized by other passes.
+ // Similar logic for ifs: if the block is an exit for the if, we can
+ // move the block in, consider for example:
+ // (block $label
+ // (if (..condition1..)
+ // (block
+ // (br_if $label (..condition2..))
+ // (..code..)
+ // )
+ // )
+ // )
+ // After also merging the blocks, we have
+ // (if (..condition1..)
+ // (block $label
+ // (br_if $label (..condition2..))
+ // (..code..)
+ // )
+ // )
+ // which can be further optimized by other passes.
if (curr->name.is() && curr->list.size() == 1) {
if (auto* loop = curr->list[0]->dynCast<Loop>()) {
curr->list[0] = loop->body;
@@ -348,8 +366,29 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
// After the flip, the outer type must be the same
assert(loop->type == oldOuterType);
replaceCurrent(loop);
- // Fall through to optimize the block, which has a new child now.
+ } else if (auto* iff = curr->list[0]->dynCast<If>()) {
+ // The label can't be used in the condition.
+ if (BranchUtils::BranchSeeker::countNamed(iff->condition, curr->name) == 0) {
+ // We can move the block into either arm, if there are no uses in the other.
+ Expression** target = nullptr;
+ if (!iff->ifFalse ||
+ BranchUtils::BranchSeeker::countNamed(iff->ifFalse, curr->name) == 0) {
+ target = &iff->ifTrue;
+ } else if (BranchUtils::BranchSeeker::countNamed(iff->ifTrue, curr->name) == 0) {
+ target = &iff->ifFalse;
+ }
+ if (target) {
+ curr->list[0] = *target;
+ *target = curr;
+ curr->finalize(curr->type);
+ iff->finalize();
+ replaceCurrent(iff);
+ // Note that the type might change, e.g. if the if condition is unreachable
+ // but the block that was on the outside had a break.
+ }
+ }
}
+ // Always fall through to optimize the block, which has a new child now.
}
// Otherwise, do the main merging optimizations.
optimizeBlock(curr, getModule(), getPassOptions());