Skip to content

Commit 23e452a

Browse files
authored
Refactor MergeBlocks to use iteration; adds Wasm GC support (#4137)
MergeBlocks was written a very long time ago, before the iteration API, so it had a bunch of hardcoded things for specific instructions. In particular, that did not handle GC. This does a small refactoring to use iteration. The refactoring is NFC, but while doing so it adds support for new relevant instructions, including wasm GC.
1 parent 7ecc77a commit 23e452a

File tree

2 files changed

+82
-31
lines changed

2 files changed

+82
-31
lines changed

src/passes/MergeBlocks.cpp

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474

7575
#include <ir/branch-utils.h>
7676
#include <ir/effects.h>
77+
#include <ir/iteration.h>
7778
#include <ir/utils.h>
7879
#include <pass.h>
7980
#include <wasm-builder.h>
@@ -397,7 +398,9 @@ void BreakValueDropper::visitBlock(Block* curr) {
397398
optimizeBlock(curr, getModule(), passOptions, branchInfo);
398399
}
399400

400-
struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
401+
struct MergeBlocks
402+
: public WalkerPass<
403+
PostWalker<MergeBlocks, UnifiedExpressionVisitor<MergeBlocks>>> {
401404
bool isFunctionParallel() override { return true; }
402405

403406
Pass* create() override { return new MergeBlocks; }
@@ -491,20 +494,26 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
491494
return outer;
492495
}
493496

494-
void visitUnary(Unary* curr) { optimize(curr, curr->value); }
495-
void visitLocalSet(LocalSet* curr) { optimize(curr, curr->value); }
496-
void visitLoad(Load* curr) { optimize(curr, curr->ptr); }
497-
void visitReturn(Return* curr) { optimize(curr, curr->value); }
497+
// Default optimizations for simple cases. Complex things are overridden
498+
// below.
499+
void visitExpression(Expression* curr) {
500+
// Control flow need special handling. Those we can optimize are handled
501+
// below.
502+
if (Properties::isControlFlowStructure(curr)) {
503+
return;
504+
}
498505

499-
void visitBinary(Binary* curr) {
500-
optimize(curr, curr->right, optimize(curr, curr->left), &curr->left);
501-
}
502-
void visitStore(Store* curr) {
503-
optimize(curr, curr->value, optimize(curr, curr->ptr), &curr->ptr);
504-
}
505-
void visitAtomicRMW(AtomicRMW* curr) {
506-
optimize(curr, curr->value, optimize(curr, curr->ptr), &curr->ptr);
506+
ChildIterator iterator(curr);
507+
auto& children = iterator.children;
508+
if (children.size() == 1) {
509+
optimize(curr, *children[0]);
510+
} else if (children.size() == 2) {
511+
optimize(curr, *children[0], optimize(curr, *children[1]), children[1]);
512+
} else if (children.size() == 3) {
513+
optimizeTernary(curr, *children[2], *children[1], *children[0]);
514+
}
507515
}
516+
508517
void optimizeTernary(Expression* curr,
509518
Expression*& first,
510519
Expression*& second,
@@ -528,23 +537,6 @@ struct MergeBlocks : public WalkerPass<PostWalker<MergeBlocks>> {
528537
}
529538
optimize(curr, third, outer);
530539
}
531-
void visitAtomicCmpxchg(AtomicCmpxchg* curr) {
532-
optimizeTernary(curr, curr->ptr, curr->expected, curr->replacement);
533-
}
534-
535-
void visitSelect(Select* curr) {
536-
optimizeTernary(curr, curr->ifTrue, curr->ifFalse, curr->condition);
537-
}
538-
539-
void visitDrop(Drop* curr) { optimize(curr, curr->value); }
540-
541-
void visitBreak(Break* curr) {
542-
optimize(curr, curr->condition, optimize(curr, curr->value), &curr->value);
543-
}
544-
545-
void visitSwitch(Switch* curr) {
546-
optimize(curr, curr->condition, optimize(curr, curr->value), &curr->value);
547-
}
548540

549541
template<typename T> void handleCall(T* curr) {
550542
Block* outer = nullptr;

test/lit/passes/merge-blocks.wast

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
2-
;; RUN: wasm-opt %s --merge-blocks -all -S -o - \
2+
;; RUN: wasm-opt %s --remove-unused-names --merge-blocks -all -S -o - \
33
;; RUN: | filecheck %s
4+
;;
5+
;; --remove-unused-names lets --merge-blocks assume blocks without names have no
6+
;; branch targets.
47

58
(module
69
(type $anyref_=>_none (func (param anyref)))
10+
11+
;; CHECK: (type $struct (struct (field (mut i32))))
12+
(type $struct (struct (field (mut i32))))
13+
714
;; CHECK: (func $br_on_to_drop
815
;; CHECK-NEXT: (nop)
916
;; CHECK-NEXT: (drop
@@ -31,4 +38,56 @@
3138
)
3239
)
3340
)
41+
42+
;; CHECK: (func $struct.set
43+
;; CHECK-NEXT: (nop)
44+
;; CHECK-NEXT: (drop
45+
;; CHECK-NEXT: (i32.const 1234)
46+
;; CHECK-NEXT: )
47+
;; CHECK-NEXT: (struct.set $struct 0
48+
;; CHECK-NEXT: (ref.null $struct)
49+
;; CHECK-NEXT: (i32.const 5)
50+
;; CHECK-NEXT: )
51+
;; CHECK-NEXT: (nop)
52+
;; CHECK-NEXT: )
53+
(func $struct.set
54+
(block
55+
(nop)
56+
(struct.set $struct 0
57+
(block (result (ref null $struct))
58+
(drop (i32.const 1234))
59+
(ref.null $struct)
60+
)
61+
(i32.const 5)
62+
)
63+
(nop)
64+
)
65+
)
66+
67+
;; CHECK: (func $struct.get
68+
;; CHECK-NEXT: (nop)
69+
;; CHECK-NEXT: (drop
70+
;; CHECK-NEXT: (i32.const 1234)
71+
;; CHECK-NEXT: )
72+
;; CHECK-NEXT: (drop
73+
;; CHECK-NEXT: (struct.get $struct 0
74+
;; CHECK-NEXT: (ref.null $struct)
75+
;; CHECK-NEXT: )
76+
;; CHECK-NEXT: )
77+
;; CHECK-NEXT: (nop)
78+
;; CHECK-NEXT: )
79+
(func $struct.get
80+
(block
81+
(nop)
82+
(drop
83+
(struct.get $struct 0
84+
(block (result (ref null $struct))
85+
(drop (i32.const 1234))
86+
(ref.null $struct)
87+
)
88+
)
89+
)
90+
(nop)
91+
)
92+
)
3493
)

0 commit comments

Comments
 (0)