Skip to content

Commit 6214fa3

Browse files
Account for addressed funcs
1 parent 0890c8f commit 6214fa3

File tree

2 files changed

+66
-13
lines changed

2 files changed

+66
-13
lines changed

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/strongly_connected_components.h"
@@ -46,8 +47,55 @@ struct FuncInfo {
4647
std::unordered_set<HeapType> indirectCalledTypes;
4748
};
4849

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

129+
std::unordered_set<Name>& addressedFuncs;
130+
81131
CallScanner(Module& wasm,
82132
const PassOptions& options,
83-
FuncInfo& funcInfo)
84-
: wasm(wasm), options(options), funcInfo(funcInfo) {}
133+
FuncInfo& funcInfo,
134+
std::unordered_set<Name>& addressedFuncs)
135+
: wasm(wasm), options(options), funcInfo(funcInfo),
136+
addressedFuncs(addressedFuncs) {}
85137

86138
void visitExpression(Expression* curr) {
87139
ShallowEffectAnalyzer effects(options, wasm, curr);
@@ -114,7 +166,7 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
114166
}
115167
}
116168
};
117-
CallScanner scanner(module, passOptions, funcInfo);
169+
CallScanner scanner(module, passOptions, funcInfo, addressedFuncs);
118170
scanner.walkFunction(func);
119171
}
120172
});
@@ -146,6 +198,7 @@ using CallGraph =
146198

147199
CallGraph buildCallGraph(const Module& module,
148200
const std::map<Function*, FuncInfo>& funcInfos,
201+
const std::unordered_set<Function*> addressedFuncs,
149202
bool closedWorld) {
150203
CallGraph callGraph;
151204

@@ -170,7 +223,9 @@ CallGraph buildCallGraph(const Module& module,
170223
}
171224

172225
// Type -> Function
173-
callGraph[caller->type.getHeapType()].insert(caller);
226+
if (addressedFuncs.contains(caller)) {
227+
callGraph[caller->type.getHeapType()].insert(caller);
228+
}
174229
}
175230

176231
// Type -> Type
@@ -325,11 +380,12 @@ void copyEffectsToFunctions(const std::map<Function*, FuncInfo>& funcInfos) {
325380

326381
struct GenerateGlobalEffects : public Pass {
327382
void run(Module* module) override {
328-
std::map<Function*, FuncInfo> funcInfos =
329-
analyzeFuncs(*module, getPassOptions());
383+
auto funcInfos = analyzeFuncs(*module, getPassOptions());
384+
385+
auto addressedFuncs = getAddressedFuncs(*module);
330386

331-
auto callGraph =
332-
buildCallGraph(*module, funcInfos, getPassOptions().closedWorld);
387+
auto callGraph = buildCallGraph(
388+
*module, funcInfos, addressedFuncs, getPassOptions().closedWorld);
333389

334390
propagateEffects(*module, getPassOptions(), funcInfos, callGraph);
335391

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

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,15 +344,12 @@
344344
)
345345

346346
;; CHECK: (func $f (type $1) (param $ref (ref $only-has-effects-in-not-addressable-function))
347-
;; CHECK-NEXT: (call $calls-type-with-effects-but-not-addressable
348-
;; CHECK-NEXT: (local.get $ref)
349-
;; CHECK-NEXT: )
347+
;; CHECK-NEXT: (nop)
350348
;; CHECK-NEXT: )
351349
(func $f (param $ref (ref $only-has-effects-in-not-addressable-function))
352350
;; The type $has-effects-but-not-exported doesn't have an address because
353351
;; it's not exported and it's never the target of a ref.func.
354-
;; We should be able to determine that $ref can only point to $nop.
355-
;; TODO: Only aggregate effects from functions that are addressed.
352+
;; So the call_ref has no potential targets and thus no effects.
356353
(call $calls-type-with-effects-but-not-addressable (local.get $ref))
357354
)
358355
)

0 commit comments

Comments
 (0)