@@ -102,9 +102,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
102102 // if without else stops the flow of values
103103 self->stopValueFlow ();
104104 }
105- } else if (curr->is <Block>()) {
105+ } else if (auto * block = curr->dynCast <Block>()) {
106106 // any breaks flowing to here are unnecessary, as we get here anyhow
107- auto * block = curr->cast <Block>();
108107 auto name = block->name ;
109108 if (name.is ()) {
110109 size_t size = flows.size ();
@@ -436,6 +435,76 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
436435 }
437436 }
438437
438+ void sinkBlocks (Function* func) {
439+ struct Sinker : public PostWalker <Sinker> {
440+ bool worked = false ;
441+
442+ void visitBlock (Block* curr) {
443+ // If the block has a single child which is a loop, and the block is named,
444+ // then it is the exit for the loop. It's better to move it into the loop,
445+ // where it can be better optimized by other passes.
446+ // Similar logic for ifs: if the block is an exit for the if, we can
447+ // move the block in, consider for example:
448+ // (block $label
449+ // (if (..condition1..)
450+ // (block
451+ // (br_if $label (..condition2..))
452+ // (..code..)
453+ // )
454+ // )
455+ // )
456+ // After also merging the blocks, we have
457+ // (if (..condition1..)
458+ // (block $label
459+ // (br_if $label (..condition2..))
460+ // (..code..)
461+ // )
462+ // )
463+ // which can be further optimized later.
464+ if (curr->name .is () && curr->list .size () == 1 ) {
465+ if (auto * loop = curr->list [0 ]->dynCast <Loop>()) {
466+ curr->list [0 ] = loop->body ;
467+ loop->body = curr;
468+ curr->finalize (curr->type );
469+ loop->finalize ();
470+ replaceCurrent (loop);
471+ worked = true ;
472+ } else if (auto * iff = curr->list [0 ]->dynCast <If>()) {
473+ // The label can't be used in the condition.
474+ if (BranchUtils::BranchSeeker::countNamed (iff->condition , curr->name ) == 0 ) {
475+ // We can move the block into either arm, if there are no uses in the other.
476+ Expression** target = nullptr ;
477+ if (!iff->ifFalse ||
478+ BranchUtils::BranchSeeker::countNamed (iff->ifFalse , curr->name ) == 0 ) {
479+ target = &iff->ifTrue ;
480+ } else if (BranchUtils::BranchSeeker::countNamed (iff->ifTrue , curr->name ) == 0 ) {
481+ target = &iff->ifFalse ;
482+ }
483+ if (target) {
484+ curr->list [0 ] = *target;
485+ *target = curr;
486+ // The block used to contain the if, and may have changed type from unreachable
487+ // to none, for example, if the if has an unreachable condition but the arm
488+ // is not unreachable.
489+ curr->finalize ();
490+ iff->finalize ();
491+ replaceCurrent (iff);
492+ worked = true ;
493+ // Note that the type might change, e.g. if the if condition is unreachable
494+ // but the block that was on the outside had a break.
495+ }
496+ }
497+ }
498+ }
499+ }
500+ } sinker;
501+
502+ sinker.doWalkFunction (func);
503+ if (sinker.worked ) {
504+ anotherCycle = true ;
505+ }
506+ }
507+
439508 void doWalkFunction (Function* func) {
440509 // multiple cycles may be needed
441510 bool worked = false ;
@@ -463,6 +532,8 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
463532 anotherCycle |= optimizeLoop (loop);
464533 }
465534 loops.clear ();
535+ // sink blocks
536+ sinkBlocks (func);
466537 if (anotherCycle) worked = true ;
467538 } while (anotherCycle);
468539
0 commit comments