Add a pass to group tests to output files. Currently, this matches what the emission pass does but can be extended to group tests according to certain requirements demanded from the execution environment. Also add a simple pass that inlines the tests without any gluecode (matching what the emission pass currently does). The emission pass will be simplified in a future PR to only iterate over the file operations and print what's inside
This patch implements lowering of hw.array_inject operations to combinational
logic in the HWAggregateToComb transformation pass.
The implementation creates a 2D array where each row represents the result
of injecting the new value at a specific index. A multiplexer then selects
the appropriate row based on the injection index.
This commit introduces a new operation to the Comb dialect:
`comb.reverse`, which performs bitwise reversal (mirroring) of an
integer value.
It also adds Verilog export support for this operation using
SystemVerilog’s streaming operator `{<<{}}`.
Bit reversal is a common operation in hardware design, especially in
signal processing and communication protocols. Previously, reversing
bits required generating many explicit `assign` statements. This new
operation makes the IR cleaner and enables direct export to compact
Verilog syntax.
Technology mapping/Cut rewriting requires enumerating multiple cuts to find best cuts, so representing a single cut as an operation doesn't make sense in general. When the AIG dialect was originally introduced, the cut operation was not well-thought-out and not used anywhere so clean up before implementing tech mapping.
Close https://github.com/llvm/circt/issues/8761
This adds the ability to the FullResetTransform to create enumeration
values which are 0. When the enumeration has a valid variant that is
encoded as a 0, we create this value using the FEnumCreateOp. If there
is no valid variant with the value 0, we create a constant 0 and bitcast
it to the enumeration type.
TagExtractOp's type inference predates adding user-defined encodings for
enums in FIRRTL. This fixes the issue by using the bitwidth helpers
defined on the enumeration type.
This adds support to flatten memories with enumeration in them.
Enumerations are treated as non-aggregate types, and so they get a
single bit mask to control the whole value.
This commit introduces a new transformation pass `RegOfVecToMem` that converts
register arrays following memory access patterns into `seq.firmem` operations.
When a valid pattern is detected, the pass replaces the register array with a
`seq.firmem` operation and corresponding read/write ports.
This is required for the `circt-verilog` tool, to identify memories, such that
other `circt` transformations/analysis can be run in the `seq` dialect on the
`mlir` parsed from verilog.
This adds verifiers to the FIRRTL parser and to the FEnumType to prevent
having uninferred widths and resets inside enumerations. It seems like
the trickiness to implement these features would be hard to take
advantage of in practice, making it not worth it. This also fixes the
error messages produced by the type verifier that had extraneous quotes
around the field name, and rearranges some tests to be co-located in the
test file.
This adds the ability to specify the constants used to encode
enumeration variants in the tag. For example,
``` firrtl
wire a : {| A = 10, B = 5 |}
```
The values can be unspecified, in which case it defaults to one higher
than the previous value, or zero if it is the first value. For example,
these two enumerations are the same:
``` firrtl
{| A = 0, B = 1 |} == {| A, B |}
```
In FIRRTL, Two enumeration types are considered equal if they have the
same variants with the same values and data, without regard to variant
order. Internally in FIRRTL dialect IR, enumerations types must have
the variants sorted from low to high. For example the following two
enumeration types are equivalent:
``` firrtl
{| B = 1, A = 0 |} == {| A, B |}
```
The mlir syntax has been updated to ellide the the tag values and data
types if they are implicit. For example, the first type would be
roundtripped to the second type:
``` mlir
!firrtl.enum<a = 0 : uint<0>> => !firrtl.enum<a>
```
Enumerations are no longer lowered to SystemVerilog enumerations, but to
regular integer types. This is for a variety of reasons, but mainly
because enumerations in SV are nominal and it was not a good fit for our
structural enumerations.
In LowerToHW, the `firrtl.istag` operation lowers to a comparison to a
constant value created with a localparam, which can show up in the
output depending on how the module is optimized. The FIRRTL code below,
``` firrtl
FIRRTL version 4.0.0
circuit Enums:
public module Enums:
input in : {|A = 8 : UInt<8>, B = 16 |}
output out : UInt<8>
match in:
A(data):
connect out, data
B:
connect out, UInt<8>(16)
```
produces:
``` verilog
module Enums(
input struct packed {logic [4:0] tag; union packed {logic [7:0] A;/*B: Zero Width;*/ } body; } in,
output [7:0] out
);
localparam [4:0] A = 8;
assign out = in.tag == A ? in.body.A : 8'h10;
endmodule
```
This PR adds the RefinementCheckingOp to the verif dialect. The motivation behind this operation is to be able to automatically check whether a 'target' circuit is a refinement of a 'source' circuit. This should be a small step towards performing translation validation comparable to Alive2. The operation is structurally identical to the LogicEquivalenceCheckingOp, so I factored out most of the ODS into a common CircuitRelationCheckOp. If there is no non-determinism present in the circuits, the operation is also functionally identical to LogicEquivalenceCheckingOp.
Co-authored-by: Bea Healy <57840981+TaoBi22@users.noreply.github.com>
This pass prints the names of the tests in the IR. Since tests can be duplicated and elaborated differently during compilation, it prints both the newly uniqued name and the original name as specified by the user in the frontend.
This adds support for enumerations to LowerSigs so that the pass no
longer fails when it encounters an enum, and just passes them through
unchanged.
Fixes#7106
Fixes the canonicalizers for wrap operations in the ESI dialect by replacing problematic attribute-based folding with proper operation creation and improving pattern matching logic.
- Updates `WrapValidReadyOp` and `WrapFIFOOp` fold methods to create `NullSourceOp` operations instead of using attributes
- Improves the `WrapFIFOOp` canonicalize method with better error handling and more robust user checking
- Delegates constant materialization to the HW dialect for better consistency
This fixes a long standing bug when parsing match statements which
contain numeric constants.
The FIRParser has a contant cache so that we can reuse any constant
operation created as we parse, by inserting them into the top-level body
of the module. To find the top level block, we were searching upwards
from the current insertion point.
In general, when creating any operation, we are required to know how
many regions the operation has; it is impossible to add more regions
after creating the operation. Due to this, when parsing the arms of a
match statement, the expressions are inserted into a region which is not
attached to any operation. This means we can not search upwards from
the insertion point to find the top level block. When operations do not
have this problem as they always have space 2 regions.
This change passes in the top level block when creating the
FIRModuleContext. If it turns out that the region we are inserting into
is not underneath the module, then we can insert the constant at the end
of the module's block.
This change also makes the cache itself a private member, and removes a
bit of code which was unnecessarily directly accessing the cache.
Enum types were not handled by this pass, and so it would hit an
unreachable assert. This handles enum types using the aggregate
codepath, which creates a 0 value and bitcasts it to the aggregate type.
The builtin tuple type does not allow empty tuples, but they can avoid special casing in the frontend and can also be used as indicators (something like a none type could otherwise be used for but which we don't have in RTG).
When we want to be able to get all possible numbers that fit in a 64 bit register, we would need a 65 bit number as the upper bound. However, an iindex typed attribute uses an APInt with 64 bits and would thus make this complicated.
Add a canonicalization pattern for AndInverterOp that flattens nested
inversions by detecting when an and_inv operation takes as input another
and_inv operation with a single inverted operand.
This eliminates redundant double inversions and simplifies the AIG
representation by reducing the depth of inversion chains.
The folders and canonicalizers for `comb.shl`, `comb.shru`, and
`comb.shrs` perform unchecked `getZExtValue()` calls which can crash
if the shift amount does not fit into 64 bits. The shift amount is also
not clamped to the width of the result, which causes the shift to be
replaced with ops that have a different type.
Found with [VlogHammer], which turns out to be a very handy tool!
Fixes#8694.
Fixes#8695.
[VlogHammer]: https://github.com/YosysHQ/VlogHammer
Set the `bin` flag on the `comb.mux` that we insert for enable
flip-flops in LLHD's Deseq pass. This allows circt-verilog to preserve
the difference between `if (en) q <= d` and `q <= en ? d : q` enables.
In the future we'll probably want to have more explicit ops to describe
these differences. But adding the `bin` flag causes the pipeline to
preserve the property we're interested in for now.
* [FIRRTL] Add "knownlayers" specifications to ExtModules
In a circuit, we only know about the layers which have been declared. If we
have an extmodule, it may have been defined under a different set of layers
than what is in the current circuit. In particular, if there is a layer which
we know about, but the extmodule does not, then the extmodule will not have a
bind file for us to include.
This commit adds a "knownlayer" declaration to extmodules, which is an explicit
specification of the layers which an extmodule was defined with. For each
bound-in layer that an extmodule knows about, we can assume that there will be
a bindfile to include.
Changes:
FExtModule: Add a knownLayers property. Update the verifier so that, if a layer
is mentioned by an enablelayer specification or port type, then that layer must
be known by the exmodule. Bonus: implement verifySymbolUses for extmodules.
FIRParser: add parsing for knownlayer declarations on extmodules.
LowerLayersPass: Use the known-layers of extmodules while building the
bindfiles for modules in the current circuit. If a module in the current
circuit instantiates an extmodule, then that module's bindfiles will include
the bindfiles for the known-layers of the extmodule.
SpecializeLayers: Clean up known-layers when a layer is specialized away.
FirEmitter: Emit knownlayer declarations.
* Apply suggestions from code review
Co-authored-by: Schuyler Eldridge <schuyler.eldridge@gmail.com>
* Address comments
* Fix typo
* Clean up layer verification messages
* Use nextFIRVersion for guarding knownlayer
---------
Co-authored-by: Schuyler Eldridge <schuyler.eldridge@gmail.com>
Adds a new transaction‐level snoop operation (`snoop.xact`) to the ESI dialect, lowers it to hardware, and wires it through the Python front end.
- Introduce `SnoopTransactionOp` in ESIChannels.td with `verify` and `inferReturnTypes` in ESIOps.cpp
- Extend the HW lowering pass to remove `snoop.xact` via `RemoveSnoopTransactionOp`
- Update MLIR tests and the PyCDE API (`snoop_xact`) to exercise the new operation
Advanced layer sink is now the only "layer sinking" pass that can run, it is no
longer possible to run the original layer sink pass. This commit also disables
layer sinking when optimizations are disabled.
Remove the LayerSink pass and rename advanced-layer-sink to layer-sink.
Implement the following canonicalizations which essentially assume the
value of a mux condition to be a constant in the op that supplies the
true or false value of the mux:
```
mux(cond, op(cond), x) -> mux(cond, op(1), x)
mux(cond, x, op(cond)) -> mux(cond, x, op(0))
```
This only works if the true or false value only have a single use.
* [CIRCT] Move parallelTransformReduce to common util header
* [FIRRTL] Lower registers under ifdefs
In seq-to-sv, we transform seq FirRegOps to sv RegOps. This is done using a
helper called FirRegLowering. This PR changes FirRegLowering to correctly lower
registers under ifdef blocks.
The initialization of registers is placed in an initial block at the footer of
the enclosing HWModuleOp. In order to initialize registers buried under ifdefs,
we have to refer to these registers by a local XMR, because the buried
registers will not dominate the initial block. We build these in a prepass over
the MLIR module, returning a "PathTable" sending buried FirRegOps to their
HierPathOps.
The main FirRegLowering procedure operates in parallel on each HWModuleOp. Each
invocation is now handed a const reference to the path table, which allows us
to produce an XMRRefOp as needed while emitting the register initialization
code at the footer of the HWModule.
The initialization code for a register has to be guarded under the same ifdef
conditions as the register itself. To do this, while lowering registers, we
record the conditions under which the register is defined, and recreate them to
guard the initialization code.
When we lower a register, we attempt to transform any input mux tree into an SV
if-else tree of connects. This PR modifies the if-else generation to co-locate
the if-else with the register. So if a register is guarded under an ifdef, then
the if-else structure driving it will also be under the same ifdef.