Compute effects for indirect calls in GlobalEffects#8609
Compute effects for indirect calls in GlobalEffects#8609stevenfontanella wants to merge 2 commits intomainfrom
Conversation
b7ce0b6 to
9fcf76b
Compare
9fcf76b to
0e28a7a
Compare
0e28a7a to
83f4b3b
Compare
83f4b3b to
3a25c2e
Compare
| auto& callees = callGraph[func]; | ||
| for (Name callee : info.calledFunctions) { | ||
| callees.insert(module.getFunction(callee)); | ||
| std::unordered_set<HeapType> allFunctionTypes; |
There was a problem hiding this comment.
| std::unordered_set<HeapType> allFunctionTypes; | |
| // In closed world [..] | |
| std::unordered_set<HeapType> allFunctionTypes; |
There was a problem hiding this comment.
Not sure if I got the comment, you wanted the below comment about open world, or did you want a comment explaining why we're noting allFunctionTypes?
There was a problem hiding this comment.
I was just suggesting that, after the previous comment that documents what we do in open world, we could document briefly how closed world is different.
There was a problem hiding this comment.
(Though if we merge the loops as I suggested elsewhere, maybe neither is needed?)
| callGraph[caller->type.getHeapType()].insert(caller); | ||
| } | ||
|
|
||
| SubTypes subtypes(module); |
There was a problem hiding this comment.
Since we already have all the function types, we can just walk up their supertype chains to construct the edges from supertypes to subtypes rather than using a SubTypes object. This is better because constructing a SubTypes is very expensive; it traverses the entire module to find all the types.
| std::vector<std::optional<EffectAnalyzer>> componentEffects; | ||
| // Points to an index in componentEffects | ||
| std::unordered_map<Function*, Index> funcComponents; | ||
| std::unordered_map<CallGraphNode, Index> funcComponents; |
There was a problem hiding this comment.
| std::unordered_map<CallGraphNode, Index> funcComponents; | |
| std::unordered_map<CallGraphNode, Index> nodeComponents; |
| // We only care about Functions that are roots, not types | ||
| // A type would be a root if a function exists with that type, but no-one | ||
| // indirect calls the type. | ||
| std::vector<CallGraphNode> allFuncs; |
There was a problem hiding this comment.
I think this is fine, but it's more obviously correct to just pass all the graph nodes into the SCC utility. And then because we have C++20 now, we can avoid creating this vector entirely and use std::views::keys(callGraph) instead!
When running in --closed-world, compute effects for indirect calls by unioning the effects of all potential functions of that type. In --closed-world, we assume that all references originate in our module, so the only possible functions that we don't know about are imports. Previously we gave up on effects analysis for indirect calls.
Yields a very small byte count reduction in calcworker (3799354 - 3799297 = 57 bytes). Also shows no significant difference in runtime: (0.1346069 -> 0.13375045 = <1% improvement, probably within noise). We expect more benefits after we're able to share indirect call effects with other passes, since currently they're only seen one layer up for callers of functions that indirectly call functions (see the newly-added tests for examples).
Followups:
Part of #8615.