Skip to content

Commit ec8f944

Browse files
Add more tests + split up
1 parent 01198f8 commit ec8f944

File tree

2 files changed

+113
-109
lines changed

2 files changed

+113
-109
lines changed

src/passes/GlobalEffects.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
// Function::effects; see more details there.
2020
//
2121

22-
#include "ir/table-utils.h"
23-
#include "ir/subtypes.h"
2422
#include "ir/effects.h"
23+
#include "ir/element-utils.h"
2524
#include "ir/module-utils.h"
25+
#include "ir/subtypes.h"
26+
#include "ir/table-utils.h"
2627
#include "pass.h"
27-
#include "ir/element-utils.h"
2828
#include "support/unique_deferring_queue.h"
2929
#include "wasm.h"
3030

@@ -125,7 +125,8 @@ using CallGraphNode = std::variant<Name, HeapType>;
125125
// Then B inherits effects from C and A inherits effects from both B and C.
126126
void propagateEffects(
127127
const Module& module,
128-
const std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>& reverseCallGraph,
128+
const std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>&
129+
reverseCallGraph,
129130
std::map<Function*, FuncInfo>& funcInfos) {
130131

131132
using CallGraphEdge = std::pair<CallGraphNode, CallGraphNode>;
@@ -164,8 +165,10 @@ void propagateEffects(
164165
while (!work.empty()) {
165166
auto [callee, caller] = work.pop();
166167

167-
if (std::get_if<Name>(&callee) == std::get_if<Name>(&caller) && std::holds_alternative<Name>(callee)) {
168-
auto& callerEffects = funcInfos.at(module.getFunction(std::get<Name>(caller))).effects;
168+
if (std::get_if<Name>(&callee) == std::get_if<Name>(&caller) &&
169+
std::holds_alternative<Name>(callee)) {
170+
auto& callerEffects =
171+
funcInfos.at(module.getFunction(std::get<Name>(caller))).effects;
169172
if (callerEffects) {
170173
callerEffects->trap = true;
171174
}
@@ -193,15 +196,18 @@ struct GenerateGlobalEffects : public Pass {
193196
analyzeFuncs(*module, getPassOptions());
194197

195198
// callee : caller
196-
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>> callers;
199+
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>
200+
callers;
197201

198202
std::unordered_set<HeapType> allIndirectCalledTypes;
199203

200204
std::unordered_set<Name> funcsWithAddress;
201205

202206
auto refFuncs = TableUtils::getFunctionsNeedingElemDeclare(*module);
203207
funcsWithAddress.insert(refFuncs.begin(), refFuncs.end());
204-
ElementUtils::iterAllElementFunctionNames(module, [&funcsWithAddress](Name name) { funcsWithAddress.insert(name); });
208+
ElementUtils::iterAllElementFunctionNames(
209+
module,
210+
[&funcsWithAddress](Name name) { funcsWithAddress.insert(name); });
205211
for (const auto& export_ : module->exports) {
206212
if (export_->kind == ExternalKind::Function) {
207213
// This exported function might flow back to us even in a closed world,
@@ -233,10 +239,10 @@ struct GenerateGlobalEffects : public Pass {
233239
for (auto type : allIndirectCalledTypes) {
234240
subtypes.iterSubTypes(type, [&callers, type](HeapType sub, int _) {
235241
// HeapType -> HeapType
236-
// A subtype is a 'callee' of its supertype. Supertypes need to inherit effects from their subtypes
237-
// See the example in (TODO)
242+
// A subtype is a 'callee' of its supertype.
243+
// Supertypes need to inherit effects from their subtypes since they may
244+
// be called via a ref to the subtype.
238245
callers[sub].insert(type);
239-
// callers[type].insert(sub);
240246
return true;
241247
});
242248
}
@@ -247,7 +253,7 @@ struct GenerateGlobalEffects : public Pass {
247253
// known.
248254
for (auto& [func, info] : funcInfos) {
249255
func->effects.reset();
250-
if (!info.effects) {
256+
if (info.effects == UnknownEffects) {
251257
continue;
252258
}
253259

Lines changed: 95 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,18 @@
11
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
2-
;; RUN: wasm-opt %s -all --closed-world --generate-global-effects --vacuum -S -o - | filecheck %s
2+
;; RUN: foreach %s %t wasm-opt -all --closed-world --generate-global-effects --vacuum -S -o - | filecheck %s
33

44
(module
5-
;; CHECK: (type $maybe-has-effects (func (param i32 i32)))
6-
(type $maybe-has-effects (func (param i32 i32)))
7-
8-
;; CHECK: (type $only-has-effects-in-non-exported-function (func (param f32 f32)))
9-
105
;; CHECK: (type $nopType (func (param i32)))
116
(type $nopType (func (param i32)))
127

13-
;; CHECK: (type $super (sub (struct)))
14-
(type $super (sub (struct)))
15-
;; CHECK: (type $sub (sub $super (struct)))
16-
(type $sub (sub $super (struct)))
17-
18-
;; CHECK: (type $func-with-sub-param (sub (func (param (ref $sub)))))
19-
20-
;; CHECK: (type $uninhabited (func (param f32)))
21-
(type $uninhabited (func (param f32)))
22-
23-
;; Subtype
24-
(type $func-with-sub-param (sub (func (param (ref $sub)))))
25-
26-
;; Subtype
27-
;; CHECK: (type $ttt (func (param i64)))
28-
29-
;; CHECK: (type $func-with-super-param (sub $func-with-sub-param (func (param (ref $super)))))
30-
(type $func-with-super-param (sub $func-with-sub-param (func (param (ref $super)))))
31-
32-
(type $only-has-effects-in-non-exported-function (func (param f32 f32)))
33-
34-
(table 10 funcref)
35-
36-
;; CHECK: (global $g (mut i32) (i32.const 0))
37-
(global $g (mut i32) (i32.const 0))
38-
39-
;; CHECK: (elem declare func $A)
40-
418
;; CHECK: (func $nop (type $nopType) (param $0 i32)
429
;; CHECK-NEXT: (nop)
4310
;; CHECK-NEXT: )
4411
(func $nop (export "nop") (type $nopType)
4512
(nop)
4613
)
4714

48-
;; CHECK: (func $unreachable (type $maybe-has-effects) (param $0 i32) (param $1 i32)
49-
;; CHECK-NEXT: (unreachable)
50-
;; CHECK-NEXT: )
51-
(func $unreachable (export "unreachable") (type $maybe-has-effects) (param i32 i32)
52-
(unreachable)
53-
)
54-
55-
;; CHECK: (func $nop2 (type $maybe-has-effects) (param $0 i32) (param $1 i32)
56-
;; CHECK-NEXT: (nop)
57-
;; CHECK-NEXT: )
58-
(func $nop2 (export "nop2") (type $maybe-has-effects) (param i32 i32)
59-
(nop)
60-
)
61-
62-
;; CHECK: (func $calls-nop-via-ref (type $8) (param $ref (ref $nopType))
15+
;; CHECK: (func $calls-nop-via-ref (type $1) (param $ref (ref $nopType))
6316
;; CHECK-NEXT: (call_ref $nopType
6417
;; CHECK-NEXT: (i32.const 1)
6518
;; CHECK-NEXT: (local.get $ref)
@@ -69,60 +22,98 @@
6922
;; This can only possibly be a nop in closed-world
7023
;; Ideally vacuum could optimize this out but we don't have a way to share
7124
;; this information with other passes today.
72-
;; For now, we can at least annotate that $f has no effects.
25+
;; For now, we can at least annotate that the call to this function in $f
26+
;; has no effects
7327
(call_ref $nopType (i32.const 1) (local.get $ref))
7428
)
7529

76-
;; CHECK: (func $f (type $8) (param $ref (ref $nopType))
30+
;; CHECK: (func $f (type $1) (param $ref (ref $nopType))
7731
;; CHECK-NEXT: (nop)
7832
;; CHECK-NEXT: )
7933
(func $f (param $ref (ref $nopType))
8034
;; $calls-nop-via-ref has no effects because we determined that it can only
8135
;; call $nop. We can optimize this call out.
8236
(call $calls-nop-via-ref (local.get $ref))
8337
)
38+
)
39+
40+
(module
41+
;; CHECK: (type $maybe-has-effects (func (param i32)))
42+
(type $maybe-has-effects (func (param i32)))
43+
44+
;; CHECK: (func $unreachable (type $maybe-has-effects) (param $0 i32)
45+
;; CHECK-NEXT: (unreachable)
46+
;; CHECK-NEXT: )
47+
(func $unreachable (export "unreachable") (type $maybe-has-effects) (param i32)
48+
(unreachable)
49+
)
50+
51+
;; CHECK: (func $nop2 (type $maybe-has-effects) (param $0 i32)
52+
;; CHECK-NEXT: (nop)
53+
;; CHECK-NEXT: )
54+
(func $nop2 (export "nop2") (type $maybe-has-effects) (param i32)
55+
(nop)
56+
)
8457

85-
;; CHECK: (func $calls-effectful-function-via-ref (type $9) (param $ref (ref $maybe-has-effects))
58+
;; CHECK: (func $calls-effectful-function-via-ref (type $1) (param $ref (ref $maybe-has-effects))
8659
;; CHECK-NEXT: (call_ref $maybe-has-effects
8760
;; CHECK-NEXT: (i32.const 1)
88-
;; CHECK-NEXT: (i32.const 2)
8961
;; CHECK-NEXT: (local.get $ref)
9062
;; CHECK-NEXT: )
9163
;; CHECK-NEXT: )
9264
(func $calls-effectful-function-via-ref (param $ref (ref $maybe-has-effects))
93-
(call_ref $maybe-has-effects (i32.const 1) (i32.const 2) (local.get $ref))
65+
(call_ref $maybe-has-effects (i32.const 1) (local.get $ref))
9466
)
9567

96-
;; CHECK: (func $g (type $9) (param $ref (ref $maybe-has-effects))
68+
;; CHECK: (func $f (type $1) (param $ref (ref $maybe-has-effects))
9769
;; CHECK-NEXT: (call $calls-effectful-function-via-ref
9870
;; CHECK-NEXT: (local.get $ref)
9971
;; CHECK-NEXT: )
10072
;; CHECK-NEXT: )
101-
(func $g (param $ref (ref $maybe-has-effects))
73+
(func $f (param $ref (ref $maybe-has-effects))
10274
;; This may be a nop or it may trap depending on the ref
10375
;; We don't know so don't optimize it out.
10476
(call $calls-effectful-function-via-ref (local.get $ref))
10577
)
78+
)
79+
80+
(module
81+
;; CHECK: (type $uninhabited (func (param i32)))
82+
(type $uninhabited (func (param i32)))
10683

107-
;; CHECK: (func $calls-uninhabited (type $10) (param $ref (ref $uninhabited))
84+
;; CHECK: (func $calls-uninhabited (type $1) (param $ref (ref $uninhabited))
10885
;; CHECK-NEXT: (call_ref $uninhabited
109-
;; CHECK-NEXT: (f32.const 0)
86+
;; CHECK-NEXT: (i32.const 1)
11087
;; CHECK-NEXT: (local.get $ref)
11188
;; CHECK-NEXT: )
11289
;; CHECK-NEXT: )
11390
(func $calls-uninhabited (param $ref (ref $uninhabited))
114-
(call_ref $uninhabited (f32.const 0) (local.get $ref))
91+
(call_ref $uninhabited (i32.const 1) (local.get $ref))
11592
)
11693

117-
;; CHECK: (func $h (type $10) (param $ref (ref $uninhabited))
94+
;; CHECK: (func $f (type $1) (param $ref (ref $uninhabited))
11895
;; CHECK-NEXT: (nop)
11996
;; CHECK-NEXT: )
120-
(func $h (param $ref (ref $uninhabited))
97+
(func $f (param $ref (ref $uninhabited))
12198
;; There's no function with this type, so it's impossible to create a ref to
12299
;; call this function with and there are no effects to aggregate.
123100
;; Remove this call.
124101
(call $calls-uninhabited (local.get $ref))
125102
)
103+
)
104+
105+
(module
106+
;; CHECK: (type $super (sub (struct)))
107+
(type $super (sub (struct)))
108+
;; CHECK: (type $sub (sub $super (struct)))
109+
(type $sub (sub $super (struct)))
110+
111+
;; Supertype
112+
;; CHECK: (type $func-with-sub-param (sub (func (param (ref $sub)))))
113+
(type $func-with-sub-param (sub (func (param (ref $sub)))))
114+
;; Subtype
115+
;; CHECK: (type $func-with-super-param (sub $func-with-sub-param (func (param (ref $super)))))
116+
(type $func-with-super-param (sub $func-with-sub-param (func (param (ref $super)))))
126117

127118
;; CHECK: (func $nop-with-supertype (type $func-with-sub-param) (param $0 (ref $sub))
128119
;; CHECK-NEXT: (nop)
@@ -137,7 +128,7 @@
137128
(unreachable)
138129
)
139130

140-
;; CHECK: (func $calls-ref-with-subtype (type $11) (param $func (ref $func-with-sub-param)) (param $sub (ref $sub))
131+
;; CHECK: (func $calls-ref-with-subtype (type $3) (param $func (ref $func-with-sub-param)) (param $sub (ref $sub))
141132
;; CHECK-NEXT: (call_ref $func-with-sub-param
142133
;; CHECK-NEXT: (local.get $sub)
143134
;; CHECK-NEXT: (local.get $func)
@@ -147,13 +138,13 @@
147138
(call_ref $func-with-sub-param (local.get $sub) (local.get $func))
148139
)
149140

150-
;; CHECK: (func $asdf (type $11) (param $func (ref $func-with-sub-param)) (param $sub (ref $sub))
141+
;; CHECK: (func $f (type $3) (param $func (ref $func-with-sub-param)) (param $sub (ref $sub))
151142
;; CHECK-NEXT: (call $calls-ref-with-subtype
152143
;; CHECK-NEXT: (local.get $func)
153144
;; CHECK-NEXT: (local.get $sub)
154145
;; CHECK-NEXT: )
155146
;; CHECK-NEXT: )
156-
(func $asdf (param $func (ref $func-with-sub-param)) (param $sub (ref $sub))
147+
(func $f (param $func (ref $func-with-sub-param)) (param $sub (ref $sub))
157148
;; Check that we account for subtyping correctly.
158149
;; The type $func-with-sub-param (the supertype) has no effects (i.e. the
159150
;; union of all effects of functions with this type is empty).
@@ -162,71 +153,78 @@
162153
;; include the unreachable effect and we can't optimize out this call.
163154
(call $calls-ref-with-subtype (local.get $func) (local.get $sub))
164155
)
156+
)
165157

166-
;; CHECK: (func $no-effects (type $only-has-effects-in-non-exported-function) (param $0 f32) (param $1 f32)
158+
(module
159+
;; CHECK: (type $only-has-effects-in-not-addressable-function (func (param i32)))
160+
(type $only-has-effects-in-not-addressable-function (func (param i32)))
161+
162+
;; CHECK: (func $nop (type $only-has-effects-in-not-addressable-function) (param $0 i32)
167163
;; CHECK-NEXT: (nop)
168164
;; CHECK-NEXT: )
169-
(func $no-effects (type $only-has-effects-in-non-exported-function) (param f32 f32)
165+
(func $nop (export "nop") (type $only-has-effects-in-not-addressable-function) (param i32)
170166
)
171167

172-
;; CHECK: (func $has-effects-but-not-exported (type $only-has-effects-in-non-exported-function) (param $0 f32) (param $1 f32)
168+
;; CHECK: (func $has-effects-but-not-exported (type $only-has-effects-in-not-addressable-function) (param $0 i32)
173169
;; CHECK-NEXT: (unreachable)
174170
;; CHECK-NEXT: )
175-
(func $has-effects-but-not-exported (type $only-has-effects-in-non-exported-function) (param f32 f32)
171+
(func $has-effects-but-not-exported (type $only-has-effects-in-not-addressable-function) (param i32)
176172
(unreachable)
177173
)
178174

179-
;; CHECK: (func $calls-type-with-effects-but-not-addressable (type $12) (param $ref (ref $only-has-effects-in-non-exported-function))
180-
;; CHECK-NEXT: (call_ref $only-has-effects-in-non-exported-function
181-
;; CHECK-NEXT: (f32.const 0)
182-
;; CHECK-NEXT: (f32.const 0)
175+
;; CHECK: (func $calls-type-with-effects-but-not-addressable (type $1) (param $ref (ref $only-has-effects-in-not-addressable-function))
176+
;; CHECK-NEXT: (call_ref $only-has-effects-in-not-addressable-function
177+
;; CHECK-NEXT: (i32.const 1)
183178
;; CHECK-NEXT: (local.get $ref)
184179
;; CHECK-NEXT: )
185180
;; CHECK-NEXT: )
186-
(func $calls-type-with-effects-but-not-addressable (param $ref (ref $only-has-effects-in-non-exported-function))
187-
(call_ref $only-has-effects-in-non-exported-function (f32.const 0) (f32.const 0) (local.get $ref))
181+
(func $calls-type-with-effects-but-not-addressable (param $ref (ref $only-has-effects-in-not-addressable-function))
182+
(call_ref $only-has-effects-in-not-addressable-function (i32.const 1) (local.get $ref))
188183
)
189184

190-
;; CHECK: (func $i (type $12) (param $ref (ref $only-has-effects-in-non-exported-function))
185+
;; CHECK: (func $f (type $1) (param $ref (ref $only-has-effects-in-not-addressable-function))
191186
;; CHECK-NEXT: (nop)
192187
;; CHECK-NEXT: )
193-
(func $i (param $ref (ref $only-has-effects-in-non-exported-function))
188+
(func $f (param $ref (ref $only-has-effects-in-not-addressable-function))
194189
(call $calls-type-with-effects-but-not-addressable (local.get $ref))
195190
)
191+
)
196192

197-
;; CHECK: (func $B (type $6)
193+
(module
194+
;; CHECK: (type $unreachable-via-direct-call (func (param i32)))
195+
(type $unreachable-via-direct-call (func (param i32)))
196+
197+
;; CHECK: (func $unreachable (type $0)
198198
;; CHECK-NEXT: (unreachable)
199199
;; CHECK-NEXT: )
200-
(func $B
200+
(func $unreachable
201201
(unreachable)
202202
)
203203

204-
(type $ttt (func (param i64)))
205-
206-
;; CHECK: (func $A (type $ttt) (param $0 i64)
207-
;; CHECK-NEXT: (call $B)
204+
;; CHECK: (func $calls-unreachable (type $unreachable-via-direct-call) (param $0 i32)
205+
;; CHECK-NEXT: (call $unreachable)
208206
;; CHECK-NEXT: )
209-
(func $A (export "A") (param i64)
210-
(call $B)
211-
;; (call_ref $ttt (ref.func $u))
207+
(func $calls-unreachable (export "calls-unreachable") (param i32)
208+
(call $unreachable)
212209
)
213210

214-
(elem declare $two)
215-
216-
;; CHECK: (func $C (type $6)
217-
;; CHECK-NEXT: (call_ref $ttt
218-
;; CHECK-NEXT: (i64.const 0)
219-
;; CHECK-NEXT: (ref.func $A)
211+
;; CHECK: (func $calls-unreachable-via-ref-and-direct-call-transtively (type $0)
212+
;; CHECK-NEXT: (call_ref $unreachable-via-direct-call
213+
;; CHECK-NEXT: (i32.const 0)
214+
;; CHECK-NEXT: (ref.func $calls-unreachable)
220215
;; CHECK-NEXT: )
221216
;; CHECK-NEXT: )
222-
(func $C
223-
(call_ref $ttt (i64.const 0) (ref.func $A))
217+
(func $calls-unreachable-via-ref-and-direct-call-transtively
218+
(call_ref $unreachable-via-direct-call (i32.const 0) (ref.func $calls-unreachable))
224219
)
225220

226-
;; CHECK: (func $foo (type $6)
227-
;; CHECK-NEXT: (call $C)
221+
;; CHECK: (func $f (type $0)
222+
;; CHECK-NEXT: (call $calls-unreachable-via-ref-and-direct-call-transtively)
228223
;; CHECK-NEXT: )
229-
(func $foo
230-
(call $C)
224+
(func $f
225+
(call $calls-unreachable-via-ref-and-direct-call-transtively)
231226
)
232227
)
228+
229+
;; TODO exact types
230+
;; TODO functions that are referenced other ways besides exporting

0 commit comments

Comments
 (0)