Extend the behavior of connect canonicalization to convert a connection
to an InvalidValueOp to a connect to zero. This is done to enforce
compliance with one Scala FIRRTL Compiler (SFC) interpretation of
"invalid is constant zero".
This change requires a RemoveResets pass (#2287) to run before the
canonicalization that this PR adds. This is because registers require a
separate interpretation of invalid where "invalid is undefined when used
as the initialization value of a register" (and where invalidness is
determined by looking through wires/connects in the current module).
This latter, "register initialization" interpretation needs to run
before invalids are fully removed by the code added in this commit.
Add an end-to-end test of firtool that checks for compliance with the
multiple Scala FIRRTL Compiler (SFC) interpretations of invalid. This
test is added to lock in behavior around invalid as this is known to
cause formal equivalence failures, e.g., if a register has a reset in
CIRCT, but does not in the SFC formal equivalence will rightly complain.
This test can likely be removed or weakened once better semantics for
invalid value are defined other than "whatever the SFC does".
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Change FIRRTL parsing to convert all parameters less than 32-bit to
32-bit APInts. This fixes downstream issues with Verilog emission,
where negative parameters may have too few bits in their APInt
representation and print as shorter-than-expected literals.
Fixes#2299.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Add a new pass, RemoveResets, that replaces RegResetOps that have
invalidated initialization values with RegOps. This is part of a series
of patches that are intended to align CIRCT with the Scala FIRRTL
Compiler (SFC) interpretation of invalid. Previously, CIRCT relies on
canonicalization/folding of invalid values to do this optimization.
This pass enables future canonicalization/folding of invalid values to
zero (as the SFC does) without having to worry about performing this
optimization.
Run the RemoveResets pass as part of firtool after ExpandWhens and
before the first canonicalization. This enables conversion of
invalidated RegResetOps to RegOps before canonicalization (eventually)
interprets invalid values as zero.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Rename the private "foldSingleSetConnect" function to
"canonicalizeSingleSetConnect" as this is actually only used by the
ConnectOp canonicalizer. This name change is done purely for clarity as
multiple people have been confused thinking that this function was a
folder or used by other folders (when it is not).
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This change adds an option to ignore the memory read enable signal during
memory lowering to register banks.
According to the FIRRTL spec, the read output is undefined if the read
enable signal is disabled.
But the `firrtl` implementation ignores the read enable signal on latency 0.
This change ensures that, in `HWMemSimImpl` by default the read output is set
to `X` if read enable is disabled, but if `ignore-read-enable-mem` option
is passed, then the read output is set with the data at the read address,
irrespective of the enable signal.
This provides an option to match the Scala FIRRTL compiler behavior.
Fix a bug in SubPrimOp canonicalization where an asUInt cast was applied
before the pad inside a utility method. This commit changes the utility
method to apply a cast (either asUInt or asSInt) if needed.
Fixes#2289.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This extends the FIRRTL fold and canonicalization patterns to treat
`invalidvalue` as a zero if it is an input to a primary operation. This
is inline with what the Scala implementation of the FIRRTL compiler
does.
Doing this removes quite a few of the special cases where certain ops
are aware of `invalidvalue`s and will fold as if it was a zero. The
addition of the `getConstant`, `isConstantZero`, and
`canonicalizePrimOp` helpers allow for most folders and canonicalizers
to not having to bother with `invalidvalue`s, as these helpers
implicitly map `invalidvalue`s to zero constants.
This also subsumes the work done in #2278 and #2198, which selectively
added handling for `invalidvalue`s to the `PadPrimOp`.
The extension of the folders and canonicalizers now makes all the cases
in `invalid-reg-fail.fir` pass, albeit some only after accepting that
the MLIR implementation folds *additional* cases where the Scala one
might just leave an operation untouched. These are marked with a
`<-- fixed; upstream to Scala FIRRTL impl?` and should probably be
upstreamed as additional canonicalizations on the Scala side as well.
This flag appears to be needed to support an upcoming revision of
LLVM. Without this, TableGen complains with:
```
error: defs belonging to more than one dialect. Must select one via
'--(attr|type)defs-dialect'
```
This commit changes expandWhens to accept vector types under the condition that connections are expanded, i.e. all the connections are between ground types. This commit changes `declareSinks` to handle vector types. Currently, aggregate registers are not supported and it will be supported after implementing expand connections.
This adds a method to insert ports into an instance op. Since this
increases the number of results of the instance op, it actually has to
be cloned. It is assumed that the user will manually call
`replaceAllUses` and erase the original instance operation. This
functionality is useful for any pass that adds ports to modules.
When an annotation targets only part of the thing it is attached to, it
is represented using a `SubAnnotationAttrs`, which contains the field ID
of its target.
The Annotation wrapper class can be only be created from a
DictionaryAttr. When using a SubAnnotationAttr, it is created from its
internal DictionaryAttr, and the stored field ID is ignored. This makes
it impractical to use `SubAnnotationAttrs` with most of the Annotation
APIs.
This change makes it so the Annotation wrapper holds on to the original
annotation attribute, instead of just a DictionaryAttr. The annotation
wrapper will check which kind of annotation it has internally when calls
are made.
This change then adds a call to `getFieldID`, which return 0 for regular
annotations, and the field id for `SubAnnotations`.
This also changes the equality comparison for two annotations: a
Annotation created from a SubAnnotationAttr will no longer be equal to a
regular annotation when the dictionary attribute is the same.
A very simple pass which removes any buffers present in the circuit. This pass can come in handy if:
1. one would like to re-buffer a circuit
2. one would like to simulate without buffers
3. one would like to simplify the circuit (for visual/.dot inspection)
Fix an issue in the canonicalization patterns for the gt/lt/geq/leq
prim ops where a `SpecialConstantOp` (can never occur) or
`InvalidValueOp` (*can* occur) would not be properly rotated to the RHS.
In certain places, FIRRTL would accept empty port annotations and symbol
arrays as a shorthand for "none of the ports have any anno/sym", while
others do not. This cleans up hopefully all of these uses to
consistently accept empty arrays as shorthand.
The former is more canonical and has more transformations that work
with it, e.g. we now generate this in RocketCore.fir:
{{65{remainder[7]}}, remainder[7:0]}
instead of:
{{65{_remainder_7to0[7]}}, _remainder_7to0}
because we don't have the replicate/extract buried in the SExt.
This is part of Issue #2248.
Change the behavior of folding around pad, as discussed in #2197 and
implemented in #2198, to fold a pad of an invalid value to a constant
zero. This prevents propagation of invalids which is generally viewed
as a source of errors.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This pass is intended to be a "software"-like companion to --flatten-memref. Whereas --flatten-memref will flatten all memref operations and function signatures to unidimensional memories and accesses thereto, this pass can be used to transform calls to such flattened operations. In other words, this pass expects the parent function of a `callOp` to be able to support multidimensional memories, but rewrites calls _to_ flattened functions.
This is done by converting memref arguments through a `memref.subview` operation. Any called function which had its signature rewritten will be replaced by a private function definition having a signature of the rewritten function type.
The `obj_to_value` and `var_to_attribute` functions used to be publicly
exposed since they had to occasionally used by users. Now that we've
patched all the cases, "hide" them. Also rename to be more consistent
with each other.
Fix a bug where certain folds involving zero width constants would cause
assertions to fire. This stems from APInt using sign extension methods
which bottom out in assertion failures and discussion upstream about
what/how to define sign extension on zero-width things. To work around
this, this change uses zero extension methods if a zero-width APInt
needs to be sign extended.
Fix a bug in IMCP using sign extension of an APInt.
Extend existing canonicalization tests to also check situations
involving folds of signed zero-width constants.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Add utilities for working around limitations of APInt/APSInt and sign
extension. This is done because many of the upstream methods hit
assertions on zero-width signed values.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Fix an issue in `ExportVerilog` where the signal names used as port
connections in emitted `bind` statements would not use the legalized
name.
PR #2234 has moved the calls to `prepareHWModule` to a point before the
global name legalization. This now causes the temporary wires that were
introduced by that preparation to have a legalized name, which `bind`
statement emission requires for the port connections.
The remaining work is to adjust the `getNameRemotely` function which
provides the names for the bind port connections to properly see through
the IR pattern used to make output ports of the instance always connect
to a wire:
%tmpWire = sv.wire
%output = hw.instance ... () -> (output: i1) {doNotPrint = true}
sv.assign %tmpWire, %output
This change updates this function to look through any `sv.assign` ops
from instance outputs to wires, and produces that wire's legalized name.
Also adds an assert to ensure that we always have a legal name to use
for the bind port connections. This used to be some optional code that
came up with a name on the spot.