@@ -95,7 +95,6 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
9595 }
9696
9797 funcInfo.indirectCalledTypes .insert (type);
98- // funcInfo.effects.reset();
9998 } else {
10099 // No call here, but update throwing if we see it. (Only do so,
101100 // however, if we have effects; if we cleared it - see before -
@@ -114,24 +113,6 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
114113 return analysis.map ;
115114}
116115
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-
135116template <typename T>
136117std::unordered_map<T, std::unordered_set<T>> transitiveClosure2 (const std::unordered_map<T, std::unordered_set<T>>& in) {
137118 UniqueNonrepeatingDeferredQueue<std::pair<T, T>> work;
@@ -240,33 +221,26 @@ std::unordered_map<V, std::unordered_set<K>> flip(const std::unordered_map<K, st
240221 return flipped;
241222}
242223
224+ // std::unordered_map<HeapType, std::unordered_set<Name>>
225+
243226struct GenerateGlobalEffects : public Pass {
244227 void run (Module* module ) override {
245228 // First, we do a scan of each function to see what effects they have,
246229 // including which functions they call directly (so that we can compute
247230 // transitive effects later).
248231 auto funcInfos = analyzeFuncs (*module , getPassOptions ());
249232
250- // Compute the transitive closure of effects. To do so, first construct for
251- // each function a list of the functions that it is called by (so we need to
252- // propagate its effects to them), and then we'll construct the closure of
253- // that.
254- //
255- // callers[foo] = [func that calls foo, another func that calls foo, ..]
256- //
257- std::unordered_map<Name, std::unordered_set<Name>> callers =
258- transitiveClosure (*module , funcInfos);
259-
260- // const auto functionsWithType = typeToFunctionNames(*module);
233+ // Find the 'entry points' of indirect calls Name -> HeapType.
234+ // At the same time, start recording connections for the transitive closure of indirect calls
235+ // HeapType -> HeapType. This will be used to find the set of HeapTypes that are reachable via any sequence of indirect calls from a given function
236+ // (Name -> HeapType)
261237 std::unordered_map<Name, std::unordered_set<HeapType>>
262238 indirectCallersNonTransitive;
263239 std::unordered_map<HeapType, std::unordered_set<HeapType>> indirectCalls;
264240 for (auto & [func, info] : funcInfos) {
265241 auto & set = indirectCallersNonTransitive[func->name ];
266242 auto & indirectCallsSet = indirectCalls[func->type .getHeapType ()];
267243 for (auto & calledType : info.indirectCalledTypes ) {
268- // if (auto it = functionsWithType.find(calledType);
269- // it != functionsWithType.end()) {
270244 set.insert (calledType);
271245 indirectCallsSet.insert (calledType);
272246 }
@@ -293,15 +267,18 @@ struct GenerateGlobalEffects : public Pass {
293267 for (const auto & [k, v] : subTypesToAdd) {
294268 auto it = indirectCalls.find (k);
295269
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.
270+ // No need to add this. It wasn't in the map because no function has this
271+ // type, so there are no effects to aggregate and we can forget about it.
298272 if (it == indirectCalls.end ()) continue ;
299273
300274 it->second .insert (v.begin (), v.end ());
301275 }
302276
303277 auto a = transitiveClosure2<HeapType>(indirectCalls);
304278
279+ // Pretend that each subtype is indirect called by its supertype.
280+ // This might not be the case but it's accurate enough since any caller that
281+ // may indirect call a given type may also indirect call its subtype.
305282 for (const auto & [k, v]: indirectCallersNonTransitive) {
306283 for (const auto & x : v) {
307284 auto y = a[x];
@@ -313,16 +290,17 @@ struct GenerateGlobalEffects : public Pass {
313290 }
314291
315292 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- // }
293+
294+ // Compute the transitive closure of effects. To do so, first construct for
295+ // each function a list of the functions that it is called by (so we need to
296+ // propagate its effects to them), and then we'll construct the closure of
297+ // that.
298+ //
299+ // callers[foo] = [func that calls foo, another func that calls foo, ..]
300+ //
301+ std::unordered_map<Name, std::unordered_set<Name>> callers =
302+ transitiveClosure (*module , funcInfos);
303+
326304
327305 // Now that we have transitively propagated all static calls, apply that
328306 // information. First, apply infinite recursion: if a function can call
0 commit comments