13#ifndef CIRCT_SUPPORT_INSTANCEGRAPH_H
14#define CIRCT_SUPPORT_INSTANCEGRAPH_H
17#include "mlir/IR/OpDefinition.h"
18#include "llvm/ADT/GraphTraits.h"
19#include "llvm/ADT/PostOrderIterator.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/ADT/iterator.h"
22#include "llvm/Support/DOTGraphTraits.h"
35 :
public llvm::mapped_iterator<It, typename It::pointer (*)(
36 typename It::reference)> {
40 static typename Iterator::value_type *
41 addrOf(
typename Iterator::value_type &v)
noexcept {
42 return std::addressof(v);
45 :
llvm::mapped_iterator<It, typename
Iterator::pointer (*)(
46 typename
Iterator::reference)>(iterator,
55class InstanceGraphNode;
60 :
public llvm::ilist_node_with_parent<InstanceRecord, InstanceGraphNode> {
63 template <
typename TTarget = InstanceOpInterface>
65 if constexpr (std::is_same<TTarget, InstanceOpInterface>::value)
67 return dyn_cast_or_null<TTarget>(
instance.getOperation());
117 template <
typename TTarget = ModuleOpInterface>
119 if constexpr (std::is_same<TTarget, ModuleOpInterface>::value)
121 return cast<TTarget>(
module.getOperation());
140 :
public llvm::iterator_facade_base<
141 UseIterator, std::forward_iterator_tag, InstanceRecord *> {
145 using llvm::iterator_facade_base<
UseIterator, std::forward_iterator_tag,
163 llvm::iterator_range<UseIterator>
uses() {
223 return lookup(op.getModuleNameAttr());
230 assert(node !=
nullptr &&
"Module not in InstanceGraph!");
237 assert(node !=
nullptr &&
"Module not in InstanceGraph!");
246 ModuleOpInterface child, ModuleOpInterface
parent,
275 template <
typename Fn>
283 template <
typename Fn>
305 InstanceOpInterface newInst);
321 llvm::DenseMap<Attribute, InstanceGraphNode *>
nodeMap;
338 InstanceOpInterface
top()
const {
343 InstanceOpInterface
leaf()
const {
353 ArrayRef<InstanceOpInterface>::iterator
begin()
const {
return path.begin(); }
354 ArrayRef<InstanceOpInterface>::iterator
end()
const {
return path.end(); }
362 void print(llvm::raw_ostream &into)
const;
370 ArrayRef<InstanceOpInterface>
path;
396 void replaceInstance(InstanceOpInterface oldOp, InstanceOpInterface newOp);
408 using PathsCache = DenseMap<Operation *, ArrayRef<InstancePath>>;
431struct llvm::GraphTraits<
circt::igraph::InstanceGraphNode *> {
454struct llvm::GraphTraits<
llvm::Inverse<circt::igraph::InstanceGraphNode *>> {
467 return inverse.Graph;
489struct llvm::GraphTraits<
circt::igraph::InstanceGraph *>
490 :
public llvm::GraphTraits<circt::igraph::InstanceGraphNode *> {
498 return graph->
begin();
508struct llvm::DOTGraphTraits<
circt::igraph::InstanceGraph *>
509 :
public llvm::DefaultDOTGraphTraits {
510 using DefaultDOTGraphTraits::DefaultDOTGraphTraits;
515 return node->
getModule().getModuleName().str();
518 template <
typename Iterator>
523 auto *instanceRecord = *it.getCurrent();
524 auto instanceOp = instanceRecord->getInstance();
525 return (
"label=" + instanceOp.getInstanceName()).str();
539template <
typename Fn>
541 constexpr bool fallible =
542 std::is_invocable_r_v<LogicalResult, Fn &, InstanceGraphNode &>;
543 DenseSet<InstanceGraphNode *> visited;
544 for (
auto &root :
nodes) {
545 for (
auto *node : llvm::post_order_ext(&root, visited)) {
546 if constexpr (fallible) {
547 if (failed(fn(*node)))
554 if constexpr (fallible)
558template <
typename Fn>
560 constexpr bool fallible =
561 std::is_invocable_r_v<LogicalResult, Fn &, InstanceGraphNode &>;
562 DenseSet<InstanceGraphNode *> visited;
563 for (
auto &root :
nodes) {
564 for (
auto *node : llvm::inverse_post_order_ext(&root, visited)) {
565 if constexpr (fallible) {
566 if (failed(fn(*node)))
573 if constexpr (fallible)
592 llvm::map_range(path, [](
auto op) {
return op.getAsOpaquePointer(); });
593 return llvm::hash_combine_range(range.begin(), range.end());
assert(baseType &&"element must be base type")
false return failure()
Parse an optional keyword or string and set instance into 'result'.
This is a Node in the InstanceGraph.
llvm::iterator_range< UseIterator > uses()
friend class InstanceRecord
detail::AddressIterator< InstanceList::iterator > iterator
Iterate the instance records in this module.
InstanceRecord * firstUse
List of instances which instantiate this module.
bool noUses()
Return true if there are no more instances of this module.
InstanceRecord * addInstance(InstanceOpInterface instance, InstanceGraphNode *target)
Record a new instance op in the body of this module.
InstanceGraphNode(const InstanceGraphNode &)=delete
auto getModule()
Get the module that this node is tracking.
InstanceList instances
List of instance operations in this module.
UseIterator usesBegin()
Iterate the instance records which instantiate this module.
llvm::iplist< InstanceRecord > InstanceList
friend class InstanceGraph
Iterates over the handshake::FuncOp's in the program to build an instance graph.
size_t getNumUses()
Get the number of direct instantiations of this module.
ModuleOpInterface module
The module.
bool hasOneUse()
Return true if this module has exactly one use.
void recordUse(InstanceRecord *record)
Record that a module instantiates this module.
This graph tracks modules and where they are instantiated.
virtual ~InstanceGraph()=default
InstanceGraphNode * lookupOrNull(StringAttr name)
Lookup an module by name.
Operation * getParent()
Return the parent under which all nodes are nested.
virtual InstanceGraphNode * addModule(ModuleOpInterface module)
Add a newly created module to the instance graph.
Operation * parent
The node under which all modules are nested.
llvm::DenseMap< Attribute, InstanceGraphNode * > nodeMap
This maps each operation to its graph node.
virtual void replaceInstance(InstanceOpInterface inst, InstanceOpInterface newInst)
Replaces an instance of a module with another instance.
virtual InstanceGraphNode * getTopLevelNode()
Get the node corresponding to the top-level module of a circuit.
FailureOr< llvm::ArrayRef< InstanceGraphNode * > > getInferredTopLevelNodes()
Get the nodes corresponding to the inferred top-level modules of a circuit.
llvm::SmallVector< InstanceGraphNode * > inferredTopLevelNodes
A caching of the inferred top level module(s).
NodeList nodes
The storage for graph nodes, with deterministic iteration.
virtual void erase(InstanceGraphNode *node)
Remove this module from the instance graph.
decltype(auto) walkPostOrder(Fn &&fn)
Perform a post-order walk across the modules.
InstanceGraphNode * lookup(ModuleOpInterface op)
Look up an InstanceGraphNode for a module.
bool isAncestor(ModuleOpInterface child, ModuleOpInterface parent, llvm::function_ref< bool(InstanceRecord *)> skipInstance=[](InstanceRecord *_) { return false;})
Check if child is instantiated by a parent.
InstanceGraphNode * lookup(StringAttr name)
Lookup an module by name. Aborts if the module does not exist.
detail::AddressIterator< NodeList::iterator > iterator
Iterate through all modules.
InstanceGraph(const InstanceGraph &)=delete
InstanceGraphNode * getOrAddNode(StringAttr name)
Get the node corresponding to the module.
InstanceGraphNode * operator[](ModuleOpInterface op)
Lookup an InstanceGraphNode for a module.
InstanceGraphNode * lookupOrNull(ModuleOpInterface op)
Look up an InstanceGraphNode for a module.
decltype(auto) walkInversePostOrder(Fn &&fn)
Perform an inverse-post-order walk across the modules.
llvm::iplist< InstanceGraphNode > NodeList
This is the list of InstanceGraphNodes in the graph.
InstanceGraph(Operation *parent)
Create a new module graph of a circuit.
static NodeList InstanceGraph::* getSublistAccess(Operation *)
Returns pointer to member of operation list.
ModuleOpInterface getReferencedModuleImpl(InstanceOpInterface op)
An instance path composed of a series of instances.
InstanceOpInterface leaf() const
bool operator==(const InstancePath &that) const
InstanceOpInterface operator[](size_t idx) const
ArrayRef< InstanceOpInterface > path
ArrayRef< InstanceOpInterface > getPath() const
InstancePath(ArrayRef< InstanceOpInterface > path)
void print(llvm::raw_ostream &into) const
Print the path to any stream-like object.
ArrayRef< InstanceOpInterface >::iterator begin() const
ArrayRef< InstanceOpInterface >::iterator end() const
InstancePath dropFront() const
InstancePath dropBack() const
InstanceOpInterface top() const
friend struct InstancePathCache
This is an edge in the InstanceGraph.
InstanceGraphNode * getParent() const
Get the module where the instantiation lives.
auto getInstance()
Get the instance-like op that this is tracking.
void erase()
Erase this instance record, removing it from the parent module and the target's use-list.
InstanceGraphNode * target
This is the module which the instance-like is instantiating.
InstanceRecord * nextUse
Intrusive linked list for other uses.
friend class InstanceGraphNode
friend class InstanceGraph
Iterates over the handshake::FuncOp's in the program to build an instance graph.
InstanceOpInterface instance
The InstanceLike that this is tracking.
InstanceGraphNode * getTarget() const
Get the module which the instance-like is instantiating.
InstanceRecord(InstanceGraphNode *parent, InstanceOpInterface instance, InstanceGraphNode *target)
InstanceGraphNode * parent
This is the module where the instantiation lives.
InstanceRecord(const InstanceRecord &)=delete
llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const InstancePath &path)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Iterator for module uses.
UseIterator(InstanceGraphNode *node)
bool operator==(const UseIterator &other) const
UseIterator & operator++()
InstanceRecord * operator*() const
A data structure that caches and provides paths to module instances in the IR.
ArrayRef< InstancePath > getPaths(ModuleOpInterface op, InstanceGraphNode *top, PathsCache &cache)
ArrayRef< InstancePath > getAbsolutePaths(ModuleOpInterface op)
DenseMap< Operation *, ArrayRef< InstancePath > > PathsCache
ArrayRef< InstancePath > getRelativePaths(ModuleOpInterface op, InstanceGraphNode *node)
DenseMap< InstanceGraphNode *, PathsCache > relativePathsCache
Cached relative instance paths.
void replaceInstance(InstanceOpInterface oldOp, InstanceOpInterface newOp)
Replace an InstanceOp. This is required to keep the cache updated.
InstancePath prependInstance(InstanceOpInterface inst, InstancePath path)
Prepend an instance to a path.
InstancePath appendInstance(InstancePath path, InstanceOpInterface inst)
Append an instance to a path.
InstancePath concatPath(InstancePath path1, InstancePath path2)
Concatenate two paths.
llvm::BumpPtrAllocator allocator
An allocator for individual instance paths and entire path lists.
InstanceGraph & instanceGraph
The instance graph of the IR.
PathsCache absolutePathsCache
Cached absolute instance paths.
InstancePathCache(InstanceGraph &instanceGraph)
This just maps a iterator of references to an iterator of addresses.
static Iterator::value_type * addrOf(typename Iterator::value_type &v) noexcept
AddressIterator(Iterator iterator)
static std::string getEdgeAttributes(const circt::igraph::InstanceGraphNode *node, Iterator it, circt::igraph::InstanceGraph *)
static std::string getNodeLabel(circt::igraph::InstanceGraphNode *node, circt::igraph::InstanceGraph *)
static bool isEqual(circt::igraph::InstancePath lhs, circt::igraph::InstancePath rhs)
static llvm::hash_code getHashValue(circt::igraph::InstancePath path)
llvm::DenseMapInfo< ArrayRef< circt::igraph::InstanceOpInterface > > ArrayRefInfo
static NodeRef getEntryNode(NodeRef node)
static ChildIteratorType child_begin(NodeRef node)
static NodeRef getChild(const circt::igraph::InstanceRecord *record)
circt::igraph::InstanceGraphNode NodeType
llvm::mapped_iterator< NodeType::iterator, decltype(&getChild)> ChildIteratorType
static ChildIteratorType child_end(NodeRef node)
static nodes_iterator nodes_begin(circt::igraph::InstanceGraph *graph)
static NodeRef getEntryNode(circt::igraph::InstanceGraph *graph)
circt::igraph::InstanceGraph::iterator nodes_iterator
static nodes_iterator nodes_end(circt::igraph::InstanceGraph *graph)
static NodeRef getParent(const circt::igraph::InstanceRecord *record)
static ChildIteratorType child_end(NodeRef node)
static ChildIteratorType child_begin(NodeRef node)
static NodeRef getEntryNode(Inverse< NodeRef > inverse)
circt::igraph::InstanceGraphNode NodeType
llvm::mapped_iterator< NodeType::UseIterator, decltype(&getParent)> ChildIteratorType