Skip to content

Commit 5efb807

Browse files
Account for addressed funcs
1 parent 2630eff commit 5efb807

2 files changed

Lines changed: 66 additions & 13 deletions

File tree

src/passes/GlobalEffects.cpp

Lines changed: 64 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <ranges>
2323

2424
#include "ir/effects.h"
25+
#include "ir/element-utils.h"
2526
#include "ir/module-utils.h"
2627
#include "pass.h"
2728
#include "support/graph_traversal.h"
@@ -47,8 +48,55 @@ struct FuncInfo {
4748
std::unordered_set<HeapType> indirectCalledTypes;
4849
};
4950

51+
std::unordered_set<Function*> getAddressedFuncs(Module& module) {
52+
struct AddressedFuncsWalker
53+
: PostWalker<AddressedFuncsWalker,
54+
UnifiedExpressionVisitor<AddressedFuncsWalker>> {
55+
const Module& module;
56+
std::unordered_set<Function*>& addressedFuncs;
57+
58+
AddressedFuncsWalker(const Module& module,
59+
std::unordered_set<Function*>& addressedFuncs)
60+
: module(module), addressedFuncs(addressedFuncs) {}
61+
62+
void visitExpression(Expression* curr) {
63+
if (auto* refFunc = curr->dynCast<RefFunc>()) {
64+
addressedFuncs.insert(module.getFunction(refFunc->func));
65+
}
66+
}
67+
};
68+
69+
std::unordered_set<Function*> addressedFuncs;
70+
AddressedFuncsWalker walker(module, addressedFuncs);
71+
walker.walkModule(&module);
72+
73+
ModuleUtils::iterImportedFunctions(
74+
module, [&addressedFuncs, &module](Function* import) {
75+
addressedFuncs.insert(module.getFunction(import->name));
76+
});
77+
78+
for (const auto& export_ : module.exports) {
79+
if (export_->kind != ExternalKind::Function) {
80+
continue;
81+
}
82+
83+
// TODO: internal or external? I think internal
84+
// This might be why we failed to lookup the function earlier
85+
// Maybe we can use Function* after all
86+
addressedFuncs.insert(module.getFunction(*export_->getInternalName()));
87+
}
88+
89+
ElementUtils::iterAllElementFunctionNames(
90+
&module, [&addressedFuncs, &module](Name func) {
91+
addressedFuncs.insert(module.getFunction(func));
92+
});
93+
94+
return addressedFuncs;
95+
}
96+
5097
std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
5198
const PassOptions& passOptions) {
99+
std::unordered_set<Name> addressedFuncs;
52100
ModuleUtils::ParallelFunctionAnalysis<FuncInfo> analysis(
53101
module, [&](Function* func, FuncInfo& funcInfo) {
54102
if (func->imported()) {
@@ -79,10 +127,14 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
79127
const PassOptions& options;
80128
FuncInfo& funcInfo;
81129

130+
std::unordered_set<Name>& addressedFuncs;
131+
82132
CallScanner(Module& wasm,
83133
const PassOptions& options,
84-
FuncInfo& funcInfo)
85-
: wasm(wasm), options(options), funcInfo(funcInfo) {}
134+
FuncInfo& funcInfo,
135+
std::unordered_set<Name>& addressedFuncs)
136+
: wasm(wasm), options(options), funcInfo(funcInfo),
137+
addressedFuncs(addressedFuncs) {}
86138

87139
void visitExpression(Expression* curr) {
88140
ShallowEffectAnalyzer effects(options, wasm, curr);
@@ -115,7 +167,7 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
115167
}
116168
}
117169
};
118-
CallScanner scanner(module, passOptions, funcInfo);
170+
CallScanner scanner(module, passOptions, funcInfo, addressedFuncs);
119171
scanner.walkFunction(func);
120172
}
121173
});
@@ -147,6 +199,7 @@ using CallGraph =
147199

148200
CallGraph buildCallGraph(const Module& module,
149201
const std::map<Function*, FuncInfo>& funcInfos,
202+
const std::unordered_set<Function*> addressedFuncs,
150203
bool closedWorld) {
151204
CallGraph callGraph;
152205
if (!closedWorld) {
@@ -182,7 +235,9 @@ CallGraph buildCallGraph(const Module& module,
182235
}
183236

184237
// Type -> Function
185-
callGraph[caller->type.getHeapType()].insert(caller);
238+
if (addressedFuncs.contains(caller)) {
239+
callGraph[caller->type.getHeapType()].insert(caller);
240+
}
186241
}
187242

188243
// Type -> Type
@@ -343,11 +398,12 @@ void copyEffectsToFunctions(const std::map<Function*, FuncInfo>& funcInfos) {
343398

344399
struct GenerateGlobalEffects : public Pass {
345400
void run(Module* module) override {
346-
std::map<Function*, FuncInfo> funcInfos =
347-
analyzeFuncs(*module, getPassOptions());
401+
auto funcInfos = analyzeFuncs(*module, getPassOptions());
402+
403+
auto addressedFuncs = getAddressedFuncs(*module);
348404

349-
auto callGraph =
350-
buildCallGraph(*module, funcInfos, getPassOptions().closedWorld);
405+
auto callGraph = buildCallGraph(
406+
*module, funcInfos, addressedFuncs, getPassOptions().closedWorld);
351407

352408
propagateEffects(*module, getPassOptions(), funcInfos, callGraph);
353409

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -348,15 +348,12 @@
348348
)
349349

350350
;; CHECK: (func $f (type $1) (param $ref (ref $only-has-effects-in-not-addressable-function))
351-
;; CHECK-NEXT: (call $calls-type-with-effects-but-not-addressable
352-
;; CHECK-NEXT: (local.get $ref)
353-
;; CHECK-NEXT: )
351+
;; CHECK-NEXT: (nop)
354352
;; CHECK-NEXT: )
355353
(func $f (param $ref (ref $only-has-effects-in-not-addressable-function))
356354
;; The type $has-effects-but-not-exported doesn't have an address because
357355
;; it's not exported and it's never the target of a ref.func.
358-
;; We should be able to determine that $ref can only point to $nop.
359-
;; TODO: Only aggregate effects from functions that are addressed.
356+
;; So the call_ref has no potential targets and thus no effects.
360357
(call $calls-type-with-effects-but-not-addressable (local.get $ref))
361358
)
362359
)

0 commit comments

Comments
 (0)