[Mlir-commits] [mlir] [mlir][CallGraph] Add edges for callable symbol references in CallGraph (PR #116177)
Haocong Lu
llvmlistbot at llvm.org
Thu Dec 5 04:59:48 PST 2024
================
@@ -93,42 +127,41 @@ static void computeCallGraph(Operation *op, CallGraph &cg,
for (Region ®ion : op->getRegions())
for (Operation &nested : region.getOps())
- computeCallGraph(&nested, cg, symbolTable, parentNode, resolveCalls);
+ computeCallGraph(&nested, cg, symbolTable, parentNode, resolveSymbolRef);
}
CallGraph::CallGraph(Operation *op)
: externalCallerNode(/*callableRegion=*/nullptr),
unknownCalleeNode(/*callableRegion=*/nullptr) {
// Make two passes over the graph, one to compute the callables and one to
- // resolve the calls. We split these up as we may have nested callable objects
- // that need to be reserved before the calls.
+ // resolve the calls and symbol references. We split these up as we may have
+ // nested callable objects that need to be reserved before the calls.
SymbolTableCollection symbolTable;
- computeCallGraph(op, *this, symbolTable, /*parentNode=*/nullptr,
- /*resolveCalls=*/false);
- computeCallGraph(op, *this, symbolTable, /*parentNode=*/nullptr,
- /*resolveCalls=*/true);
+ computeCallGraph(op, *this, symbolTable, getEntryNode(),
+ /*resolveSymbolRef=*/false);
+ computeCallGraph(op, *this, symbolTable, getEntryNode(),
+ /*resolveSymbolRef=*/true);
}
/// Get or add a call graph node for the given region.
CallGraphNode *CallGraph::getOrAddNode(Region *region,
CallGraphNode *parentNode) {
- assert(region && isa<CallableOpInterface>(region->getParentOp()) &&
+ Operation *parentOp = region->getParentOp();
+ assert(region && isa<CallableOpInterface>(parentOp) &&
"expected parent operation to be callable");
std::unique_ptr<CallGraphNode> &node = nodes[region];
if (!node) {
node.reset(new CallGraphNode(region));
// Add this node to the given parent node if necessary.
- if (parentNode) {
+ assert(parentNode && "expected non-empty parent node");
+ if (!parentNode->isExternal()) {
parentNode->addChildEdge(node.get());
- } else {
- // Otherwise, connect all callable nodes to the external node, this allows
- // for conservatively including all callable nodes within the graph.
- // FIXME This isn't correct, this is only necessary for callable nodes
- // that *could* be called from external sources. This requires extending
- // the interface for callables to check if they may be referenced
- // externally.
- externalCallerNode.addAbstractEdge(node.get());
+ } else if (auto symbolOp = dyn_cast<SymbolOpInterface>(parentOp)) {
+ // Otherwise, connect all symbol nodes with public visibility
+ // to the entry node, which may be referenced externally.
+ if (!symbolOp.canDiscardOnUseEmpty())
+ parentNode->addRefEdge(node.get());
----------------
Luhaocong wrote:
Although the default implementation of `canDiscardOnUseEmpty` is `getVisibility() != Visibility::Public`, I think it's a more accurate condition to indicate whether this node may be referenced somewhere. e.g. A public symbol with `canDiscardOnUseEmpty == true` must not be referenced by external node, but a private symbol with `canDiscardOnUseEmpty == false` should be considered as having potential references.
https://github.com/llvm/llvm-project/pull/116177
More information about the Mlir-commits
mailing list