Skip to content

Commit a8aa660

Browse files
authored
ReFinalize in MergeBlocks so we can optimize unreachable instructions too (#6994)
In #6984 we optimized dropped blocks even if they had unreachable code. In #6988 that part was reverted, and blocks with unreachable code were ignored once more. However, I realized that the check was not actually for unreachable code, but for having an unreachable child, so it would miss things like this: (block (block .. (br $somewhere) ;; unreachable type, but no unreachable code ) ) But it is useful to merge such blocks: we don't need the inner block here. To fix this, just run ReFinalize if we change anything, which will propagate unreachability as needed. I think MergeBlocks was written before we had that utility, so it didn't use it... This is not only useful for itself but will unblock an EH optimization in a later PR, that has code in this form. It also simplifies the code by removing the hasUnreachableChild checks.
1 parent debd246 commit a8aa660

File tree

6 files changed

+123
-178
lines changed

6 files changed

+123
-178
lines changed

src/passes/MergeBlocks.cpp

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,6 @@ struct BreakValueDropper : public ControlFlowWalker<BreakValueDropper> {
176176
}
177177
};
178178

179-
static bool hasUnreachableChild(Block* block) {
180-
for (auto* test : block->list) {
181-
if (test->type == Type::unreachable) {
182-
return true;
183-
}
184-
}
185-
return false;
186-
}
187-
188179
// Checks for code after an unreachable element.
189180
static bool hasDeadCode(Block* block) {
190181
auto& list = block->list;
@@ -206,11 +197,6 @@ static bool optimizeDroppedBlock(Drop* drop,
206197
PassOptions& options,
207198
BranchUtils::BranchSeekerCache& branchInfo) {
208199
assert(drop->value == block);
209-
if (hasUnreachableChild(block)) {
210-
// Don't move around unreachable code, as it can change types (leave it for
211-
// DCE).
212-
return false;
213-
}
214200
if (block->name.is()) {
215201
// There may be breaks: see if we can remove their values.
216202
Expression* expression = block;
@@ -241,8 +227,8 @@ static bool optimizeDroppedBlock(Drop* drop,
241227
return true;
242228
}
243229

244-
// Core block optimizer routine.
245-
static void optimizeBlock(Block* curr,
230+
// Core block optimizer routine. Returns true when we optimize.
231+
static bool optimizeBlock(Block* curr,
246232
Module* module,
247233
PassOptions& passOptions,
248234
BranchUtils::BranchSeekerCache& branchInfo) {
@@ -412,6 +398,7 @@ static void optimizeBlock(Block* curr,
412398
if (changed) {
413399
curr->finalize(curr->type);
414400
}
401+
return changed;
415402
}
416403

417404
void BreakValueDropper::visitBlock(Block* curr) {
@@ -427,6 +414,8 @@ struct MergeBlocks
427414
return std::make_unique<MergeBlocks>();
428415
}
429416

417+
bool refinalize = false;
418+
430419
BranchUtils::BranchSeekerCache branchInfo;
431420

432421
void visitBlock(Block* curr) {
@@ -438,6 +427,7 @@ struct MergeBlocks
438427
if (optimizeDroppedBlock(
439428
curr, block, *getModule(), getPassOptions(), branchInfo)) {
440429
replaceCurrent(block);
430+
refinalize = true;
441431
}
442432
}
443433
}
@@ -485,13 +475,6 @@ struct MergeBlocks
485475
}
486476
if (auto* block = child->dynCast<Block>()) {
487477
if (!block->name.is() && block->list.size() >= 2) {
488-
// if we move around unreachable code, type changes could occur. avoid
489-
// that, as anyhow it means we should have run dce before getting here
490-
if (curr->type == Type::none && hasUnreachableChild(block)) {
491-
// moving the block to the outside would replace a none with an
492-
// unreachable
493-
return outer;
494-
}
495478
auto* back = block->list.back();
496479
if (back->type == Type::unreachable) {
497480
// curr is not reachable, dce could remove it; don't try anything
@@ -510,6 +493,7 @@ struct MergeBlocks
510493
return outer;
511494
}
512495
child = back;
496+
refinalize = true;
513497
if (outer == nullptr) {
514498
// reuse the block, move it out
515499
block->list.back() = curr;
@@ -600,8 +584,7 @@ struct MergeBlocks
600584
// too small for us to remove anything from (we cannot remove the last
601585
// element), or if it has unreachable code (leave that for dce), then give
602586
// up.
603-
if (!block || block->name.is() || block->list.size() <= 1 ||
604-
hasUnreachableChild(block)) {
587+
if (!block || block->name.is() || block->list.size() <= 1) {
605588
continueEarly();
606589
continue;
607590
}
@@ -682,6 +665,7 @@ struct MergeBlocks
682665
outerBlock->list.push_back(curr);
683666
outerBlock->finalize(curr->type);
684667
replaceCurrent(outerBlock);
668+
refinalize = true;
685669
}
686670
}
687671

@@ -700,6 +684,12 @@ struct MergeBlocks
700684
outer = optimize(curr, curr->operands[i], outer);
701685
}
702686
}
687+
688+
void visitFunction(Function* curr) {
689+
if (refinalize) {
690+
ReFinalize().walkFunctionInModule(curr, getModule());
691+
}
692+
}
703693
};
704694

705695
Pass* createMergeBlocksPass() { return new MergeBlocks(); }

test/lit/passes/merge-blocks.wast

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -405,12 +405,11 @@
405405
)
406406

407407
;; CHECK: (func $toplevel (type $4)
408-
;; CHECK-NEXT: (drop
409-
;; CHECK-NEXT: (block $label (result i32)
410-
;; CHECK-NEXT: (br $label
411-
;; CHECK-NEXT: (i32.const 42)
412-
;; CHECK-NEXT: )
408+
;; CHECK-NEXT: (block $label
409+
;; CHECK-NEXT: (drop
410+
;; CHECK-NEXT: (i32.const 42)
413411
;; CHECK-NEXT: )
412+
;; CHECK-NEXT: (br $label)
414413
;; CHECK-NEXT: )
415414
;; CHECK-NEXT: )
416415
(func $toplevel

test/lit/passes/monomorphize-drop.wast

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -672,12 +672,7 @@
672672

673673
;; CAREFUL: (func $return-normal_4 (type $1)
674674
;; CAREFUL-NEXT: (drop
675-
;; CAREFUL-NEXT: (block
676-
;; CAREFUL-NEXT: (drop
677-
;; CAREFUL-NEXT: (call $import)
678-
;; CAREFUL-NEXT: )
679-
;; CAREFUL-NEXT: (return)
680-
;; CAREFUL-NEXT: )
675+
;; CAREFUL-NEXT: (call $import)
681676
;; CAREFUL-NEXT: )
682677
;; CAREFUL-NEXT: )
683678

test/passes/Oz_fuzz-exec_all-features.txt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,10 @@
183183
(nop)
184184
)
185185
(func $br-on_non_null-2 (type $void_func)
186-
(drop
187-
(block
188-
(call $log
189-
(i32.const 1)
190-
)
191-
(unreachable)
192-
)
186+
(call $log
187+
(i32.const 1)
193188
)
189+
(unreachable)
194190
)
195191
(func $cast-on-func (type $void_func)
196192
(call $log

test/passes/merge-blocks.txt

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
)
1111
)
1212
(func $drop-block-br
13-
(drop
14-
(block $x (result i32)
15-
(br $x
16-
(i32.const 1)
17-
)
13+
(block $x
14+
(drop
15+
(i32.const 1)
16+
)
17+
(br $x)
18+
(drop
1819
(i32.const 0)
1920
)
2021
)
@@ -77,15 +78,9 @@
7778
)
7879
)
7980
(func $drop-block-squared-iloop
80-
(drop
81-
(block $label$0 (result i32)
82-
(drop
83-
(block $label$1
84-
(loop $label$2
85-
(br $label$2)
86-
)
87-
)
88-
)
81+
(block $label$0
82+
(loop $label$2
83+
(br $label$2)
8984
)
9085
)
9186
)
@@ -109,11 +104,7 @@
109104
(func $loop-block-drop-block-return
110105
(loop $label$4
111106
(block $label$5
112-
(drop
113-
(block $label$6 (result i32)
114-
(return)
115-
)
116-
)
107+
(return)
117108
)
118109
)
119110
)

0 commit comments

Comments
 (0)