diff options
author | Alon Zakai <alonzakai@gmail.com> | 2018-11-15 13:43:49 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-15 13:43:49 -0800 |
commit | 991bd336973702b4996237fc4610ad52af6718a1 (patch) | |
tree | 0105d52f5149042aad59415bddc2ae765f698536 /src | |
parent | ec16a4d076d290f892fc00f598777631cdda5f09 (diff) | |
download | binaryen-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.h | 1 | ||||
-rw-r--r-- | src/passes/MergeBlocks.cpp | 41 |
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()); |