Skip to content

Commit 991bd33

Browse files
authored
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.
1 parent ec16a4d commit 991bd33

18 files changed

+51596
-51994
lines changed

src/asm2wasm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,7 @@ void Asm2WasmBuilder::processAsm(Ref ast) {
14581458
// autodrop can add some garbage
14591459
passRunner.add("vacuum");
14601460
passRunner.add("remove-unused-brs");
1461+
passRunner.add("remove-unused-names");
14611462
passRunner.add("merge-blocks");
14621463
passRunner.add("optimize-instructions");
14631464
passRunner.add("post-emscripten");

src/passes/MergeBlocks.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,24 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
338338
// If the block has a single child which is a loop, and the block is named,
339339
// then it is the exit for the loop. It's better to move it into the loop,
340340
// where it can be better optimized by other passes.
341+
// Similar logic for ifs: if the block is an exit for the if, we can
342+
// move the block in, consider for example:
343+
// (block $label
344+
// (if (..condition1..)
345+
// (block
346+
// (br_if $label (..condition2..))
347+
// (..code..)
348+
// )
349+
// )
350+
// )
351+
// After also merging the blocks, we have
352+
// (if (..condition1..)
353+
// (block $label
354+
// (br_if $label (..condition2..))
355+
// (..code..)
356+
// )
357+
// )
358+
// which can be further optimized by other passes.
341359
if (curr->name.is() && curr->list.size() == 1) {
342360
if (auto* loop = curr->list[0]->dynCast<Loop>()) {
343361
curr->list[0] = loop->body;
@@ -348,8 +366,29 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
348366
// After the flip, the outer type must be the same
349367
assert(loop->type == oldOuterType);
350368
replaceCurrent(loop);
351-
// Fall through to optimize the block, which has a new child now.
369+
} else if (auto* iff = curr->list[0]->dynCast<If>()) {
370+
// The label can't be used in the condition.
371+
if (BranchUtils::BranchSeeker::countNamed(iff->condition, curr->name) == 0) {
372+
// We can move the block into either arm, if there are no uses in the other.
373+
Expression** target = nullptr;
374+
if (!iff->ifFalse ||
375+
BranchUtils::BranchSeeker::countNamed(iff->ifFalse, curr->name) == 0) {
376+
target = &iff->ifTrue;
377+
} else if (BranchUtils::BranchSeeker::countNamed(iff->ifTrue, curr->name) == 0) {
378+
target = &iff->ifFalse;
379+
}
380+
if (target) {
381+
curr->list[0] = *target;
382+
*target = curr;
383+
curr->finalize(curr->type);
384+
iff->finalize();
385+
replaceCurrent(iff);
386+
// Note that the type might change, e.g. if the if condition is unreachable
387+
// but the block that was on the outside had a break.
388+
}
389+
}
352390
}
391+
// Always fall through to optimize the block, which has a new child now.
353392
}
354393
// Otherwise, do the main merging optimizations.
355394
optimizeBlock(curr, getModule(), getPassOptions());

0 commit comments

Comments
 (0)