@@ -154,6 +154,15 @@ struct BreakValueDropper : public ControlFlowWalker<BreakValueDropper> {
154154 }
155155};
156156
157+ static bool hasUnreachableChild (Block* block) {
158+ for (auto * test : block->list ) {
159+ if (test->type == unreachable) {
160+ return true ;
161+ }
162+ }
163+ return false ;
164+ }
165+
157166// core block optimizer routine
158167static void optimizeBlock (Block* curr, Module* module , PassOptions& passOptions) {
159168 bool more = true ;
@@ -168,42 +177,37 @@ static void optimizeBlock(Block* curr, Module* module, PassOptions& passOptions)
168177 if (drop) {
169178 child = drop->value ->dynCast <Block>();
170179 if (child) {
171- // if we move around unreachable code, type changes could occur. avoid that, as
172- // anyhow it means we should have run dce before getting here
173- for (auto * test : child->list ) {
174- if (test->type == unreachable) {
180+ if (hasUnreachableChild (child)) {
181+ // don't move around unreachable code, as it can change types
182+ // dce should have been run anyhow
183+ continue ;
184+ }
185+ if (child->name .is ()) {
186+ Expression* expression = child;
187+ // check if it's ok to remove the value from all breaks to us
188+ ProblemFinder finder (passOptions);
189+ finder.origin = child->name ;
190+ finder.walk (expression);
191+ if (finder.found ()) {
175192 child = nullptr ;
176- break ;
193+ } else {
194+ // fix up breaks
195+ BreakValueDropper fixer (passOptions);
196+ fixer.origin = child->name ;
197+ fixer.setModule (module );
198+ fixer.walk (expression);
177199 }
178200 }
179201 if (child) {
180- if (child->name .is ()) {
181- Expression* expression = child;
182- // check if it's ok to remove the value from all breaks to us
183- ProblemFinder finder (passOptions);
184- finder.origin = child->name ;
185- finder.walk (expression);
186- if (finder.found ()) {
187- child = nullptr ;
188- } else {
189- // fix up breaks
190- BreakValueDropper fixer (passOptions);
191- fixer.origin = child->name ;
192- fixer.setModule (module );
193- fixer.walk (expression);
194- }
195- }
196- if (child) {
197- // we can do it!
198- // reuse the drop
199- drop->value = child->list .back ();
200- drop->finalize ();
201- child->list .back () = drop;
202- child->finalize ();
203- curr->list [i] = child;
204- more = true ;
205- changed = true ;
206- }
202+ // we can do it!
203+ // reuse the drop
204+ drop->value = child->list .back ();
205+ drop->finalize ();
206+ child->list .back () = drop;
207+ child->finalize ();
208+ curr->list [i] = child;
209+ more = true ;
210+ changed = true ;
207211 }
208212 }
209213 }
@@ -251,6 +255,23 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
251255 optimizeBlock (curr, getModule (), getPassOptions ());
252256 }
253257
258+ // given
259+ // (curr
260+ // (block=child
261+ // (..more..)
262+ // (back)
263+ // )
264+ // (..other..children..)
265+ // )
266+ // if child is a block, we can move this around to
267+ // (block
268+ // (..more..)
269+ // (curr
270+ // (back)
271+ // (..other..children..)
272+ // )
273+ // )
274+ // at which point the block is on the outside and potentially mergeable with an outer block
254275 Block* optimize (Expression* curr, Expression*& child, Block* outer = nullptr , Expression** dependency1 = nullptr , Expression** dependency2 = nullptr ) {
255276 if (!child) return outer;
256277 if ((dependency1 && *dependency1) || (dependency2 && *dependency2)) {
@@ -261,18 +282,28 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
261282 }
262283 if (auto * block = child->dynCast <Block>()) {
263284 if (!block->name .is () && block->list .size () >= 2 ) {
264- child = block->list .back ();
285+ // if we move around unreachable code, type changes could occur. avoid that, as
286+ // anyhow it means we should have run dce before getting here
287+ if (curr->type == none && hasUnreachableChild (block)) {
288+ // moving the block to the outside would replace a none with an unreachable
289+ return outer;
290+ }
291+ auto * back = block->list .back ();
292+ if (back->type == unreachable) {
293+ // curr is not reachable, dce could remove it; don't try anything fancy
294+ // here
295+ return outer;
296+ }
297+ child = back;
265298 // we modified child (which is a reference to a pointer), which modifies curr, which might change its type
266299 // (e.g. (drop (block (result i32) .. (unreachable)))
267300 // the child was a block of i32, and is being replaced with an unreachable, so the
268301 // parent will likely need to be unreachable too
269- auto oldType = curr->type ;
270- ReFinalize ().walk (curr);
271302 if (outer == nullptr ) {
272303 // reuse the block, move it out
273304 block->list .back () = curr;
274305 // we want the block outside to have the same type as curr had
275- block->finalize (oldType );
306+ block->finalize (curr-> type );
276307 replaceCurrent (block);
277308 return block;
278309 } else {
0 commit comments