1515 */
1616
1717//
18- // Handle the computation of global effects. The effects are stored on the
19- // PassOptions structure ; see more details there.
18+ // Handle the computation of global effects. The effects are stored on
19+ // Function::effects ; see more details there.
2020//
2121
22+ #include " ir/subtypes.h"
2223#include " ir/effects.h"
2324#include " ir/module-utils.h"
2425#include " pass.h"
@@ -39,6 +40,9 @@ struct FuncInfo {
3940
4041 // Directly-called functions from this function.
4142 std::unordered_set<Name> calledFunctions;
43+
44+ // Types that are targets of indirect calls.
45+ std::unordered_set<HeapType> indirectCalledTypes;
4246};
4347
4448std::map<Function*, FuncInfo> analyzeFuncs (Module& module ,
@@ -84,11 +88,16 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
8488 // Note the direct call.
8589 funcInfo.calledFunctions .insert (call->target );
8690 } else if (effects.calls ) {
87- // This is an indirect call of some sort, so we must assume the
88- // worst. To do so, clear the effects, which indicates nothing
89- // is known (so anything is possible).
90- // TODO: We could group effects by function type etc.
91- funcInfo.effects = UnknownEffects;
91+ HeapType type;
92+ if (auto * callRef = curr->dynCast <CallRef>()) {
93+ type = callRef->target ->type .getHeapType ();
94+ } else if (auto * callIndirect = curr->dynCast <CallIndirect>()) {
95+ type = callIndirect->heapType ;
96+ } else {
97+ assert (false && " Unexpected type of call" );
98+ }
99+
100+ funcInfo.indirectCalledTypes .insert (type);
92101 } else {
93102 // No call here, but update throwing if we see it. (Only do so,
94103 // however, if we have effects; if we cleared it - see before -
@@ -107,43 +116,54 @@ std::map<Function*, FuncInfo> analyzeFuncs(Module& module,
107116 return std::move (analysis.map );
108117}
109118
119+ using CallGraphNode = std::variant<Name, HeapType>;
120+
110121// Propagate effects from callees to callers transitively
111122// e.g. if A -> B -> C (A calls B which calls C)
112123// Then B inherits effects from C and A inherits effects from both B and C.
113124void propagateEffects (
114125 const Module& module ,
115- const std::unordered_map<Name , std::unordered_set<Name >>& reverseCallGraph,
126+ const std::unordered_map<CallGraphNode , std::unordered_set<CallGraphNode >>& reverseCallGraph,
116127 std::map<Function*, FuncInfo>& funcInfos) {
117128
118- UniqueNonrepeatingDeferredQueue<std::pair<Name, Name>> work;
129+ using CallGraphEdge = std::pair<CallGraphNode, CallGraphNode>;
130+ UniqueNonrepeatingDeferredQueue<CallGraphEdge> work;
119131
120132 for (const auto & [callee, callers] : reverseCallGraph) {
121133 for (const auto & caller : callers) {
122134 work.push (std::pair (callee, caller));
123135 }
124136 }
125137
126- auto propagate = [&](Name callee, Name caller) {
127- auto & callerEffects = funcInfos.at (module .getFunction (caller)).effects ;
138+ auto propagate = [&](Name* callee, Name* caller) {
139+ if (callee == nullptr || caller == nullptr ) {
140+ return ;
141+ }
142+
143+ auto & callerEffects = funcInfos.at (module .getFunction (*caller)).effects ;
128144 const auto & calleeEffects =
129- funcInfos.at (module .getFunction (callee)).effects ;
130- if (! callerEffects) {
145+ funcInfos.at (module .getFunction (* callee)).effects ;
146+ if (callerEffects == UnknownEffects ) {
131147 return ;
132148 }
133149
134- if (! calleeEffects) {
150+ if (calleeEffects == UnknownEffects ) {
135151 callerEffects = UnknownEffects;
136152 return ;
137153 }
138154
139- callerEffects->mergeIn (*calleeEffects);
155+ if (*callee == *caller) {
156+ callerEffects->trap = true ;
157+ } else {
158+ callerEffects->mergeIn (*calleeEffects);
159+ }
140160 };
141161
142162 while (!work.empty ()) {
143163 auto [callee, caller] = work.pop ();
144164
145- if (callee == caller) {
146- auto & callerEffects = funcInfos.at (module .getFunction (caller)).effects ;
165+ if (std::get_if<Name>(& callee) == std::get_if<Name>(& caller) && std::holds_alternative<Name>(callee) ) {
166+ auto & callerEffects = funcInfos.at (module .getFunction (std::get<Name>( caller) )).effects ;
147167 if (callerEffects) {
148168 callerEffects->trap = true ;
149169 }
@@ -152,14 +172,14 @@ void propagateEffects(
152172 // Even if nothing changed, we still need to keep traversing the callers
153173 // to look for a potential cycle which adds a trap affect on the above
154174 // lines.
155- propagate (callee, caller);
175+ propagate (std::get_if<Name>(& callee), std::get_if<Name>(& caller) );
156176
157177 const auto & callerCallers = reverseCallGraph.find (caller);
158178 if (callerCallers == reverseCallGraph.end ()) {
159179 continue ;
160180 }
161181
162- for (const Name & callerCaller : callerCallers->second ) {
182+ for (const CallGraphNode & callerCaller : callerCallers->second ) {
163183 work.push (std::pair (callee, callerCaller));
164184 }
165185 }
@@ -171,11 +191,35 @@ struct GenerateGlobalEffects : public Pass {
171191 analyzeFuncs (*module , getPassOptions ());
172192
173193 // callee : caller
174- std::unordered_map<Name, std::unordered_set<Name>> callers;
194+ std::unordered_map<CallGraphNode, std::unordered_set<CallGraphNode>> callers;
195+
196+ std::unordered_set<HeapType> allIndirectCalledTypes;
175197 for (const auto & [func, info] : funcInfos) {
198+ // Name -> Name for direct calls
176199 for (const auto & callee : info.calledFunctions ) {
177200 callers[callee].insert (func->name );
178201 }
202+
203+ // HeapType -> Name for indirect calls
204+ for (const auto & calleeType : info.indirectCalledTypes ) {
205+ callers[calleeType].insert (func->name );
206+ }
207+
208+ // Name -> HeapType for function types
209+ callers[func->name ].insert (func->type .getHeapType ());
210+
211+ allIndirectCalledTypes.insert (func->type .getHeapType ());
212+ }
213+
214+ SubTypes subtypes (*module );
215+ for (auto type : allIndirectCalledTypes) {
216+ subtypes.iterSubTypes (type, [&callers, type](HeapType sub, int _) {
217+ // HeapType -> HeapType
218+ // A subtype is a 'callee' of its supertype. Supertypes need to inherit effects from their subtypes
219+ // See the example in (TODO)
220+ callers[sub].insert (type);
221+ return true ;
222+ });
179223 }
180224
181225 propagateEffects (*module , callers, funcInfos);
0 commit comments