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 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.
This implements LinkModulesPass that is a core logic of `om-linker`.
The input IR consists of multiple mlir::ModuleOp that have their own
symbol namespaces. LinkModulesPass first constructs a map from
symbols to ClassLike operations and checks whether it’s legal to link the classes.
We consider a symbol used as an external module to be "public" thus we
cannot rename such symbols when symbols collide. We require a public symbol
to have exactly one definition so otherwise raise an error.
Also a definition and declarations must have the same input types and fields.
Lowering the Ibis control flow starts with converting all calls to the DC dialect's values with one struct representing the packed arguments.
In the interest of incremental development, this only implements narrowing the arguments to one struct. Part 2 will then wrap them in DC values.
#5577, #5575
Re. the lowering; `verif.print` lowers directly to a `sv.fwrite` via. inspection of its source operand (which is expected to be a `verif.format_verilog_string`). The source `format_verilog_string` is `not` deleted in the process (there may be other users). However, i marked `verif.format_verilog_string` as `Pure` meaning that it'll get removed if `canonicalize` is run after `lower-verif-to-sv` and there are no more users of the result.
It's expected that `verif.print` will reside inside *something* that eventually lowers to a procedural SV region, if one is going the SV route. I'd imagine that most users will embed `verif.print` inside `hw.triggered` regions.
We will be porting an internal language over to CIRCT. This dialect will
be the entry point into CIRCT. Eventually, all of the backend will be
part of CIRCT and the frontend parser will be open sourced.
We plan on developing this dialect in the open so as to not dump a giant
PR at some point months down the road.
Here's a stab at the `hw.triggered` operation.
I think the main issue is to decide where to place the lowering. AFAICT, the closest we have to a "hw to sv" conversion pass is `hw-legalize-modules` (which really should be named to `sv-legalize-modules` seeing as it's lowering away HW constructs in favor of SV constructs).
I chose to introduce a new pass - `lower-hw-to-sv` which could serve as a clear home for these kinds of lowerings (maybe some things in `HWLegalizeModules` could be moved to here?).
Lastly, just went with a simple assembly format. If people would like to see something more fancy, e.g. an initializer-list style format with an elided entry block:
> `hw.triggered postedge %t (%a0 : i32 = %in) { ...`
let me know.
* Ensure the ControlFlow dialect is registered in the context where needed and linked against (not sure where exactly this stems from)
* LLVM IR cttz and ctlz intrinsics moved from undef to poison and take an attribute instead of value now: https://reviews.llvm.org/D151692
* Function inliner extension is a promised interface: https://reviews.llvm.org/D120368
* New replaceOp added to Rewriter: https://reviews.llvm.org/D152814
---------
Co-authored-by: Martin Erhart <maerhart@outlook.com>
Some operations in the comb dialect (e.g. comb.truth_table) are not directly supported by ExportVerilog. They need to be lowered into ops which are supported. There are many ways to lower these ops so we do this in a separate pass. This also allows the lowered form to participate in optimizations like the comb canonicalizers. This change is just to introduce the pass boilerplate. It currently doesn't do anything.
This commit adds a lowering of DC operation to a combination of
`comb,seq` and `hw` operations. The implementations are identical to
those of the `handshake` dialect (i.e. `handshake-to-hw` sans the
arithmetic operations).
- ESI-typed I/O
- DC buffers lower to ESI buffers
- This is just a temporary solution. I anticipate more complexity here
in the future when we want to do more with the FIFOs that connect
DC circuits.
- In case the IR contains DC operations that need to be clocked (fork, buffer),
there must exist a clock and reset signal in the parent `FunctionLike`
operation. These arguments are to be marked with a `dc.clock` and `dc.reset`
attribute, respectively.
- Only a single integration test for now. Will add more once #5297 lands
(allows us to do some high-level tests through handshake).
Add two new dialects to CIRCT.
The `ltl` dialect represents Linear Temporal Logic expressions and
borrows from SystemVerilog's rich assertion system (SVAs). The current
implementation is fairly minimal, but is sufficient to capture basic
liveness properties and something akin to "regular expressions over
time". Since the mapping from SVAs to this dialect is non-trivial, there
is an `LTL.md` doc accompanying the dialect to capture some of the
design decisions.
The `verif` dialect captures various verification-related operations.
It currently contains just a trivial flavor of assert, assume, and
cover, without any labels, messages, or value interpolation. The
intention is for these operations to be expanded in the future until
they can replace the corresponding operations in the SV dialect. The
`verif` dialect will also be a good place to introduce
verification-specific concepts such as test programs, clock generators,
pre- and post-condition checks.
The LTL operations have a few basic folds and canonicalizations defined
on them, to be expanded later. Something like a "never" sequence or
property would be useful to have unreachable/unmatachable sequences fold
to something.
Support for emission in ExportVerilog will be done in a separate commit.
... progressive lowering of handshake!
This obviously requires a future addition of an `arith-to-comb/hw` pass to map arith stuff to comb/external hardware/pipelines, ...
Removes the handshake to FIRRTL lowering pass.
Also:
* All handshake integration tests now run through the handshake to HW pass (thanks to 936db150)
* Some changes were required to the handshake cocotb test runner, seeing as struct are not flattened in HandshakeToHW.
Add two passes to lower a design to a software model.
The `LowerClocksToFuncs` pass outlines all `arc.clock_tree` and
`arc.passthrough` operations into separate MLIR functions. This
conceptually converts clocks from being a signal in the design into a
function that can be called in order to execute the state update
triggered by that clock.
The `LowerArcToLLVM` conversion pass does exactly as it says: it sets up
a dialect conversion from Arc and the core CIRCT dialects to Func/SCF,
and from there to the LLVM dialect.
Also add an output format option to the arcilator tool that allows for
the direct emission of LLVM IR (as opposed to the MLIR's LLVM dialect).
Co-authored-by: Martin Erhart <maerhart@outlook.com>
Co-authored-by: Zachary Yedidia <zyedidia@gmail.com>
This defines the dialect boilerplate, as well as a rationale document
that explains the intended use case and initial core constructs that
will be added in future patches.
Add an experimental pass to convert operations in the Comb dialect to
their equivalent in the Arith dialect. The pass isn't used anywhere yet,
but conversion to Arith allows all canonicalizations defined on that
dialect to take effect before mapping things to LLVM to generate a
software model.
Co-authored-by: Martin Erhart <maerhart@outlook.com>
Add the `Dedup` pass which deduplicates arcs with identical definitions.
If arcs differ only by constant values, the pass outlines the constants
such that the arcs can be deduplicated.
Identical arcs are surprisingly common since splitting modules along the
fundamental state elements yields a finer-grained subdivision than the
modules themselves, which has the potential to uncover additional
redundancies.
Co-authored-by: Martin Erhart <maerhart@outlook.com>
Co-authored-by: Zachary Yedidia <zyedidia@gmail.com>
Add the `ConvertToArcs` conversion which collects the combinational
operations in a module body, divides them into distinct sets split along
registers and a few other potentially state-holding operations, and
outlines these sets into arc definitions, inserting an `arc.state` op in
place of the original combinational ops.
Note that this merely replaces logic and registers with arc invocations,
but keeps the module hierarchy intact.
Co-authored-by: Martin Erhart <maerhart@outlook.com>
Co-authored-by: Zachary Yedidia <zyedidia@gmail.com>
Add the `Arc` dialect which is useful for capturing a canonical
representation of the state transfer in a circuit. It does this by
introducing function-like arc definitions (`arc.define`) and call-like
arc invocations (`arc.state`). The state op represents a transfer
function, given by the arc definition, and zero or more registers, as
specified by its latency attribute.
Co-authored-by: Martin Erhart <maerhart@outlook.com>
Co-authored-by: Zachary Yedidia <zyedidia@gmail.com>
Change all existing CIRCT tools to use a CIRCT-specific bug report
message. Previously a crash would tell people to file a bug on LLVM
which isn't correct.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Add a pass to overwrite lowering options on a module. This lets us get rid of the in-library cmdline option and move it to the two tools which need it. With this, prepare and export never change the lowering options.
Also make prepare a nested pass.
We create and manage many thousands of HierPathOp's unnecessarily.
Fix this by addressing the primary location they're added to the IR: LowerAnnotations, by using a simple cache to avoid emitting duplicate ops.
This reduces the count from thousands to tens on even small-ish designs.
Modify GC and GCT passes to stop deleting HierPathOp's as they don't know if they're still used. Indeed, in our tests we were deleting these ops despite them still being alive (breadcrumbs).
Add SymbolDCE to the pipeline to do this cleanup instead, thanks to various recent changes using private visibility in many places, particularly the HierPathOp's themselves (#3871).
[Pipeline] Add pipeline stage register materialization pass
This commit adds an intermediate transformation to the Pipeline dialect
which is responsible for converting `pipeline.stage` to `pipeline.stage.register`
operations. The purpose of this transformation is to 'fix' where
registers needs to be placed in the pipeline, after all stages have been
defined and placed.
In short, the transformation will scan through the pipeline (in order,
top to bottom) and insert `pipeline.stage.register` operations in place
of `pipeline.stage` operations. Any operand used in any operation will
be analyzed to determine if it originates in between the last seen stage
and the operation itself. If not, this means that the operand crossed
a pipeline stage, and as such, the value will be routed through the
predecessor stage (`routeThroughStage`).
This is a fairly straight-forward transformation since the brunt of the
work of detecting which values will be registered in a given pipeline
stage has already been performed by a prior pass.
This pass simply elaborates the `pipeline.stage.register` operations
into `seq.compreg` operations and stitches up the circuit.
* [ExportChiselInterface] Basic infrastructure for Chisel Interface file emission
This commit adds a pass for FIRRTL that generates a Scala file with a module
class that represents the interface for the top module of the FIRRTL circuit.
This is to support the development of separable compilation of FIRRTL circuits.
The details about linking circuits together are to be determined. The generated
Scala module extends ExtModule, although a new module class may be introduced
in the future.
This representation and conversion aren't being used, and never
connected to Verilog output. The newer PipelineWhileOp could subsume
this use-case, and further evolution is coming to this dialect, so it
seems like a good time to clean out the older parts that aren't used.
Motivation:
1. This file is nearing 2000 LOC. I personally find that having a single file per pass helps in quickly navigating to/between implementations of different passes. Bunching everything into one file makes locating things just a bit harder.
2. This is the style used in the remainder of CIRCT.
3. Uses canonical CMake structure for declaring passes.
It is probably fair to conclude that naming this dialect `StaticLogic` has been a pain point for a while. This commit proposes a dialect renaming to `Pipeline`, for a couple of reaons:
1. So far, we've only been working with pipeline abstractions within this dialect.
2. Pipeline representations aren't necessarily statically scheduled - we plan on adding switches to select between latency sensitive and latency insensitive lowerings of pipelines.
This name change does not preclude renamings in the future if we want to fit more stuff into this dialect. Personally, i think it is prudent to maintain a dialect name which reflects what's actually being done within the dialect, as well as the (near/mid/"someone actually intends to work on this"-term) future plans for the dialect.
Moves Comb to LLVM and HW to LLVM conversions out of the LLHDToLLVM pass and into their own dedicated lowering passes, as proposed in #3539.
The methods convertToLLVMEndianess and llvmIndexOfStructField are also encapsulated here within a HWToLLVMEndianessConverter class, in order to allow easier re-use between different passes.
This commit represents a lowering pass for converting a Calyx control schedule (seq/if/while/enable) into an FSM representation. The FSM is embedded within the Calyx component, and references both the group symbols and cell SSA values.
The lowering method is a fairly straight forward conversion, which leaves plenty of canonicalization opportunities to remove redundant states in the generated FSM. However, doing it as presented in this PR lends itself to some very clean code (which I prefer, rather than prematurely optimizing during lowering) as well as meaningful naming of states (which i think is fairly important).