Skip to content

Commit e0d287f

Browse files
Done??
1 parent 17f779f commit e0d287f

File tree

2 files changed

+126
-47
lines changed

2 files changed

+126
-47
lines changed

src/passes/GlobalEffects.cpp

Lines changed: 122 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -114,22 +114,48 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
114114
return analysis.map;
115115
}
116116

117-
std::unordered_map<HeapType, std::unordered_set<Name>>
118-
typeToFunctionNames(const Module& module) {
119-
std::unordered_map<HeapType, std::unordered_set<Name>> ret;
117+
// std::unordered_map<HeapType, std::unordered_set<Name>>
118+
// typeToFunctionNames(const Module& module) {
119+
// std::unordered_map<HeapType, std::unordered_set<Name>> ret;
120+
121+
// // TODO
122+
// SubTypes s(*const_cast<Module*>(&module));
123+
124+
// for (const auto& func : module.functions) {
125+
// s.iterSubTypes(func->type.getHeapType(), [&ret, &func](HeapType type, int _) {
126+
// std::cout<<"subtype "<< func->type.getHeapType() << " " << type<< "\n";
127+
// ret[type].insert(func->name);
128+
// });
129+
// // ret[func->type.getHeapType()].insert(func->name);
130+
// }
131+
132+
// return ret;
133+
// }
134+
135+
template <typename T>
136+
std::unordered_map<T, std::unordered_set<T>> transitiveClosure2(const std::unordered_map<T, std::unordered_set<T>>& in) {
137+
UniqueNonrepeatingDeferredQueue<std::pair<T, T>> work;
138+
139+
for (const auto& [curr, neighbors] : in) {
140+
for (const auto& neighbor : neighbors) {
141+
work.push({curr, neighbor});
142+
}
143+
}
144+
145+
std::unordered_map<T, std::unordered_set<T>> closure;
146+
while (!work.empty()) {
147+
auto [curr, neighbor] = work.pop();
120148

121-
// TODO
122-
SubTypes s(*const_cast<Module*>(&module));
149+
closure[curr].insert(neighbor);
123150

124-
for (const auto& func : module.functions) {
125-
s.iterSubTypes(func->type.getHeapType(), [&ret, &func](HeapType type, int _) {
126-
std::cout<<"subtype "<< func->type.getHeapType() << " " << type<< "\n";
127-
ret[type].insert(func->name);
128-
});
129-
// ret[func->type.getHeapType()].insert(func->name);
151+
auto neighborNeighbors = in.find(neighbor);
152+
if (neighborNeighbors == in.end()) continue;
153+
for (const auto& neighborNeighbor : neighborNeighbors->second) {
154+
work.push({curr, neighborNeighbor});
155+
}
130156
}
131157

132-
return ret;
158+
return closure;
133159
}
134160

135161
std::unordered_map<Name, std::unordered_set<Name>>
@@ -186,21 +212,32 @@ transitiveClosure(const Module& module,
186212
return callers;
187213
}
188214

189-
std::unordered_map<Name, std::unordered_set<Name>> transitiveClosure(
190-
const Module& module,
191-
const std::unordered_map<Name, std::unordered_set<Name>>& funcInfos) {
192-
auto transformed =
193-
funcInfos | std::views::transform(
194-
[&](const auto& pair) -> std::pair<Function*, FuncInfo> {
195-
auto& [k, v] = pair;
196-
197-
auto* func = module.getFunction(k);
198-
FuncInfo info;
199-
info.calledFunctions = v;
200-
return {func, info};
201-
});
202-
std::map<Function*, FuncInfo> other(transformed.begin(), transformed.end());
203-
return transitiveClosure(module, other);
215+
// std::unordered_map<Name, std::unordered_set<Name>> transitiveClosure(
216+
// const Module& module,
217+
// const std::unordered_map<Name, std::unordered_set<Name>>& funcInfos) {
218+
// auto transformed =
219+
// funcInfos | std::views::transform(
220+
// [&](const auto& pair) -> std::pair<Function*, FuncInfo> {
221+
// auto& [k, v] = pair;
222+
223+
// auto* func = module.getFunction(k);
224+
// FuncInfo info;
225+
// info.calledFunctions = v;
226+
// return {func, info};
227+
// });
228+
// std::map<Function*, FuncInfo> other(transformed.begin(), transformed.end());
229+
// return transitiveClosure(module, other);
230+
// }
231+
232+
template <typename K, typename V>
233+
std::unordered_map<V, std::unordered_set<K>> flip(const std::unordered_map<K, std::unordered_set<V>>& in) {
234+
std::unordered_map<V, std::unordered_set<K>> flipped;
235+
for (const auto& [k, vs] : in) {
236+
for (const auto& v : vs) {
237+
flipped[v].insert(k);
238+
}
239+
}
240+
return flipped;
204241
}
205242

206243
struct GenerateGlobalEffects : public Pass {
@@ -220,34 +257,73 @@ struct GenerateGlobalEffects : public Pass {
220257
std::unordered_map<Name, std::unordered_set<Name>> callers =
221258
transitiveClosure(*module, funcInfos);
222259

223-
const auto functionsWithType = typeToFunctionNames(*module);
224-
std::unordered_map<Name, std::unordered_set<Name>>
260+
// const auto functionsWithType = typeToFunctionNames(*module);
261+
std::unordered_map<Name, std::unordered_set<HeapType>>
225262
indirectCallersNonTransitive;
263+
std::unordered_map<HeapType, std::unordered_set<HeapType>> indirectCalls;
226264
for (auto& [func, info] : funcInfos) {
227-
indirectCallersNonTransitive[func->name];
265+
auto& set = indirectCallersNonTransitive[func->name];
266+
auto& indirectCallsSet = indirectCalls[func->type.getHeapType()];
228267
for (auto& calledType : info.indirectCalledTypes) {
229-
if (auto it = functionsWithType.find(calledType);
230-
it != functionsWithType.end()) {
231-
indirectCallersNonTransitive[func->name].insert(it->second.begin(),
232-
it->second.end());
233-
}
268+
// if (auto it = functionsWithType.find(calledType);
269+
// it != functionsWithType.end()) {
270+
set.insert(calledType);
271+
indirectCallsSet.insert(calledType);
234272
}
235273
}
236274

237275
// indirectCallers[foo] = [func that indirect calls something with the same
238276
// type as foo, ..]
239-
const std::unordered_map<Name, std::unordered_set<Name>> indirectCallers =
240-
transitiveClosure(*module, indirectCallersNonTransitive);
241-
242-
std::cout << "indirectCallers\n";
243-
for (auto [callee, callers] : indirectCallers) {
244-
std::cout << callee << "\n";
245-
for (auto caller : callers) {
246-
std::cout << "\t" << caller << "\n";
277+
// const std::unordered_map<HeapType, std::unordered_set<Name>> indirectCallers =
278+
// transitiveClosure(*module, indirectCallersNonTransitive);
279+
280+
// TODO: need to take subtypes into account here
281+
// we can pretend that each type 'indirect calls' its subtypes
282+
// This is good enough because when querying the particular function Name that
283+
// indirect calls someone we want to take its indirect calls into account anyway
284+
// So just pretend that it indirect calls its subtypes.
285+
286+
SubTypes subtypes(*module);
287+
std::unordered_map<HeapType, std::unordered_set<HeapType>> subTypesToAdd;
288+
289+
for (const auto& [type, _] : indirectCalls) {
290+
subtypes.iterSubTypes(type, [&subTypesToAdd, type](HeapType sub, int _) { subTypesToAdd[type].insert(sub); return true; });
291+
}
292+
293+
for (const auto& [k, v] : subTypesToAdd) {
294+
auto it = indirectCalls.find(k);
295+
296+
// This is possible but if it happens it means there was no function with this type anyway
297+
// So no effects to include and no harm in forgetting it.
298+
if (it == indirectCalls.end()) continue;
299+
300+
it->second.insert(v.begin(), v.end());
301+
}
302+
303+
auto a = transitiveClosure2<HeapType>(indirectCalls);
304+
305+
for (const auto& [k, v]: indirectCallersNonTransitive) {
306+
for (const auto& x : v) {
307+
auto y = a[x];
308+
309+
// we're leaving what was already there but should be fine
310+
// since it's covered under transitive calls anyway
311+
indirectCallersNonTransitive[k].insert(y.begin(), y.end());
247312
}
248-
std::cout << "\n";
249313
}
250314

315+
std::unordered_map<HeapType, std::unordered_set<Name>> flipped = flip(indirectCallersNonTransitive);
316+
// indirectCalls;
317+
318+
// std::cout << "indirectCallers\n";
319+
// for (auto [callee, callers] : indirectCallers) {
320+
// std::cout << callee << "\n";
321+
// for (auto caller : callers) {
322+
// std::cout << "\t" << caller << "\n";
323+
// }
324+
// std::cout << "\n";
325+
// }
326+
251327
// Now that we have transitively propagated all static calls, apply that
252328
// information. First, apply infinite recursion: if a function can call
253329
// itself then it might recurse infinitely, which we consider an effect (a
@@ -282,8 +358,8 @@ struct GenerateGlobalEffects : public Pass {
282358
callerEffects->mergeIn(*funcEffects);
283359
}
284360

285-
auto indirectCallersOfThisFunction = indirectCallers.find(func->name);
286-
if (indirectCallersOfThisFunction == indirectCallers.end()) {
361+
auto indirectCallersOfThisFunction = flipped.find(func->type.getHeapType());
362+
if (indirectCallersOfThisFunction == flipped.end()) {
287363
continue;
288364
}
289365
for (Name caller : indirectCallersOfThisFunction->second) {

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,10 @@
140140
)
141141

142142
;; CHECK: (func $asdf (type $8) (param $func (ref $func-with-sub-param)) (param $sub (ref $sub))
143-
;; CHECK-NEXT: (nop)
143+
;; CHECK-NEXT: (call $calls-ref-with-subtype
144+
;; CHECK-NEXT: (local.get $func)
145+
;; CHECK-NEXT: (local.get $sub)
146+
;; CHECK-NEXT: )
144147
;; CHECK-NEXT: )
145148
(func $asdf (param $func (ref $func-with-sub-param)) (param $sub (ref $sub))
146149
;; Check that we account for subtyping correctly.

0 commit comments

Comments
 (0)