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() {
181 ModuleOpInterface
module;
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 *> {
445 return {node->
begin(), &getChild};
448 return {node->
end(), &getChild};
454struct llvm::GraphTraits<
llvm::Inverse<circt::igraph::InstanceGraphNode *>> {
467 return inverse.Graph;
473 return {node->
usesEnd(), &getParent};
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)
599 llvm::map_range(path, [](
auto op) {
return op.getAsOpaquePointer(); });
600 return llvm::hash_combine_range(range.begin(), range.end());
assert(baseType &&"element must be base type")
This is a Node in the InstanceGraph.
llvm::iterator_range< UseIterator > uses()
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.
ModuleOpInterface InstanceList instances
The module.
UseIterator usesBegin()
Iterate the instance records which instantiate this module.
llvm::iplist< InstanceRecord > InstanceList
size_t getNumUses()
Get the number of direct instantiations of this 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
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.
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)
DenseMap< Operation *, ArrayRef< InstancePath > > PathsCache
ArrayRef< InstancePath > getAbsolutePaths(ModuleOpInterface op)
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 circt::igraph::InstancePath getTombstoneKey()
static bool isEqual(circt::igraph::InstancePath lhs, circt::igraph::InstancePath rhs)
static llvm::hash_code getHashValue(circt::igraph::InstancePath path)
static circt::igraph::InstancePath getEmptyKey()
static NodeRef getEntryNode(NodeRef node)
static ChildIteratorType child_begin(NodeRef node)
static NodeRef getChild(const circt::igraph::InstanceRecord *record)
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)
static nodes_iterator nodes_end(circt::igraph::InstanceGraph *graph)
llvm::mapped_iterator< NodeType::UseIterator, decltype(&getParent)> ChildIteratorType
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)