-
Notifications
You must be signed in to change notification settings - Fork 298
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[HW/Support] Introduce InstanceGraph interface #5833
Conversation
Haven't had a chance to review this yet, but I know @darthscsi was working on something like this #5758 and #5706. |
@teqdruid Looks like i should read the ongoing PR list through a bit more thoroughly before starting stuff like this (to my defence, i was offline on a plane and needed something to do). |
332e556
to
22e0f4d
Compare
This change moves InstanceGraphBase to support, and introduces an interface for driving the implementation, `InstanceGraphInterface`, which essentially is an extraction of the name- and lookup related functions of `HWModuleLike/HWInstanceLike` (which now inherit from the `InstanceGraph` interfaces). The motivation for this is that multiple things in CIRCT may benefit from having graph iterators, and most/all of these will need an implementation exactly as what is given in InstanceGraphBase. My immediate usecase is to provide a graph for Ibis classes/containers, but things like handshake and FSM are other obvious users of this. The interface is named `InstanceGraphInterface`, but in practice naming it `CIRCTModuleInterface` or something similar would probably be more apt, seeing as the `InstanceGraph` is just a generic view of module-like things in CIRCT (which in turn is more generic than HWModule like) - LMKWYT. Implementing this change also performs some housekeeping in ensuring that all ops who inherit from the `HWModuleLike/HWInstanceLike` interfaces actually implements the name-related parts of the interface.
22e0f4d
to
f2aa070
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixing getReferencedModule is important, getInstance is a bit weird. Other than that, lgtm. Feel free to ignore my other PR.
|
||
/// This graph tracks modules and where they are instantiated. This is intended | ||
/// to be used as a cached analysis on FIRRTL circuits. This class can be used | ||
/// to walk the modules efficiently in a bottom-up or top-down order. | ||
/// | ||
/// To use this class, retrieve a cached copy from the analysis manager: | ||
/// auto &instanceGraph = getAnalysis<InstanceGraph>(getOperation()); | ||
class InstanceGraph : public hw::InstanceGraphBase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not completely convinced we need per-dialect versions of the InstanceGraph, but that isn't blocking for this.
auto getInstance() { | ||
if constexpr (std::is_same<TTarget, InstanceOpInterface>::value) | ||
return instance; | ||
return dyn_cast_or_null<TTarget>(instance.getOperation()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dyn_cast should be sufficient. instance should always be non-null.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is instance dyn_cast_or_null and module (below) is cast?
@@ -51,7 +55,12 @@ class InstanceRecord | |||
: public llvm::ilist_node_with_parent<InstanceRecord, InstanceGraphNode> { | |||
public: | |||
/// Get the instance-like op that this is tracking. | |||
HWInstanceLike getInstance() const { return instance; } | |||
template <typename TTarget = InstanceOpInterface> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was pondering this functionality too. An alternate would be an explicitly specialized implementation for InstanceOpInterface
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also considered simply overloading the function in the per-dialect versions, but that gets a bit messy (though would eliminate the need for the op interfaces).
@@ -96,7 +105,12 @@ class InstanceGraphNode : public llvm::ilist_node<InstanceGraphNode> { | |||
InstanceGraphNode() : module(nullptr) {} | |||
|
|||
/// Get the module that this node is tracking. | |||
HWModuleLike getModule() const { return module; } | |||
template <typename TTarget = ModuleOpInterface> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, an explicitly specialized version might be clearer.
let cppNamespace = "::circt::igraph"; | ||
|
||
let methods = [ | ||
InterfaceMethod<"Get the name of the instance", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Must all instances have names? This doesn't seem obviously true for all dialects. It seems primarily a requirement for pretty graph printing.
"::mlir::StringAttr", "getInstanceNameAttr", (ins)>, | ||
|
||
InterfaceMethod<"Get the name of the instantiated module", | ||
"::llvm::StringRef", "getReferencedModuleName", (ins), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we instead be returning a symbolRefAttr?
/*methodBody=*/[{}], | ||
/*defaultImplementation=*/[{ return $_op.getModuleNameAttr().getAttr(); }]>, | ||
|
||
InterfaceMethod<"Get the referenced module", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should have this operation without taking a symbol table. Code which uses this without a symbol table tends to have n^2 behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not using a symbol table also has significant foot-guns related to passes and threading. I've added a note.
@mortbopet I hope you'll forgive my minor changes and committing this when it's done with CI. I want to update my other work in progress based on this PR. |
@darthscsi no problem! |
This change moves InstanceGraphBase to support, and introduces an interface for driving the implementation,
InstanceGraphInterface
, which essentially is an extraction of the name and lookup related functions ofHWModuleLike/HWInstanceLike
(which now inherit from theInstanceGraph
interfaces). The motivation for this is that multiple things in CIRCT may benefit from having graph iterators, and most/all of these will need an implementation exactly as what is given inInstanceGraphBase
. My immediate usecase is to provide a graph interface for Ibis classes/containers (which don't have block argument/return values as ports, and thus aren'tHWModuleLike
), but things like handshake and FSM are other obvious users of this.The interface is named
InstanceGraphInterface
, but in reality this is just introducing an even more generic module/instance interface thanHWModuleLike
- that is, instances and modules without port info. Hence, we could name the interface something more appropriate, e.g.CIRCTModuleInterface
or something - LMKWYT.Implementing this change also performs some housekeeping which bloats the PR mainly by NFCs through:
HWModuleLike/HWInstanceLike
interfaces actually implements the name-related parts of the interface.hw
includes from InstanceGraph.