@@ -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
135161std::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
206243struct 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 ) {
0 commit comments