Add a new pass, GroupSink/firrtl-group-sink, which will sink operations
that are only used by optional groups into optional groups. This is very
simple at present. This pass uses `mlir::controlFlowSink` to sink ops
into regions. This only works for very simple things in FIRRTL which have
normal SSA dominance, e.g., nodes, constants, or primitive operations.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This also simplifies the stage enable signals, seeing as the entry enable signal will now always be the last argument of any mlir block inside the pipeline.
Remove the now unused global reference operations and attributes. These
have been fully migrated to HierPathOp.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Basic driver analysis to detect must-driven values and hoist/rematerialize them using equivalent driver at instantiation site.
Disabled for HW signals to start. See PR for impact on some designs and discussion/details.
Converts an `ibis.method` into an `ibis.method.df` by converting
controlflow using `cf` to `handshake` dialect conversion applied to
the `ibis.method` body region.
Since AppIDs serve as system identifiers, they classify as a system
construction feature. So they should be in the ESI dialect, which will
be using them shortly.
Double-precision floating point type.
Add attribute, constant op, and parse + emit support.
Only support what we understand as floatingpoint in lexer for now, which includes exponent notation.
Add support to LowerClasses.
Ibis dataflow methods share the same interface as an `ibis.method` but without imperative CFG-based control flow. Instead, this method implements a graph region, and control flow is expected to be defined by dataflow operations.
A couple of minor refactors - more will come - to allow for using `CFToHandshake` on things other than just `func.func` as the source operation and `handshake.func` as the target operation.
Discovering AppIDs used to be a pass and only worked on `msft.module`s. Since we're removing them, make AppID discovery an API which creates dynamic instances from AppIDs. Since it'll primarily be used from PyCDE, expose to Python. Test through Python.
Will remove the discover appid pass in a subsequent PR. Progress on #6109.
Use the PrettyPrinter CallbackToken API, to record print events and store the
verilog output locations for each operation. Record the print begin and end
location of each op. This has a side-effect of updating the IR, location
attribute of the op is updated to include the verilog location range. `FusedLoc`
is used to record the location ranges and each op can correspond to multiple
verilog locations.
This feature is disabled by default under an emission flag `emitVerilogLocations`.
The prior motivation for a single return value was to enforce... well, exactly that. However, this is nothing but a pain, requiring the user to tupel/struct-ify return values at a high level. This is a trivial transformation that can be done down the line. Allowing multiple return values, however, allows this op to play much more nicely with other passes and code that expects function-like operations (and terminators of said ops) to -generally speaking - accept multiple return values.
Implement the python bindings for the `om.integer` attribute. Add support to
create `om::IntegerAttr` from `mlir::IntegerAttr`. Also ensure all tests use
`om::IntegerAttr` instead of `mlir::IntegerAttr`.
`argNames` and `resultNames` attributes were removed from HWModule (https://github.com/llvm/circt/pull/6095) in the presence of ModuleType but downstream python tools are relying these attributes for name look up. However currently there is no CAPI/Python API for ModuleType to query names of ports so this PR adds CAPI and bindings respectively in the same way to port types.
Inlines `ibis.sblock` operations, by creating MLIR blocks and `cf` operations, while adding annotations to the parent operation about `sblock`-specific attributes.
This PR restricts the clock gate op to solely use the clock type.
Uses in other dialects, especially Pipeline, were adjusted.
To maintain canonicalization behaviour, a clock constant op along with an attribute is also introduced to represent constant clocks and to fold ops to them.
... by requiring that handshake ops are nested within an operation that inherits the `FineGrainedDataflowRegionOpInterface`.
This is somewhat of a half-way solution, seeing as there isn't support for `HasParent` with an interface upstream. I've raised the issue and suggested a fix here https://github.com/llvm/llvm-project/pull/66196 but we'll see how long that takes to resolve.
Until then, added a `HasParentInterface` which does the same thing, albeit with a cryptic error message about which interface the parent op lacked (note: the whole issue here is that there isn't any name literal being generated for op interfaces).
I'll be monitoring the upstream stuff, and changing this over until then. For now, the motivation for adding this into circt is to unblock me in using handshake outside of a `handshake.func` while still having a restriction on where handshake ops can be used - i.e. i don't want to completely lift the `HasParent` restriction - users should still explicitly opt-into the fact that "using handshake => handshake ops is in a fine-grained dataflow region".
Make the `LowerState` pass allow operations to remain in the top-level
`arc.model` op after state lowering. This is necessary for lowering the
model op into an `eval` function in the future. Make use of this new
flexibility by inserting logic into the model that detects edges on the
clocks of the `arc.clock_tree` ops. The clock trees no longer trigger on
the clock itself, but are given an "enable" signal that indicates
whether a clock edge has been observed.
In the future, we'll want to schedule the ops in the `arc.model` and
lower it to a separate `eval` function, instead of throwing it away. In
doing so the user will no longer have to manually call clock functions,
but can call a singular `eval` function instead. A centralized function
that performs model execution will also allow us to properly simulate
clock edges occurring at the same time -- something which is impossible
today.
Together with the `arc.clock_domain` op, this `eval` function will make
the entire clock detection and grouping a performance optimization
instead of a required transformation. Theoretically, even if we did not
separate state with the same clock into dedicated clock functions, we'll
still be able to generate an `eval` function, with all logic inlined.
This will ultimately make the Arc dialect more robust and the transforms
more composable.
Adds a pass to lower operations. Currently, only lowering the boundary and inlining the op body is supported. Lowering of the body will be added in a separate commit since that is a bit more complex.
Rewrite the access analysis used in the `LegalizeStateUpdate` pass.
This pass is a known performance bottleneck in arcilator and causes poor
scaling to larger state spaces: on the `boom-small` benchmark in
`circt/arc-tests`, the analysis runs for >130s, which accounts for >95%
of the overall arcilator runtime.
This PR replaces the MLIR dataflow framework implementation of the
analysis with a custom one. The analysis requires only very sparse
traversal of the operations, which is a lot easier to implement with a
custom graph of nodes. On `boom-small` the new implementation takes
<200ms to complete.
Currently, all the pass base classes are included in all files
implementing one specific pass. This aims to reduce the amount of
unnecessarily included code.
Recreates `ibis.block` operations from a CFG. Any `ibis.block.attributes` operations at the parent operation will be added to the resulting blocks.
The IR is expected to be in maximal SSA form prior to this pass, given that the pass will only inspect the terminator operation of a block for any values that are generated within the block. Maximum SSA form thus ensures that any value defined within the block is never used outside of the block.
It is expected that `ibis.call` operations have been isolated into their own basic blocks before this pass is run. This implies that all operations within a block (except for the terminator operation) can be statically scheduled with each other.
Also adds changes to the Ibis method op to make it more "imperative". This is under the assumption that we want to use the method op as the container of choice while going through "impeartive" lowering steps (i.e. all steps wherein we expect to keep around `cf` and MLIR blocks).
Hardware designs commonly have a considerable amount of duplicated logic
for parallel execution (e.g., multiple cores). This logic can be
collected and vectorized. This operation allows us to separate the
concerns of finding logic to vectorize, applying a cost model on whether
it is actually worth vectorizing the found set of operations (since
gather, scatter, shuffling might be more expensive than what we save
from vectorizing), and performing the actual vectorization to SIMD
registers or pack them within a scalar register.
This adds the FreezePaths pass which performs the final lowering of path
operations after ExportVerilog. This prepares the OMIR be split from the
hardware by transforming the dynamic hardware references in to frozen
attributes.
In situations where an object is instantiated and passed to a sink
that expects any reference, we need to cast away the object's type to
AnyRef type. This adds an operation to accomplish this, and inserts it
when necessary in the parser.
Now that the Python bindings for ClassType can return a Python object
of the actual ClassType Python class, it would be useful to get the
ClassType's name from such an object. This includes the usual C API
boilerplate to call the accessor in C++, and the usual Python wrapper
to return a string through pybind.
A relatively new feature of MLIR Python bindings allows returned
MlirTypes to automatically be downcast to the actual concrete Python
class for the type. To enable this, a C API to get the type's TypeID
must be provided, and the rest just works. Opt-in for the OM dialect's
ClassType.
Don't do this by default, as code reasonably expects the returned
FieldRef has expected type if indexed to the specified fieldID,
however when this is used for producing names just walk through
the cast operations to find the originating declaration.
This PR add Evaluator support for Map values.
* EvaluatorValue now takes a MLIR context as a member to make it easy to
construct attributes from evaluated values.
* MapValue is added and created from om.map_create.
* CAPIs for MapType and StringType are added.
Will be removing the outlined pipeline lowering. It's dumb to have to support two separate, but similar lowerings. Instead, rely on the inline lowering, and down the road, implement a "stage extraction" pass to extract operations that reside within the same logical stage after-the-fact by annotating ops during inline conversion.
A channel bundle (sometimes referred to as just "bundle") is a set of channels of associated signals, along with per-channel names and directions. The prototypical example for a bundle is a request-response channel pair.
This was never used and it adds a bunch of complexity and maintainence
burden. If we want to revive it at some point in the future, we can but
I don't see that happening.
This is conceptually similar to Class type, but represents a reference
to any class. It is opaque, like a void pointer, so it can be passed
around but not "deferenced". For example, accessing a subfield of the
referred to object is illegal.
The AnyType is used to represent any valid OM type, without needing to
declare it. The AnyType cast can cast any value to AnyType. This is
useful when dealing with values opaquely in a limited way.
The `ibis.block` operation defines a block wherein a group of operations are expected to be statically scheduleable. The operation is not isolated from above to facilitate ease of construction. However, once a program has been constructed and lowered to a sufficient level, the user may run `--ibis-argify-blocks` to effectively isolate the block from above, by converting SSA values referenced through dominanes into arguments of the block
The block may contain additional attributes to specify constraints on the block further down the compilation pipeline.
This operation subsumes the `ibis.schedule` in that `ibis.schedule` has the same semantics as if we attach some scheduling constraint attribute to the block.
The `ibis.block` operation defines a block wherein a group of operations are expected to be statically scheduleable. The operation is not isolated from above to facilitate ease of construction. However, once a program has been constructed and lowered to a sufficient level, the user may run `--ibis-argify-blocks` to effectively isolate the block from above, by converting SSA values referenced through dominanes into arguments of the block
The block may contain additional attributes to specify constraints on the block further down the compilation pipeline.
This operation subsumes the `ibis.schedule` in that `ibis.schedule` has the same semantics as if we attach some scheduling constraint attribute to the block.
This PR adds a light wrapper on top of instance path. With this wrapper, a subsequent PR should be able to de-duplicate instance paths to save on memory usage and provide quick comparison operators.
HW enumeration was also fixed and a unit test preserves behaviour.
Fixes a bug where an inout input was being eliminated which resulted in the block argument list shifting, but input->output replacements were not being updated correctly.
Fixed by keeping to-be-output values as temporary operations instead of an in-memory array of values. By doing so, any value replacements performed by other patterns will also affect the temporary output operations.
... that pattern should maybe be factored out and given a name - seems like a generic thing where we want to store a value for later use, but that value may be replaced at any point in time.
- Parser support in the FIRParser
- New ExtClassOp in the firrtl dialect for extclasses
- New ClassLike op interface in firrtl
- LowerClasses:
- Lower firrtl.extclasses to om.class.extern
- Legalize om.class.extern.field ops
Be a little bit more strict about naming here - the `i1` block argument of any given stage represents the stage **enable** signal - stage **valid** is reserved for the **output** signal/register of a stage, that is fed to its successor stage (as the successor stage enable signal).
The `ibis.schedule` operation defines a block wherein a group of operations can be placed wherein a limited number of Ibis threads can execute at once.
The operation is not isolated from above and has no return types. References to external values should be performed through SSA dominance and memrefs.
Update the attribute for all the ports and set it together, instead of
updating each individually.
This also fixes a bug with LegalizeNames, that was ignoring verilogName
attribute when renaming ports.
Fixes: #5986
Update the interface to get the Value corresponding to each module port index.
The module ports may not be ordered input-output, so we need to iterate over
the ModulePortInfo to compute the input/output port index from the module port
index.
Precompute the module port index to instance port Value to avoid the
recomputation of port to value mapping. This avoids the `getPortList` computation
for every port index, which is very expensive.
Add a new LoweringOption, "caseInsensitiveKeywords". When set, this will
cause ExportVerilog to mangle names which conflict with keywords case
insensitively. This exists to avoid lint warnings which error about this.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Add information to LowerAnnotations ApplyState about whether or not the
"noRefTypePorts" option is set. This indicates if lowering should never
generate reference type ports.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This commit adds a member variable defining operation (`ibis.var`) and a member variable dereferencing operation (`ibis.get_var`). `ibis.get_var` works by taking an ibis `scoperef` value alongside a symbol for the member variable name, and generates a `memref`-typed value. This value can then be used by `memref` ops to perform load/stores.
We do this by analyzing how a portref is used inside a container, and then creating an in- or output port based on that.
That is:
- write to `portref<in portref<in, T>>` becomes `out T`
i.e this container wants to write to an input of another container, hence
it will produce an output value that will drive that input port.
- read from `portref<in portref<out, T>>` becomes `in T`
i.e. this container wants to read from an output of another container,
hence it will have an input port that will be driven by that output port.
- write to `portref<out portref<out, T>>` becomes `out T`
i.e. a port reference inside the module will be driven by a value from
the outside.
- read from `portref<out portref<in, T>>` becomes `in T`
i.e. a port reference inside the module will be driven by a value from
the outside.
A benefit of having portref lowering separate from portref tunneling is that portref lowering can be done on an `ibis.container` granularity, allowing for a bit of parallelism in the flow.
This attribute represents a value of Path type, and can be used with the OM
constant operation. For now, it holds a string encoding of the path, but will
probably change in the near future.
OM path operations use a HierPathOp to identify their target. To facilitate
this, it makes sense to insert OM classes under the FIRRTL circuit, as
HierPathOp should be under the same symbol table as the path operation for
lookup to work correctly. If they were not under the same symbol table, it
would be possible to craft a nested symbol reference, but that would just
complicate the LowerToHw pass.
This change removes the restriction that OM ClassOps have MLIRModuleOp as a
parent, changes LowerClasses from a MLIRModule pass to a FIRRTL CircuitOp pass,
and updates some logic to ensure that we are inserting the class operations in
to the correct location.
As a quick example of how this will look with path operations:
```mlir
module { // SymbolTable
firrtl.circuit "Foo" { // SymbolTable
hw.hierpath @Path [@Foo::@Wire]
firrtl.module @Foo { // Not a SymbolTable
%wire = firrtl.wire sym @wire : !firrtl.uint<1>
}
om.class @Class() { // Not a SymbolTable
%0 = firrtl.path @Path
}
}
}
```
Currently, OM class operations are symbols tables and their fields are symbols,
which is used to facilitate the lookup of fields. The ObjectFieldOp verifier
needs to verify that it is accessing a legal field of the class, and does this
by first looking up the class in the MLIR ModuleOp, and then the field in the
OM ClassOp. This double lookup strategy is problematic because it does not
follow the normal rules of symbol resolution as defined by the SymbolTable.
This means that anything that examines symbol uses (e.g. SymbolDCE) will be
incorrect. We have faced this kind of problem before, which is why we invented
InnerSymbolTables and InnerSymbols.
This is also needed to properly support path operations: path ops will have a
references to HierPathOps and we need lookup to work correctly. For this, we
will need two things:
1. Since HierPathOps will live inside a FIRRTL circuit, and FIRRTL circuits are
themselves symbol tables, we will need to put OM classes under the circuit
as well.
2. When this happens, it will no longer be acceptable for the ObjectFieldOp
verifier to "jump up" to the MLIRModule op's symbol table for lookup, since
the classes will actually be under the FIRRTL circuit op.
By removing the SymbolTable interface from class operations, we can change
symbol resolution to use the normal rules, which enables both path operations
to reference NLAs and OM class operations to live in FIRRTL circuits.
This PR removes the SymbolTable op interface from ClassOps, and switches the
ObjectField verifier to perform a manual walk of the ClassOp to find the target
field. In the future, we should switch to InnerSymbols or invent something
totally new for these operations.
This implements region kind interface for class op to support graph regions. Graph regions are useful to represent DAG or cyclic references between two objects. A follow up would be to make sure that OM evaluator works with cyclic references.
[FIRRTL] Flow checking for propassign
- An output property port cannot be read
- An Input port on an object cannot be read
- We can only assign the input ports of a local object declaration.
- A "remote" object (eg input object port, or output port of a local object)
cannot be assigned into.
- An output object port must be assigned at the root.
Tunnels relative `get_port` ops through the module hierarchy, based on `ibis.path` ops. The result of this pass is that various new in- and output ports of `!ibis.portref<...>` type are created. After this pass, `get_port` ops should only exist at the same scope of container instantiations.
The `ibis.path` operation describes an instance hierarchy path relative to the current scope. The path is specified by a list of either parent or child identifiers (navigating up or down the hierarchy, respectively).
Scopes along the path are optionally typed, however, An `ibis.path` must always terminate in a fully typed specifier, i.e. never an `!ibis.scoperef<>`.
The operation returns a single `!ibis.scoperef`-typed value representing the instance at the end of the path.
This new operation represents the path to a hardware entity. It is similar to
the FIRRTL path operation, but instead of relying on annotations it uses a
HierPathOp to reference its target.
The clock type will be used to carry the clock signal in a design.
This PR allows it to be placed on module ports and wires, without forcing its use on all ops.
Subsequent PRs will switch `seq` ops over to use it and generate it from FIRRTL.
The PathOp is being re-worked to remotely reference hardware objects using
(possibly non-local) annotations. The hardware target recieves an annotation
with class `circt.tracker` and an identifier. The Path operation tracks the
original reference kind and the target identifier. It is legal to optimize away
the hardware target, which will leave the Path op with a dangling identifier
reference. A later pass will lower this pick bb5ad82a6 [FIRRTL] Add enumeration
for OM path kinds FIRRTL PathOp to an OM specific Path operation, which will
not use annotations. See the example in FIRRTLExpressions.td for what this
looks like in FIRRTL.
Add base-level MMIO functionality to cosim. Exposes an AXI-lite master interface which is driven by capnp messages. This provides the ability to build a BSP with MMIO services (which works in any system with AXI-lite style MMIO).
This change ensures that when lowering InnerSymbol operations, we copy the
existing inner symbol to the target, as well as properly adding a symbol on
fieldID 0 when required. This fixes an assumption of symbol name uniqueness,
and they are now uniqued in the module's symbol namespace. A side effect of
this change is that the used symbol names are always of the form `@sym_1`.
This also fixes a bug where an `InnerSymAttr` was assumed to target field ID 0,
and could result in an incorrect lowering of the `DontTouch` annotation.
This adds OMIR path kind attribute for use in Path operations. We will have to
keep track of which kind of path was specified by the user throughout the
pipeline, as it is not information which can be reconstructed later.
This operation is meant to read in an encoded OM target string, with a pass
later resolving the string target to a real target and validating the contents.
This new operation purposefully does not contain much in the way of
verification.
Until have proper container op to put the trait on,
add a dummy struct we can classof to classify IRN-like,
and add a simple pass that drives verification on these
if they aren't self-verifying.
Add verification pass to pipeline, basic test for duplicate
inner symbols and invalid InnerRef user.
Let's all promise ourselves this is temporary! ;)
cc #3526 (nearly fixes), #4453.
cc #5716.
Co-authored-by: Robert Young <rwy0717@gmail.com>
This change takes a common pattern in LowerAnnotations, which avoids creating
duplicate HierPathOps by maintaining a cache, and moves it into a dedicated
class for easier re-use. Since the HierPathCache maintains an insertion point
instead of always inserting to the top of the circuit's block, HierPathOps are
now in reverse order after LowerAnnotations.
DistinctAttr does not have proper upstream exposure through OpBase.td as type
constraint, so we have to declare it ourselves. This should be a temporary
workaround.
This switches to non-explicit constructors in cases where it would not lead to
automatic conversions. This helps write shorter code to when creating new
InnerSymTargets.
It is a common pattern for passes to have a map from a modules to an
InnerSymbolNamespace. This captures the pattern for reuse in a
InnerSymbolNamespaceCollection.
This PR moves the conversion of FIRRTL-specific `seq` ops to their own conversion pass, `SeqToSV`.
The existing register & memory lowering passes are packaged as re-usable utilities to keep them available as individual transformations.
Both the memory and register lowering utilities are packaged into a single parallelized lowering.
Introduce `Callback` token type. The callback token is associated with a
listener. The listener is invoked only after all the tokens
that were preceding the callback token have been printed. This enables the
listener to record the output stream state (for example current output file
location) after the last token is printed on the stream.
The Callback token provides a generic mechanism by which any state can be
tracked and necessary updates can be made as per the client requirements.
The unit tests demonstrate a mechanism to log the token print line and
column information on the output stream.
This will be used to record Verilog output file location information in a future PR.
* [FIRRTL] Class symbols can not be deleted
Prevent symbolDCE from deleting classes. We cannot always find the users of
class symbols, because sometimes that class could be referenced only by the
type of a port.
* [FIRRTL] Do not delete classes in the module inliner
GCC defines function-like macros major(x) and minor(x), for extracting
information from device IDs. These macros conflict with, and cause compilation
errors in, FIRVersion's constructor. This commit changes FIRVersion to
initialize it's major and minor fields using brace-initialization, so that the
initialization isn't mistaken for a macro invocation.
Fixes: #5868
We need to support having paths for some ref-type ports but not others
(ABI + GCT's internalPath mechanism) so change to have entry per port,
with empty entries for non-ref and ref ports that should use ABI.
Handle in LowerTypes (just propagate, don't support lowering).
`igraph::InstanceGraph` should be able to serve as a standalone graph implementation, without needing specialization (`getTopLevelNode` is the only pure virtual function, whereas there's always the alternative of using `getInferredTopLevelNodes`).
Allow so, by publicly exposing the constructors, and make `getTopLevelNode` opt-in.
This is a fairly significant rewrite, so I've chosen to rename the
pass, but otherwise share some of the good parts. A lot of warts are
hopefully removed.
The pass lowers both FIRRTL modules with property ports as well as
FIRRTL classes into OM classes. It does a linear walk to initially
create the OM classes, and then processes each in parallel.
The logic to move ops into the new class body is greatly
simplified--ops are copied over, in order, if they have property
operands or results. We might make this even simpler with a trait at
some point.
Instantiations and the instance graph no longer need to be kept in
sync--only FIRRTL Object instantiations are effected. These are
converted to OM Object instantiations. It's actually impossible to
represent a FIRRTL Object that takes inputs with the current
flow-checking. I tried to write out an implementation for it, even
though I can't test it.
Besides the structural changes, I've also added type conversion from
the FIRRTL ops to the OM versions. I'm using DialectConversion for
this, which actually helps for this sort of thing. There are fairly
simple patterns for converting the constant property ops to the OM
versions. These could almost be templated on the operation class, but
minor differences made that more trouble than its worth. There are
also patterns for legalizing OM class fields and OM classes, which are
just there to let the type converter do its thing.
I've added a basic unit test for the kind of IR we want to support
here. One more parser and flow-checking support is in, I will also
include an end-to-end test from FIRRTL through ExportVerilog to the
final MLIR.
In anticipation of most modules converting from functions to portlists using module type, route most of the HWModuleLike interface through the ModuleType. Modules like things must now be able to produce a moduletype from which many accessors are derived. getNumPorts is separate from this as non-function-like modules need this to compute the module type.
Instead, a constant X is materialized to drive the dummy port of the `seq` memory.
A subsequent PR should consider whether these memories can be removed altogether.
This is a PR for new representation of Evaluator and list_create support.
`std::variant` has been used as runtime representation of Evaluator but it's difficult to use it as
data structure for more structured values such as list or map. So this PR instead introduces a base class `EvaluatorValue ` and derived classes, `AttributeValue`, `ListValue` and `ObjectValue`, as runtime representation of values.
Also terminology `ObjectValue` is changed to `EvaluatorValue` since runtime values will not be limited to Object.
Python and C bindings are changed accordingly.
This isn't used by much yet, but some parts of the MLIR
infrastructure (e.g., Dialect Conversion) assume ConstantLike ops have
a folder. This adds the usual folder, same as StringConstantOp and
others.
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.
Co-authored-by: Morten Borup Petersen <mpetersen@microsoft.com>
Co-authored-by: Andrew Lenharth <andrew@lenharth.org>
Rework RWProbeOp to explicitly track result type,
don't "infer" from target type argument (removed).
This is a better fit for this op, particualrly in that no
useful "inference" is performed that way.
(not inferring through symbol target)
Teach InferWidths about the type constraint,
getting inner symbol analysis for resolution.
Loosen parsing, but still only use RWProbeOp
for ports.
With these changes, it's nearly possible to remove
"Forceable" entirely in favor of the one mechanism.
Combine identical "ModuleNamespaces" into a new common one
for anything with inner symbols.
First step towards dropping use of a "Namespace" for generating
inner symbols entirely, once other pieces are in place.
Also sets the stage for moving the utility functions that help
create inner symbols and inner refs out of FIRRTL.
NFCI.
This functionality was used primarily wrap handshake modules. Now that
handshake uses ESI channels it's no longer necessary. I don't think
there are any other users.