Skip to content

Commit 8a0e725

Browse files
PR updates
1 parent 6bf6f2a commit 8a0e725

2 files changed

Lines changed: 50 additions & 23 deletions

File tree

src/passes/GlobalEffects.cpp

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -122,24 +122,27 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
122122
}
123123

124124
using CallGraphNode = std::variant<Function*, HeapType>;
125-
using CallGraph =
126-
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>;
127125

128126
/*
129-
Build a call graph for indirect and direct calls.
127+
Call graph for indirect and direct calls.
130128
131129
key (caller) -> value (callee)
132-
Name -> Name : direct call
133-
Name -> HeapType : indirect call to the given HeapType
134-
HeapType -> Name : The function `callee` has the type `caller`. The
135-
HeapType may essentially 'call' any of its
136-
potential implementations.
137-
HeapType -> HeapType : `callee` is a subtype of `caller`. A call_ref
138-
could target any subtype of the ref, so we need to
139-
aggregate effects of subtypes of the target type.
140-
141-
If we're running in an open world, we only include Name -> Name edges.
130+
Function -> Function : direct call
131+
Function -> HeapType : indirect call to the given HeapType
132+
HeapType -> Function : The function `callee` has the type `caller`. The
133+
HeapType may essentially 'call' any of its
134+
potential implementations.
135+
HeapType -> HeapType : `callee` is a subtype of `caller`. A call_ref
136+
could target any subtype of the ref, so we need to
137+
aggregate effects of subtypes of the target type.
138+
139+
If we're running in an open world, we only include Function -> Function edges,
140+
and don't compute effects for indirect calls, conservatively assuming the
141+
worst.
142142
*/
143+
using CallGraph =
144+
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>;
145+
143146
CallGraph buildCallGraph(const Module& module,
144147
const std::map<Function*, FuncInfo>& funcInfos,
145148
bool closedWorld) {
@@ -149,7 +152,7 @@ CallGraph buildCallGraph(const Module& module,
149152
for (const auto& [caller, callerInfo] : funcInfos) {
150153
auto& callees = callGraph[caller];
151154

152-
// Name -> Name
155+
// Function -> Function
153156
for (Name calleeFunction : callerInfo.calledFunctions) {
154157
callees.insert(module.getFunction(calleeFunction));
155158
}
@@ -158,24 +161,26 @@ CallGraph buildCallGraph(const Module& module,
158161
continue;
159162
}
160163

161-
// Name -> Type
164+
// Function -> Type
162165
allFunctionTypes.insert(caller->type.getHeapType());
163166
for (HeapType calleeType : callerInfo.indirectCalledTypes) {
164167
callees.insert(calleeType);
165168
allFunctionTypes.insert(calleeType);
166169
}
167170

168-
// Type -> Name
171+
// Type -> Function
169172
callGraph[caller->type.getHeapType()].insert(caller);
170173
}
171174

172175
// Type -> Type
173176
for (HeapType type : allFunctionTypes) {
174-
// Not needed but during lookup we expect the key to exist.
177+
// Not needed except that during lookup we expect the key to exist.
175178
callGraph[type];
176179

177180
for (auto super = type.getDeclaredSuperType(); super;
178181
super = super->getDeclaredSuperType()) {
182+
// Don't bother noting supertypes with no functions in it. There are no
183+
// effects to aggregate anyway.
179184
if (allFunctionTypes.contains(*super)) {
180185
callGraph[*super].insert(type);
181186
}
@@ -244,7 +249,7 @@ void propagateEffects(const Module& module,
244249
const PassOptions& passOptions,
245250
std::map<Function*, FuncInfo>& funcInfos,
246251
const CallGraph& callGraph) {
247-
// We only care about Functions that are roots, not types
252+
// We only care about Functions that are roots, not types.
248253
// A type would be a root if a function exists with that type, but no-one
249254
// indirect calls the type.
250255
auto funcNodes = std::views::keys(callGraph) |

test/lit/passes/global-effects-closed-world.wast

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,26 @@
1919
;; CHECK-NEXT: )
2020
;; CHECK-NEXT: )
2121
(func $calls-nop-via-ref (param $ref (ref $nopType))
22-
;; This can only possibly be a nop in closed-world
22+
;; This can only possibly be a nop in closed-world.
2323
;; Ideally vacuum could optimize this out but we don't have a way to share
2424
;; this information with other passes today.
2525
;; For now, we can at least annotate that the call to this function in $f
26-
;; has no effects
26+
;; has no effects.
27+
;; TODO: This call_ref could be marked as having no effects, like the call below.
2728
(call_ref $nopType (i32.const 1) (local.get $ref))
2829
)
2930

31+
;; CHECK: (func $calls-nop-via-nullable-ref (type $2) (param $ref (ref null $nopType))
32+
;; CHECK-NEXT: (call_ref $nopType
33+
;; CHECK-NEXT: (i32.const 1)
34+
;; CHECK-NEXT: (local.get $ref)
35+
;; CHECK-NEXT: )
36+
;; CHECK-NEXT: )
37+
(func $calls-nop-via-nullable-ref (param $ref (ref null $nopType))
38+
(call_ref $nopType (i32.const 1) (local.get $ref))
39+
)
40+
41+
3042
;; CHECK: (func $f (type $1) (param $ref (ref $nopType))
3143
;; CHECK-NEXT: (nop)
3244
;; CHECK-NEXT: )
@@ -35,6 +47,16 @@
3547
;; call $nop. We can optimize this call out.
3648
(call $calls-nop-via-ref (local.get $ref))
3749
)
50+
51+
;; CHECK: (func $g (type $2) (param $ref (ref null $nopType))
52+
;; CHECK-NEXT: (call $calls-nop-via-nullable-ref
53+
;; CHECK-NEXT: (local.get $ref)
54+
;; CHECK-NEXT: )
55+
;; CHECK-NEXT: )
56+
(func $g (param $ref (ref null $nopType))
57+
;; Similar to $f, but we may still trap here because the ref is null.
58+
(call $calls-nop-via-nullable-ref (local.get $ref))
59+
)
3860
)
3961

4062
(module
@@ -71,7 +93,7 @@
7193
;; CHECK-NEXT: )
7294
;; CHECK-NEXT: )
7395
(func $f (param $ref (ref $maybe-has-effects))
74-
;; This may be a nop or it may trap depending on the ref
96+
;; This may be a nop or it may trap depending on the ref.
7597
;; We don't know so don't optimize it out.
7698
(call $calls-effectful-function-via-ref (local.get $ref))
7799
)
@@ -156,7 +178,7 @@
156178
)
157179

158180
;; Same as above but this time our reference is the exact supertype
159-
;; So we know not to aggregate effects from the subtype.
181+
;; so we know not to aggregate effects from the subtype.
160182
;; TODO: this case doesn't optimize today. Add exact ref support in the pass.
161183
(module
162184
;; CHECK: (type $super (sub (struct)))
@@ -240,7 +262,7 @@
240262
(func $f (param $ref (ref $only-has-effects-in-not-addressable-function))
241263
;; The type $has-effects-but-not-exported doesn't have an address because
242264
;; it's not exported and it's never the target of a ref.func.
243-
;; We should be able to determine that $ref can only point to $nop
265+
;; We should be able to determine that $ref can only point to $nop.
244266
;; TODO: Only aggregate effects from functions that are addressed.
245267
(call $calls-type-with-effects-but-not-addressable (local.get $ref))
246268
)

0 commit comments

Comments
 (0)