@@ -435,7 +435,7 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
435435 }
436436 }
437437
438- void sinkBlocks (Function* func) {
438+ bool sinkBlocks (Function* func) {
439439 struct Sinker : public PostWalker <Sinker> {
440440 bool worked = false ;
441441
@@ -501,13 +501,14 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
501501
502502 sinker.doWalkFunction (func);
503503 if (sinker.worked ) {
504- anotherCycle = true ;
504+ ReFinalize ().walkFunctionInModule (func, getModule ());
505+ return true ;
505506 }
507+ return false ;
506508 }
507509
508510 void doWalkFunction (Function* func) {
509511 // multiple cycles may be needed
510- bool worked = false ;
511512 do {
512513 anotherCycle = false ;
513514 super::doWalkFunction (func);
@@ -532,32 +533,39 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
532533 anotherCycle |= optimizeLoop (loop);
533534 }
534535 loops.clear ();
536+ if (anotherCycle) {
537+ ReFinalize ().walkFunctionInModule (func, getModule ());
538+ }
535539 // sink blocks
536- sinkBlocks (func);
537- if (anotherCycle) worked = true ;
540+ if (sinkBlocks (func)) {
541+ anotherCycle = true ;
542+ }
538543 } while (anotherCycle);
539544
540- if (worked) {
541- // Our work may alter block and if types, they may now return values that we made flow through them
542- ReFinalize ().walkFunctionInModule (func, getModule ());
543- }
544-
545545 // thread trivial jumps
546546 struct JumpThreader : public ControlFlowWalker <JumpThreader> {
547- // map of all value-less breaks going to a block (and not a loop)
548- std::map<Block*, std::vector<Break *>> breaksToBlock ;
547+ // map of all value-less breaks and switches going to a block (and not a loop)
548+ std::map<Block*, std::vector<Expression *>> branchesToBlock ;
549549
550- // the names to update
551- std::map<Break*, Name> newNames;
550+ bool worked = false ;
552551
553552 void visitBreak (Break* curr) {
554553 if (!curr->value ) {
555554 if (auto * target = findBreakTarget (curr->name )->dynCast <Block>()) {
556- breaksToBlock[target].push_back (curr);
555+ branchesToBlock[target].push_back (curr);
556+ }
557+ }
558+ }
559+ void visitSwitch (Switch* curr) {
560+ if (!curr->value ) {
561+ auto names = BranchUtils::getUniqueTargets (curr);
562+ for (auto name : names) {
563+ if (auto * target = findBreakTarget (name)->dynCast <Block>()) {
564+ branchesToBlock[target].push_back (curr);
565+ }
557566 }
558567 }
559568 }
560- // TODO: Switch?
561569 void visitBlock (Block* curr) {
562570 auto & list = curr->list ;
563571 if (list.size () == 1 && curr->name .is ()) {
@@ -566,41 +574,36 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
566574 // the two blocks must have the same type for us to update the branch, as otherwise
567575 // one block may be unreachable and the other concrete, so one might lack a value
568576 if (child->name .is () && child->name != curr->name && child->type == curr->type ) {
569- auto & breaks = breaksToBlock[child];
570- for (auto * br : breaks) {
571- newNames[br] = curr->name ;
572- breaksToBlock[curr].push_back (br); // update the list - we may push it even more later
573- }
574- breaksToBlock.erase (child);
577+ redirectBranches (child, curr->name );
575578 }
576579 }
577580 } else if (list.size () == 2 ) {
578581 // if this block has two children, a child-block and a simple jump, then jumps to child-block can be replaced with jumps to the new target
579582 auto * child = list[0 ]->dynCast <Block>();
580583 auto * jump = list[1 ]->dynCast <Break>();
581584 if (child && child->name .is () && jump && ExpressionAnalyzer::isSimple (jump)) {
582- auto & breaks = breaksToBlock[child];
583- for (auto * br : breaks) {
584- newNames[br] = jump->name ;
585- }
586- // if the jump is to another block then we can update the list, and maybe push it even more later
587- if (auto * newTarget = findBreakTarget (jump->name )->dynCast <Block>()) {
588- for (auto * br : breaks) {
589- breaksToBlock[newTarget].push_back (br);
590- }
591- }
592- breaksToBlock.erase (child);
585+ redirectBranches (child, jump->name );
593586 }
594587 }
595588 }
596589
597- void finish (Function* func) {
598- for (auto & iter : newNames) {
599- auto * br = iter.first ;
600- auto name = iter.second ;
601- br->name = name;
590+ void redirectBranches (Block* from, Name to) {
591+ auto & branches = branchesToBlock[from];
592+ for (auto * branch : branches) {
593+ if (BranchUtils::replacePossibleTarget (branch, from->name , to)) {
594+ worked = true ;
595+ }
596+ }
597+ // if the jump is to another block then we can update the list, and maybe push it even more later
598+ if (auto * newTarget = findBreakTarget (to)->dynCast <Block>()) {
599+ for (auto * branch : branches) {
600+ branchesToBlock[newTarget].push_back (branch);
601+ }
602602 }
603- if (newNames.size () > 0 ) {
603+ }
604+
605+ void finish (Function* func) {
606+ if (worked) {
604607 // by changing where brs go, we may change block types etc.
605608 ReFinalize ().walkFunctionInModule (func, getModule ());
606609 }
@@ -686,6 +689,19 @@ struct RemoveUnusedBrs : public WalkerPass<PostWalker<RemoveUnusedBrs>> {
686689 }
687690 }
688691
692+ void visitSwitch (Switch* curr) {
693+ if (BranchUtils::getUniqueTargets (curr).size () == 1 ) {
694+ // This switch has just one target no matter what; replace with a br.
695+ Builder builder (*getModule ());
696+ replaceCurrent (
697+ builder.makeSequence (
698+ builder.makeDrop (curr->condition ), // might have side effects
699+ builder.makeBreak (curr->default_ , curr->value )
700+ )
701+ );
702+ }
703+ }
704+
689705 // Restructuring of ifs: if we have
690706 // (block $x
691707 // (br_if $x (cond))
0 commit comments