LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
CallGraph.h
Go to the documentation of this file.
1//===-- CallGraph.h ---------------------------------------------*- C++ -*-===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9
10#pragma once
11
12#include <mlir/Analysis/CallGraph.h>
13#include <mlir/Interfaces/CallInterfaces.h>
14
15#include <llvm/ADT/GraphTraits.h>
16#include <llvm/ADT/MapVector.h>
17#include <llvm/ADT/PointerIntPair.h>
18#include <llvm/ADT/SCCIterator.h>
19#include <llvm/ADT/SetVector.h>
20
21namespace mlir {
22
23class Operation;
24class CallOpInterface;
25class SymbolTableCollection;
26
27} // namespace mlir
28
29namespace llzk {
30
36class CallGraphNode {
37public:
39 class Edge {
40 enum class Kind : std::uint8_t {
41 // An 'Abstract' edge represents an opaque, non-operation, reference
42 // between this node and the target. Edges of this type are only valid
43 // from the external node (e.g., an external library call),
44 // as there is no valid connection to an operation in the module.
45 Abstract,
46
47 // A 'Call' edge represents a direct reference to the target node via a
48 // call-like operation within the callable region of this node.
49 Call,
50
51 // A 'Child' edge is used when the region of target node is defined inside
52 // of the callable region of this node. This means that the region of this
53 // node is an ancestor of the region for the target node. As such, this
54 // edge cannot be used on the 'external' node.
55 Child,
56 };
57
58 public:
60 bool isAbstract() const { return targetAndKind.getInt() == Kind::Abstract; }
61
63 bool isCall() const { return targetAndKind.getInt() == Kind::Call; }
64
66 bool isChild() const { return targetAndKind.getInt() == Kind::Child; }
67
70 CallGraphNode *getSource() const { return source; }
71
73 CallGraphNode *getTarget() const { return targetAndKind.getPointer(); }
74
75 bool operator==(const Edge &edge) const {
76 return source == edge.source && targetAndKind == edge.targetAndKind;
77 }
78
79 private:
80 Edge(CallGraphNode *src, CallGraphNode *target, Kind kind)
81 : source(src), targetAndKind(target, kind) {}
82 Edge(CallGraphNode *src, llvm::PointerIntPair<CallGraphNode *, 2, Kind> tgtAndKind)
83 : source(src), targetAndKind(tgtAndKind) {}
84
88
90 llvm::PointerIntPair<CallGraphNode *, 2, Kind> targetAndKind;
91
92 // Provide access to the constructor and Kind.
93 friend class CallGraphNode;
94 };
95
97 bool isExternal() const;
98
101 mlir::Region *getCallableRegion() const;
102
106 mlir::CallableOpInterface getCalledFunction() const;
107
111 void addAbstractEdge(CallGraphNode *node);
112
114 void addCallEdge(CallGraphNode *node);
115
117 void addChildEdge(CallGraphNode *child);
118
120 using iterator = mlir::SmallVectorImpl<Edge>::const_iterator;
121 iterator begin() const { return edges.begin(); }
122 iterator end() const { return edges.end(); }
123
124 llvm::iterator_range<iterator> edgesOut() const { return llvm::make_range(begin(), end()); }
125
127 bool hasChildren() const;
128
129private:
131 struct EdgeKeyInfo {
132 using SourceInfo = mlir::DenseMapInfo<CallGraphNode *>;
133 using BaseInfo = mlir::DenseMapInfo<llvm::PointerIntPair<CallGraphNode *, 2, Edge::Kind>>;
134
135 static Edge getEmptyKey() { return Edge(nullptr, BaseInfo::getEmptyKey()); }
136 static Edge getTombstoneKey() { return Edge(nullptr, BaseInfo::getTombstoneKey()); }
137 static unsigned getHashValue(const Edge &edge) {
138 return SourceInfo::getHashValue(edge.source) ^ BaseInfo::getHashValue(edge.targetAndKind);
139 }
140 static bool isEqual(const Edge &lhs, const Edge &rhs) { return lhs == rhs; }
141 };
142
143 CallGraphNode(mlir::Region *callable) : callableRegion(callable) {}
144
146 void addEdge(CallGraphNode *node, Edge::Kind kind);
147
151 mlir::Region *callableRegion;
152
154 mlir::SetVector<Edge, mlir::SmallVector<Edge, 4>, llvm::SmallDenseSet<Edge, 4, EdgeKeyInfo>>
155 edges;
156
157 // Provide access to private methods.
158 friend class CallGraph;
159};
160
165 using NodeMapT = llvm::MapVector<mlir::Region *, std::unique_ptr<CallGraphNode>>;
166
169 class NodeIterator final
170 : public llvm::mapped_iterator<
171 NodeMapT::const_iterator, CallGraphNode *(*)(const NodeMapT::value_type &)> {
172 static CallGraphNode *unwrap(const NodeMapT::value_type &value) { return value.second.get(); }
173
174 public:
176 NodeIterator(NodeMapT::const_iterator it)
177 : llvm::mapped_iterator<
178 NodeMapT::const_iterator, CallGraphNode *(*)(const NodeMapT::value_type &)>(
179 it, &unwrap
180 ) {}
181 };
182
183public:
184 CallGraph(mlir::Operation *op);
185
189 CallGraphNode *getOrAddNode(mlir::Region *region, CallGraphNode *parentNode);
190
193 CallGraphNode *lookupNode(mlir::Region *region) const;
194
197 return const_cast<CallGraphNode *>(&externalCallerNode);
198 }
199
202 return const_cast<CallGraphNode *>(&unknownCalleeNode);
203 }
204
210 resolveCallable(mlir::CallOpInterface call, mlir::SymbolTableCollection &symbolTable) const;
211
213 void eraseNode(CallGraphNode *node);
214
216 using iterator = NodeIterator;
217 iterator begin() const { return nodes.begin(); }
218 iterator end() const { return nodes.end(); }
219
220 size_t size() const { return nodes.size(); }
221
223 void dump() const;
224 void print(llvm::raw_ostream &os) const;
225
226private:
228 NodeMapT nodes;
229
231 CallGraphNode externalCallerNode;
232
234 CallGraphNode unknownCalleeNode;
235};
236
237} // namespace llzk
238
239namespace llvm {
240// Provide graph traits for traversing call graphs using standard graph
241// traversals.
242template <> struct GraphTraits<const llzk::CallGraphNode *> {
244 static NodeRef getEntryNode(NodeRef node) { return node; }
245
246 static NodeRef unwrap(const llzk::CallGraphNode::Edge &edge) { return edge.getTarget(); }
247
248 // ChildIteratorType/begin/end - Allow iteration over all nodes in the graph.
249 using ChildIteratorType = mapped_iterator<llzk::CallGraphNode::iterator, decltype(&unwrap)>;
250 static ChildIteratorType child_begin(NodeRef node) { return {node->begin(), &unwrap}; }
251 static ChildIteratorType child_end(NodeRef node) { return {node->end(), &unwrap}; }
252};
253
254template <>
255struct GraphTraits<const llzk::CallGraph *> : public GraphTraits<const llzk::CallGraphNode *> {
257 static NodeRef getEntryNode(const llzk::CallGraph *cg) { return cg->getExternalCallerNode(); }
258
259 // nodes_iterator/begin/end - Allow iteration over all nodes in the graph
261 static nodes_iterator nodes_begin(llzk::CallGraph *cg) { return cg->begin(); }
262 static nodes_iterator nodes_end(llzk::CallGraph *cg) { return cg->end(); }
263};
264} // namespace llvm
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation source
Definition LICENSE.txt:28
This class represents a directed edge between two nodes in the callgraph.
Definition CallGraph.h:39
bool isChild() const
Returns true if this edge represents a Child edge.
Definition CallGraph.h:66
CallGraphNode * getTarget() const
Returns the target node for this edge.
Definition CallGraph.h:73
bool operator==(const Edge &edge) const
Definition CallGraph.h:75
bool isCall() const
Returns true if this edge represents a Call edge.
Definition CallGraph.h:63
CallGraphNode * getSource() const
Returns the source node of this edge.
Definition CallGraph.h:70
bool isAbstract() const
Returns true if this edge represents an Abstract edge.
Definition CallGraph.h:60
friend class CallGraphNode
Definition CallGraph.h:93
This is a simple port of the mlir::CallGraphNode with llzk::CallGraph as a friend class,...
Definition CallGraph.h:36
friend class CallGraph
Definition CallGraph.h:158
bool isExternal() const
Returns true if this node is an external node.
Definition CallGraph.cpp:39
mlir::SmallVectorImpl< Edge >::const_iterator iterator
Iterator over the outgoing edges of this node.
Definition CallGraph.h:120
iterator begin() const
Definition CallGraph.h:121
llvm::iterator_range< iterator > edgesOut() const
Definition CallGraph.h:124
mlir::Region * getCallableRegion() const
Returns the callable region this node represents.
Definition CallGraph.cpp:43
void addChildEdge(CallGraphNode *child)
Adds a reference edge to the given child node.
Definition CallGraph.cpp:63
bool hasChildren() const
Returns true if this node has any child edges.
Definition CallGraph.cpp:66
void addCallEdge(CallGraphNode *node)
Add an outgoing call edge from this node.
Definition CallGraph.cpp:60
mlir::CallableOpInterface getCalledFunction() const
Returns the called function that the callable region represents.
Definition CallGraph.cpp:48
void addAbstractEdge(CallGraphNode *node)
Adds an abstract reference edge to the given node.
Definition CallGraph.cpp:54
iterator end() const
Definition CallGraph.h:122
This is a port of mlir::CallGraph that has been adapted to use the custom symbol lookup helpers (see ...
Definition CallGraph.h:164
size_t size() const
Definition CallGraph.h:220
CallGraph(mlir::Operation *op)
iterator begin() const
Definition CallGraph.h:217
iterator end() const
Definition CallGraph.h:218
CallGraphNode * getExternalCallerNode() const
Return the callgraph node representing an external caller.
Definition CallGraph.h:196
NodeIterator iterator
An iterator over the nodes of the graph.
Definition CallGraph.h:216
void dump() const
Dump the graph in a human readable format.
void print(llvm::raw_ostream &os) const
void eraseNode(CallGraphNode *node)
Erase the given node from the callgraph.
CallGraphNode * resolveCallable(mlir::CallOpInterface call, mlir::SymbolTableCollection &symbolTable) const
Resolve the callable for given callee to a node in the callgraph, or the external node if a valid nod...
CallGraphNode * lookupNode(mlir::Region *region) const
Lookup a call graph node for the given region, or nullptr if none is registered.
CallGraphNode * getUnknownCalleeNode() const
Return the callgraph node representing an indirect callee.
Definition CallGraph.h:201
CallGraphNode * getOrAddNode(mlir::Region *region, CallGraphNode *parentNode)
Get or add a call graph node for the given region.
static ChildIteratorType child_begin(NodeRef node)
Definition CallGraph.h:250
static NodeRef getEntryNode(NodeRef node)
Definition CallGraph.h:244
mapped_iterator< llzk::CallGraphNode::iterator, decltype(&unwrap)> ChildIteratorType
Definition CallGraph.h:249
static NodeRef unwrap(const llzk::CallGraphNode::Edge &edge)
Definition CallGraph.h:246
static ChildIteratorType child_end(NodeRef node)
Definition CallGraph.h:251
static nodes_iterator nodes_begin(llzk::CallGraph *cg)
Definition CallGraph.h:261
static nodes_iterator nodes_end(llzk::CallGraph *cg)
Definition CallGraph.h:262
static NodeRef getEntryNode(const llzk::CallGraph *cg)
The entry node into the graph is the external node.
Definition CallGraph.h:257
llzk::CallGraph::iterator nodes_iterator
Definition CallGraph.h:260