@@ -126,7 +126,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
126126 } else if (curr->is <Block>()) {
127127 return ; // handled in visitBlock
128128 } else if (curr->is <If>()) {
129- assert (!curr->cast <If>()->ifFalse ); // if-elses are handled by doNoteIfElse * methods
129+ assert (!curr->cast <If>()->ifFalse ); // if-elses are handled by doNoteIf * methods
130130 } else if (curr->is <Switch>()) {
131131 auto * sw = curr->cast <Switch>();
132132 auto targets = BranchUtils::getUniqueTargets (sw);
@@ -138,26 +138,34 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
138138 self->sinkables .clear ();
139139 }
140140
141- static void doNoteIfElseCondition (SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
141+ static void doNoteIfCondition (SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
142142 // we processed the condition of this if-else, and now control flow branches
143143 // into either the true or the false sides
144- assert ((*currp)->cast <If>()->ifFalse );
145144 self->sinkables .clear ();
146145 }
147146
148- static void doNoteIfElseTrue (SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
149- // we processed the ifTrue side of this if-else, save it on the stack
150- assert ((*currp)->cast <If>()->ifFalse );
151- self->ifStack .push_back (std::move (self->sinkables ));
147+ static void doNoteIfTrue (SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
148+ auto * iff = (*currp)->dynCast <If>();
149+ if (iff->ifFalse ) {
150+ // We processed the ifTrue side of this if-else, save it on the stack.
151+ assert ((*currp)->cast <If>()->ifFalse );
152+ self->ifStack .push_back (std::move (self->sinkables ));
153+ } else {
154+ // This is an if without an else.
155+ if (allowStructure) {
156+ self->optimizeIfReturn (iff, currp);
157+ }
158+ self->sinkables .clear ();
159+ }
152160 }
153161
154- static void doNoteIfElseFalse (SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
162+ static void doNoteIfFalse (SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
155163 // we processed the ifFalse side of this if-else, we can now try to
156164 // mere with the ifTrue side and optimize a return value, if possible
157165 auto * iff = (*currp)->cast <If>();
158166 assert (iff->ifFalse );
159167 if (allowStructure) {
160- self->optimizeIfReturn (iff, currp, self->ifStack .back ());
168+ self->optimizeIfElseReturn (iff, currp, self->ifStack .back ());
161169 }
162170 self->ifStack .pop_back ();
163171 self->sinkables .clear ();
@@ -444,7 +452,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
444452 }
445453
446454 // optimize set_locals from both sides of an if into a return value
447- void optimizeIfReturn (If* iff, Expression** currp, Sinkables& ifTrue) {
455+ void optimizeIfElseReturn (If* iff, Expression** currp, Sinkables& ifTrue) {
448456 assert (iff->ifFalse );
449457 // if this if already has a result, or is unreachable code, we have
450458 // nothing to do
@@ -497,14 +505,14 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
497505 // need another cycle
498506 auto * ifTrueBlock = iff->ifTrue ->dynCast <Block>();
499507 if (iff->ifTrue ->type != unreachable) {
500- if (!ifTrueBlock || ifTrueBlock->list .size () == 0 || !ifTrueBlock->list .back ()->is <Nop>()) {
508+ if (!ifTrueBlock || ifTrueBlock->name . is () || ifTrueBlock-> list .size () == 0 || !ifTrueBlock->list .back ()->is <Nop>()) {
501509 ifsToEnlarge.push_back (iff);
502510 return ;
503511 }
504512 }
505513 auto * ifFalseBlock = iff->ifFalse ->dynCast <Block>();
506514 if (iff->ifFalse ->type != unreachable) {
507- if (!ifFalseBlock || ifFalseBlock->list .size () == 0 || !ifFalseBlock->list .back ()->is <Nop>()) {
515+ if (!ifFalseBlock || ifFalseBlock->name . is () || ifFalseBlock-> list .size () == 0 || !ifFalseBlock->list .back ()->is <Nop>()) {
508516 ifsToEnlarge.push_back (iff);
509517 return ;
510518 }
@@ -532,20 +540,78 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
532540 anotherCycle = true ;
533541 }
534542
543+ // Optimize set_locals from a one-sided iff, adding a get on the other:
544+ // (if
545+ // (..condition..)
546+ // (block
547+ // (set_local $x (..value..))
548+ // )
549+ // )
550+ // =>
551+ // (set_local $x
552+ // (if (result ..)
553+ // (..condition..)
554+ // (block (result ..)
555+ // (..value..)
556+ // )
557+ // (get_local $x)
558+ // )
559+ // )
560+ // This is a speculative optimization: we add a get here, as well as a branch
561+ // in the if, so this is harmful for code size and for speed. However, later
562+ // optimizations may sink the set and enable other useful things. If none of
563+ // that happens, other passes can "undo" this by turning an if with a copy
564+ // arm into a one-sided if.
565+ void optimizeIfReturn (If* iff, Expression** currp) {
566+ // If this if is unreachable code, we have nothing to do.
567+ if (iff->type != none || iff->ifTrue ->type != none) return ;
568+ // Anything sinkable is good for us.
569+ if (sinkables.empty ()) return ;
570+ Index goodIndex = sinkables.begin ()->first ;
571+ // Ensure we have a place to write the return values for, if not, we
572+ // need another cycle.
573+ auto * ifTrueBlock = iff->ifTrue ->dynCast <Block>();
574+ if (!ifTrueBlock || ifTrueBlock->name .is () || ifTrueBlock->list .size () == 0 || !ifTrueBlock->list .back ()->is <Nop>()) {
575+ ifsToEnlarge.push_back (iff);
576+ return ;
577+ }
578+ // Update the ifTrue side.
579+ Builder builder (*this ->getModule ());
580+ auto ** item = sinkables.at (goodIndex).item ;
581+ auto * set = (*item)->template cast <SetLocal>();
582+ ifTrueBlock->list [ifTrueBlock->list .size () - 1 ] = set->value ;
583+ *item = builder.makeNop ();
584+ ifTrueBlock->finalize ();
585+ assert (ifTrueBlock->type != none);
586+ // Update the ifFalse side.
587+ iff->ifFalse = builder.makeGetLocal (set->index , set->value ->type );
588+ iff->finalize (); // update type
589+ // Update the get count.
590+ getCounter.num [set->index ]++;
591+ assert (iff->type != none);
592+ // Finally, reuse the set_local on the iff itself.
593+ set->value = iff;
594+ set->finalize ();
595+ *currp = set;
596+ anotherCycle = true ;
597+ }
598+
535599 // override scan to add a pre and a post check task to all nodes
536600 static void scan (SimplifyLocals<allowTee, allowStructure, allowNesting>* self, Expression** currp) {
537601 self->pushTask (visitPost, currp);
538602
539603 auto * curr = *currp;
540604
541- if (curr->is <If>() && curr->cast <If>()->ifFalse ) {
542- // handle if-elses in a special manner, using the ifStack
543- self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfElseFalse, currp);
544- self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::scan, &curr->cast <If>()->ifFalse );
545- self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfElseTrue, currp);
546- self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::scan, &curr->cast <If>()->ifTrue );
547- self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfElseCondition, currp);
548- self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::scan, &curr->cast <If>()->condition );
605+ if (auto * iff = curr->dynCast <If>()) {
606+ // handle if in a special manner, using the ifStack for if-elses etc.
607+ if (iff->ifFalse ) {
608+ self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfFalse, currp);
609+ self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::scan, &iff->ifFalse );
610+ }
611+ self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfTrue, currp);
612+ self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::scan, &iff->ifTrue );
613+ self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::doNoteIfCondition, currp);
614+ self->pushTask (SimplifyLocals<allowTee, allowStructure, allowNesting>::scan, &iff->condition );
549615 } else {
550616 WalkerPass<LinearExecutionWalker<SimplifyLocals<allowTee, allowStructure, allowNesting>>>::scan (self, currp);
551617 }
@@ -582,7 +648,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
582648 // opts; continue only if they do. In other words, do not end up
583649 // doing final opts again and again when no main opts are being
584650 // enabled.
585- if (runFinalOptimizations (func) && runMainOptimizations (func)) {
651+ if (runLateOptimizations (func) && runMainOptimizations (func)) {
586652 anotherCycle = true ;
587653 }
588654 }
@@ -603,15 +669,17 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
603669 // enlarge ifs that were marked, for the next round
604670 if (ifsToEnlarge.size () > 0 ) {
605671 for (auto * iff : ifsToEnlarge) {
606- auto ifTrue = Builder (*this ->getModule ()).blockify (iff->ifTrue );
672+ auto ifTrue = Builder (*this ->getModule ()).blockifyWithName (iff->ifTrue , Name () );
607673 iff->ifTrue = ifTrue;
608674 if (ifTrue->list .size () == 0 || !ifTrue->list .back ()->template is <Nop>()) {
609675 ifTrue->list .push_back (this ->getModule ()->allocator .template alloc <Nop>());
610676 }
611- auto ifFalse = Builder (*this ->getModule ()).blockify (iff->ifFalse );
612- iff->ifFalse = ifFalse;
613- if (ifFalse->list .size () == 0 || !ifFalse->list .back ()->template is <Nop>()) {
614- ifFalse->list .push_back (this ->getModule ()->allocator .template alloc <Nop>());
677+ if (iff->ifFalse ) {
678+ auto ifFalse = Builder (*this ->getModule ()).blockifyWithName (iff->ifFalse , Name ());
679+ iff->ifFalse = ifFalse;
680+ if (ifFalse->list .size () == 0 || !ifFalse->list .back ()->template is <Nop>()) {
681+ ifFalse->list .push_back (this ->getModule ()->allocator .template alloc <Nop>());
682+ }
615683 }
616684 }
617685 ifsToEnlarge.clear ();
@@ -641,7 +709,7 @@ struct SimplifyLocals : public WalkerPass<LinearExecutionWalker<SimplifyLocals<a
641709 return anotherCycle;
642710 }
643711
644- bool runFinalOptimizations (Function* func) {
712+ bool runLateOptimizations (Function* func) {
645713 // Finally, after optimizing a function we can do some additional
646714 // optimization.
647715 getCounter.analyze (func);
0 commit comments