Skip to content

Commit 8fcba01

Browse files
Start cleaning up
1 parent c0543a1 commit 8fcba01

File tree

1 file changed

+71
-55
lines changed

1 file changed

+71
-55
lines changed

src/passes/GlobalEffects.cpp

Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,68 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
120120

121121
using CallGraphNode = std::variant<Name, HeapType>;
122122

123+
// Build a call graph for indirect and direct calls.
124+
// key (callee) -> value (caller)
125+
// Name -> Name : callee is called directly by caller
126+
// Name -> HeapType : callee is a potential target of a virtual call with this HeapType
127+
// HeapType -> Name : callee is indirectly called by caller
128+
// HeapType -> HeapType : callee is a subtype of caller
129+
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>> buildReverseCallGraph(Module& module, const std::map<Function*, FuncInfo> funcInfos) {
130+
// callee : caller
131+
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>
132+
callers;
133+
134+
std::unordered_set<HeapType> allIndirectCalledTypes;
135+
136+
std::unordered_set<Name> funcsWithAddress;
137+
138+
auto refFuncs = TableUtils::getFunctionsNeedingElemDeclare(module);
139+
funcsWithAddress.insert(refFuncs.begin(), refFuncs.end());
140+
ElementUtils::iterAllElementFunctionNames(
141+
&module,
142+
[&funcsWithAddress](Name name) { funcsWithAddress.insert(name); });
143+
for (const auto& export_ : module.exports) {
144+
if (export_->kind == ExternalKind::Function) {
145+
// This exported function might flow back to us even in a closed world,
146+
// so it's essentially addressed.
147+
funcsWithAddress.insert(export_->name);
148+
}
149+
}
150+
151+
for (const auto& [func, info] : funcInfos) {
152+
// Name -> Name for direct calls
153+
for (const auto& callee : info.calledFunctions) {
154+
callers[callee].insert(func->name);
155+
}
156+
157+
// HeapType -> Name for indirect calls
158+
for (const auto& calleeType : info.indirectCalledTypes) {
159+
callers[calleeType].insert(func->name);
160+
}
161+
162+
// Name -> HeapType for function types
163+
if (funcsWithAddress.contains(func->name)) {
164+
callers[func->name].insert(func->type.getHeapType());
165+
}
166+
167+
allIndirectCalledTypes.insert(func->type.getHeapType());
168+
}
169+
170+
SubTypes subtypes(module);
171+
for (auto type : allIndirectCalledTypes) {
172+
subtypes.iterSubTypes(type, [&callers, type](HeapType sub, int _) {
173+
// HeapType -> HeapType
174+
// A subtype is a 'callee' of its supertype.
175+
// Supertypes need to inherit effects from their subtypes since they may
176+
// be called via a ref to the subtype.
177+
callers[sub].insert(type);
178+
return true;
179+
});
180+
}
181+
182+
return callers;
183+
}
184+
123185
// Propagate effects from callees to callers transitively
124186
// e.g. if A -> B -> C (A calls B which calls C)
125187
// Then B inherits effects from C and A inherits effects from both B and C.
@@ -138,14 +200,16 @@ void propagateEffects(
138200
}
139201
}
140202

141-
auto propagate = [&](Name* callee, Name* caller) {
142-
if (callee == nullptr || caller == nullptr) {
203+
auto propagate = [&](const CallGraphNode& calleeNode, const CallGraphNode& callerNode) {
204+
if (!std::get_if<Name>(&calleeNode) || !std::get_if<Name>(&callerNode)) {
143205
return;
144206
}
145207

146-
auto& callerEffects = funcInfos.at(module.getFunction(*caller)).effects;
208+
Name callee = std::get<Name>(calleeNode);
209+
Name caller = std::get<Name>(callerNode);
210+
auto& callerEffects = funcInfos.at(module.getFunction(caller)).effects;
147211
const auto& calleeEffects =
148-
funcInfos.at(module.getFunction(*callee)).effects;
212+
funcInfos.at(module.getFunction(callee)).effects;
149213
if (callerEffects == UnknownEffects) {
150214
return;
151215
}
@@ -155,7 +219,7 @@ void propagateEffects(
155219
return;
156220
}
157221

158-
if (*callee == *caller) {
222+
if (callee == caller) {
159223
callerEffects->trap = true;
160224
} else {
161225
callerEffects->mergeIn(*calleeEffects);
@@ -177,7 +241,7 @@ void propagateEffects(
177241
// Even if nothing changed, we still need to keep traversing the callers
178242
// to look for a potential cycle which adds a trap affect on the above
179243
// lines.
180-
propagate(std::get_if<Name>(&callee), std::get_if<Name>(&caller));
244+
propagate(callee, caller);
181245

182246
const auto& callerCallers = reverseCallGraph.find(caller);
183247
if (callerCallers == reverseCallGraph.end()) {
@@ -197,55 +261,7 @@ struct GenerateGlobalEffects : public Pass {
197261

198262
// callee : caller
199263
std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>>
200-
callers;
201-
202-
std::unordered_set<HeapType> allIndirectCalledTypes;
203-
204-
std::unordered_set<Name> funcsWithAddress;
205-
206-
auto refFuncs = TableUtils::getFunctionsNeedingElemDeclare(*module);
207-
funcsWithAddress.insert(refFuncs.begin(), refFuncs.end());
208-
ElementUtils::iterAllElementFunctionNames(
209-
module,
210-
[&funcsWithAddress](Name name) { funcsWithAddress.insert(name); });
211-
for (const auto& export_ : module->exports) {
212-
if (export_->kind == ExternalKind::Function) {
213-
// This exported function might flow back to us even in a closed world,
214-
// so it's essentially addressed.
215-
funcsWithAddress.insert(export_->name);
216-
}
217-
}
218-
219-
for (const auto& [func, info] : funcInfos) {
220-
// Name -> Name for direct calls
221-
for (const auto& callee : info.calledFunctions) {
222-
callers[callee].insert(func->name);
223-
}
224-
225-
// HeapType -> Name for indirect calls
226-
for (const auto& calleeType : info.indirectCalledTypes) {
227-
callers[calleeType].insert(func->name);
228-
}
229-
230-
// Name -> HeapType for function types
231-
if (funcsWithAddress.contains(func->name)) {
232-
callers[func->name].insert(func->type.getHeapType());
233-
}
234-
235-
allIndirectCalledTypes.insert(func->type.getHeapType());
236-
}
237-
238-
SubTypes subtypes(*module);
239-
for (auto type : allIndirectCalledTypes) {
240-
subtypes.iterSubTypes(type, [&callers, type](HeapType sub, int _) {
241-
// HeapType -> HeapType
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.
245-
callers[sub].insert(type);
246-
return true;
247-
});
248-
}
264+
callers = buildReverseCallGraph(*module, funcInfos);
249265

250266
propagateEffects(*module, callers, funcInfos);
251267

0 commit comments

Comments
 (0)