Skip to content

Commit 0fbfeda

Browse files
authored
Vacuum unneeded instructions even if children have effects (#5488)
This can handle e.g. (drop (i32.add (call ..) (call ..) ) ) We can remove the add and just leave two dropped calls: (drop (call ..) ) (drop (call ..) )
1 parent 728b37c commit 0fbfeda

File tree

4 files changed

+216
-55
lines changed

4 files changed

+216
-55
lines changed

src/passes/Vacuum.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
//
2020

2121
#include <ir/block-utils.h>
22+
#include <ir/drop.h>
2223
#include <ir/effects.h>
2324
#include <ir/iteration.h>
2425
#include <ir/literal-utils.h>
@@ -137,9 +138,17 @@ struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
137138
curr = childrenWithEffects[0];
138139
continue;
139140
}
140-
// TODO: with multiple children with side effects, we can perhaps figure
141-
// out something clever, like a block with drops, or an i32.add for just
142-
// two, etc.
141+
// The result is not used, but multiple children have side effects, so we
142+
// need to keep them around. We must also return something of the proper
143+
// type - if we can do that, replace everything with the children + a
144+
// dummy value of the proper type.
145+
if (curr->type.isDefaultable()) {
146+
auto* dummy = Builder(*getModule())
147+
.makeConstantExpression(Literal::makeZeros(curr->type));
148+
return getDroppedChildrenAndAppend(
149+
curr, *getModule(), getPassOptions(), dummy);
150+
}
151+
// Otherwise, give up.
143152
return curr;
144153
}
145154
}

test/lit/passes/vacuum-gc.wast

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33

44
(module
55
;; CHECK: (type ${} (struct ))
6+
7+
;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects (param i32 i32 funcref) (result anyref)))
8+
(import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects (param i32 i32 funcref) (result (ref null any))))
9+
;; CHECK: (import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects.non.null (param i32 i32 funcref) (result (ref any))))
10+
(import "binaryen-intrinsics" "call.without.effects" (func $call.without.effects.non.null (param i32 i32 funcref) (result (ref any))))
11+
612
(type ${} (struct))
713

814
;; CHECK: (func $drop-ref-as (type $anyref_=>_none) (param $x anyref)
@@ -90,4 +96,101 @@
9096
)
9197
)
9298
)
99+
100+
;; CHECK: (func $dropped-calls (type $none_=>_none)
101+
;; CHECK-NEXT: (block
102+
;; CHECK-NEXT: (drop
103+
;; CHECK-NEXT: (call $helper-i32)
104+
;; CHECK-NEXT: )
105+
;; CHECK-NEXT: (drop
106+
;; CHECK-NEXT: (call $helper-i32)
107+
;; CHECK-NEXT: )
108+
;; CHECK-NEXT: )
109+
;; CHECK-NEXT: (block
110+
;; CHECK-NEXT: (drop
111+
;; CHECK-NEXT: (call $helper-ref)
112+
;; CHECK-NEXT: )
113+
;; CHECK-NEXT: (drop
114+
;; CHECK-NEXT: (call $helper-ref)
115+
;; CHECK-NEXT: )
116+
;; CHECK-NEXT: )
117+
;; CHECK-NEXT: (block
118+
;; CHECK-NEXT: (drop
119+
;; CHECK-NEXT: (call $helper-i32)
120+
;; CHECK-NEXT: )
121+
;; CHECK-NEXT: (drop
122+
;; CHECK-NEXT: (call $helper-i32)
123+
;; CHECK-NEXT: )
124+
;; CHECK-NEXT: )
125+
;; CHECK-NEXT: (drop
126+
;; CHECK-NEXT: (call $call.without.effects.non.null
127+
;; CHECK-NEXT: (call $helper-i32)
128+
;; CHECK-NEXT: (call $helper-i32)
129+
;; CHECK-NEXT: (ref.func $helper-two-refs-non-null)
130+
;; CHECK-NEXT: )
131+
;; CHECK-NEXT: )
132+
;; CHECK-NEXT: )
133+
(func $dropped-calls
134+
;; The calls' outputs are used in a computation that itself has no effects,
135+
;; and is dropped, so we don't need it. But we can't remove the calls
136+
;; themselves, which should be all that remains, with drops of them (there
137+
;; will also be blocks, which merge-blocks would remove).
138+
(drop
139+
(i32.add
140+
(call $helper-i32)
141+
(call $helper-i32)
142+
)
143+
)
144+
(drop
145+
(ref.eq
146+
(call $helper-ref)
147+
(call $helper-ref)
148+
)
149+
)
150+
;; The call.without.effects can be removed, but not the two calls nested in
151+
;; it.
152+
(drop
153+
(call $call.without.effects
154+
(call $helper-i32)
155+
(call $helper-i32)
156+
(ref.func $helper-two-refs)
157+
)
158+
)
159+
;; The non-null case however is tricky, and we do not handle it atm. TODO
160+
(drop
161+
(call $call.without.effects.non.null
162+
(call $helper-i32)
163+
(call $helper-i32)
164+
(ref.func $helper-two-refs-non-null)
165+
)
166+
)
167+
)
168+
169+
;; CHECK: (func $helper-i32 (type $none_=>_i32) (result i32)
170+
;; CHECK-NEXT: (i32.const 1)
171+
;; CHECK-NEXT: )
172+
(func $helper-i32 (result i32)
173+
(i32.const 1)
174+
)
175+
176+
;; CHECK: (func $helper-ref (type $none_=>_eqref) (result eqref)
177+
;; CHECK-NEXT: (unreachable)
178+
;; CHECK-NEXT: )
179+
(func $helper-ref (result eqref)
180+
(unreachable)
181+
)
182+
183+
;; CHECK: (func $helper-two-refs (type $i32_i32_=>_anyref) (param $0 i32) (param $1 i32) (result anyref)
184+
;; CHECK-NEXT: (unreachable)
185+
;; CHECK-NEXT: )
186+
(func $helper-two-refs (param i32) (param i32) (result (ref null any))
187+
(unreachable)
188+
)
189+
190+
;; CHECK: (func $helper-two-refs-non-null (type $i32_i32_=>_ref|any|) (param $0 i32) (param $1 i32) (result (ref any))
191+
;; CHECK-NEXT: (unreachable)
192+
;; CHECK-NEXT: )
193+
(func $helper-two-refs-non-null (param i32) (param i32) (result (ref any))
194+
(unreachable)
195+
)
93196
)

test/passes/vacuum_all-features.txt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,11 @@
111111
(drop
112112
(call $int)
113113
)
114-
(drop
115-
(i32.add
114+
(block
115+
(drop
116116
(call $int)
117+
)
118+
(drop
117119
(call $int)
118120
)
119121
)

0 commit comments

Comments
 (0)