Add an emitter to export FIRRTL dialect as a .fir file. This is a first
shot at such an emitter, with no output formatting options and no
opinion on output code quality. Expressions for example are all simply
emitted inline, which can lead to some rather nasty nesting and
repetition. Supports pretty much all FIRRTL ops that the `FIRParser`
would generate, except `MemoryPortOp`, `CMemOp`, `MemOp`, and `SMemOp`.
This came out of a quick hacking sprint towards a FIR reduction and
register/wire isolation tool to facilitate debugging.
Calling `parseFIRRTLType` and `FIRRTLType::print` would currently only
consider the hand-written type parsers and printers. On the other hand,
using the dialect hooks `FIRRTLDialect::parseType` and
`FIRRTLDialect::printType` would properly try to apply the generated
parsers and printers first, and then resort to the manual
implementations.
This commit fixes the inconsistency by introducing local `parseType` and
`printType` functions which appropriately try the generated and the
custom printer/parser to do the work. This decouples generated/custom
implementations from whether a type inherits from `FIRRTLType` or not.
(There are some helper types around `cmemory` that currently do not
inherit from `FIRRTLType`.)
`parseFIRRTLType` then simply calls these functions and performs a
dynamic cast to `FIRRTLType`.
A RootedInstancePath is just an instance path prepended with the root (aka top) module which the instance path is relative to. If we structure the placements based on this, we no longer have to walk the instance hierarchy while exporting TCL! This patch also removes support for locations not inside of instance switches. That use case required the design be fully elaborated which isn't really done.
SystemVerilog is very clear that these are 'self determined' operands
that don't participate in sign inference of >>> operators, and whose
value is always treated as an unsigned value.
It turns out that Verilog has some weird context sensitive sign inference
thing going on that affects the result type of the >>> operator and causes
it to do an unsigned shift. I cannot pin down how or why this happens,
so we'll just emit redundant $signed() casts around the operator to make sure
it is controlled appropriately.
I don't feel very good about not understanding this from reading the spec,
but empirically this is how it works with verilog implementations.
Adds a struct that walks the program to determine which libraries are necessary to be imported for the
native Calyx compiler. This is a very simple approach that isn't looking to optimize anything, since the
# of operations and # of import is relatively small.
Add the `verifLabels` lowering option which assigns an automatically
generated label to all verification statements (assert/assume/cover)
that have no label specified. This works around the issue of
verification EDA tools commonly requiring all verification statements to
be labeled.
This commit adds the labels of these ops to the name manager in the
ExportVerilog prepass, and then uses the manager to uniquify a generic
label generated for unlabeled ops in case the `verifLabels` option is
set.
Fixes#1691.
This add an option to control how `always_comb` is printed by the
verilog exporter. The default has been changed to print `always_comb`
as `always @(*)`. A lowering option `alwaysComb` has been added, similar
to `alwaysFF`, to use the old printing style. This change is motivated
by a lack of tool support for the `always_comb` verilog construct.
This implements `disallowLocalVariables` lowering option with a simple approach:
have ExportVerilog move roughly all expressions to the top level. This ensures
we don't need to generate automatic temporary variables, which aren't compatible
with classic-verilog consumers.
Fix a bug in the parser where a DontTouchAnnotation on a subfield would
not cause names to be preserved. Use the simplest solution here of
using the hasDontTouch method of AnnotationSet as opposed to the older
version of the method of the same name in the parser. Remove the old
hasDontTouch method in the parser (since this is now unused).
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Adds emitters for: RegisterOp, MemoryOp, GroupGoOp, GroupDoneOp, SeqOp,
WhileOp, IfOp, EnableOp, combinational guards. Remove HasParent trait from
MemoryOp since this is checked by the Cell trait (inherited by CalyxCell). Move
base class for CalyxPrimitive to CalyxPrimitives.td. Add helper functions for string
literals. Add simple emitter for imports.
Add a check that the foldResetMux rewrite pattern isn't used for
firrtl.regreset if the reset has a DontTouchAnnotation.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Add the `DataTapTests` from the Scala implementation of FIRRTL as an
integration test for the FIRRTL dialect. This uncovers a few subtle
breakages in the `GrandCentralTaps` introduced by changes to the
annotation scattering code that happened a while back. This fixes those
issues and the test ensures we don't have any regressions of this in the
future.
This makes lookup much faster, even though it still requires IR scanning.
This speeds up `firtool -extract-test-code -verilog` on a large design from
550s to 120s. There is still more to go though, as a -verify-each=false
run completes in 60s - we're still spending more time verifying than doing
work.
This resolves issue #1647.
This is the first step to supporting verilog implementations like Yosys
and Icarus Verilog that don't support SystemVerilog "automatic logic"
variables in procedural scopes.
For this step we handle side effecting operations (like the RANDOM
macros in FIRRTL lowering) by spilling them to a local reg with a
blocking assignment, the same way SFC does.
This is one step towards resolving Issue #1633
FIRRTL files coming out of chisel don't seem to preserve module
locations typically even though they could, but other clients can
produce location info for them, and we should print it.
It turns out that sv.bind can exist inside of a hw.module as well
as at the top level. These cause non-local references so we need
to make sure not to emit such modules concurrently with the modules
being emitted.
There is no good test for this, I noticed it due to a transient
failure of the existing ExportVerilog/sv-dialect.mlir test.
Using an `int32_t` to parse vector types limits our maximum vector
length to 2147483647. We have memory length 1 higher than that maximum,
and we need to use the `int64_t` parser to support it.
getReferencedModule is a performance tarpit because it has to scan the top
level of the circuit to find the right module. We already have the
instance graph, we should use it for all lookups.
This speeds up IMConstProp on a large testcase from 24s to 6.3s.
* [Handshake] Refactor handshake tablegen files
No functional changes; this commit creates an identical structure to the rest of the dialects in CIRCT wrt. how and where the various TableGen'erated files are included.
This parallelizes emission of operations when they are all emitted
to the same file by emitting to string buffers, then concatenating
them all at the end in series (simple map+reduce).
This speeds up emission of a large testcase on my laptop from 17s
to 5.2s, a 3.2x speedup.
This makes it part of the parallel emission when emitting split files,
and avoids having to keep the `ModuleNameManager` in memory for every
module in the circuit before emitting each file. This speeds up
split-verilog emission on a large design from 8.3s to 5.8s (~30%).
Previously all the extracted assert/assume modules were put at the top of the
file. This is a problem because the #ifdef boilerplate needs to come first.
This builds a SymbolCache at setup time, when the verilog exporter
is scanning the ops to see what files they go into. This cache is
then used when emitting each of the chunks, speeding up the
"getReferencedFoo" calls by turning them into O(1) lookups.
This speeds up export verilog on a large testcase that includes a
bunch of binds from 126s to 17s. It should also help speedup
other normal cases as well, since each instance has to resolve the
module it refers to.
The HW/SV dialects have a bunch of symbols used to map instances, modules,
interfaces etc, and corresponding "getReferencedXXX" methods to resolve
them. Each of these resolutions is really slow - scanning huge amounts of
the IR to resolve them, so we should have a way to shortcut that when a
client has done a prepass. The SymbolCache class allows making these faster.
This patch introduces the new functionality, but no clients of it.
Most of the FIRRTL code base expects port annotations to live in the
`portAnnotations` attribute on `FModuleOp` and `FExtModuleOp`. But the
parser, printer, and some operation builders accidentally store these in
`arg_attrs` through the standard argument attribute mechanism of MLIR.
This commit removes redundant/conflicting uses of `arg_attrs` and
`portAnnotations` in the code base. To keep things ergonomic for the
custom syntax of FIRRTL operations, we still parse and print port
annotations as part of the regular argument attributes (under the
`firrtl.annotations` key), but then immediately separate them out into
the `portAnnotations` attribute where all of our code expects this to
live.
When infering the direction of a CHIRRTL memory, we look through
subindexes, subfields, and subaccesses looking for connect ops which
could be reading or writing to the memory. The code to look through
subaccess was broken, leading to an infinite loop. This properly
recurses on the results of the subaccess op instead of the input.
The shift by constant canonicalizers extract the relevant bits from the
value and prepend/append 0s depending on the direction shifted. The
canonicalizer made a mistake in the extract op generation, chopping off
the high bits when shifting right, and chopping off the low bits when
shifting left. When doing a signed ShrS, it was using the low bit of the value
as the sign bit.
Add a verifier to check that sv.passign and sv.bpassign don't drive an
sv.wire. An sv.wire is a net type and can only be driven by sv.assign.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This follows a similar approach to the RegisterOp. Rather than
defining different primitives for different numbers of dimensions like
the Rust compiler, this uses a single operation to represent any
n-dimensional memory.
This generality means we can't enumerate explicit return types.
Rather, the return type is a variadic list of signless integer types.
A helper build method is provided to support this from C++ code, and a
verifier ensures everything lines up.
This also includes a helpful builder for RegisterOp.
Fix HWMemSimImpl bug where a wire was being procedurally assigned in RW
port code generation. Update the associated test to reflect this
change.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
- Add parameter S to the simplex tableau.
- Keep track of variable locations in the tableau.
- Add entry point in Algorithms.h.
- Set up test pass, prepare test cases.
Change lowering of muxes to casez to use legal Verilog. Change a wire
driven in an always block to be a reg. Change non-blocking assignment
to blocking assignment per Verilator lint suggestion.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This allows us to emit an arbitrary expression tree inline so long as
it is safe, including _tmp values generated to avoid line length
restrictions. This inlines most of them in practice.
This shrinks #lines of a large testcase I play with by 5%.
The verilog printer duplicates small verbatim expressions even if
they are used multiple times. This isn't safe to do for
side-effecting verbatims though, since the side effect will happen
multiple times.
Noticed by inspection.
This generalizes support for emitting inline initializers "just a
little bit". This is technically enough to resolve Issue #1567,
but there is more to do.
We previously had a bunch of special cases for constants that
worked but was a bit fragile. The issue is that there was coupling
between stuff that "knew" that out-of-line constants in procedural
regions are emitted in the declaration.
Clean this up a bit by adding a expressionsEmittedIntoDecl set,
which makes this more explicit and easier to generalize.
NFC.
Tools like Yosys don't support packed arrays, and we recently started
pattern matching mux chains into them. Teach HWLegalizeModules about
this idiom, lowering it into casez statements instead. This produces
uglier but more compatible verilog. For example, without this flag,
we produce things like:
wire [3:0][2:0] _T_83 = {{_T_15}, {_T_14}, {_T_13}, {_T_12}};
wire [3:0][2:0] _T_84 = {{_T_9}, {_T_8}, {_T_7}, {_T_6}};
wire _T_85 = _T_83[Queue_1_io_deq_bits_id] != _T_84[Queue_1_io_deq_bits_id];
with this flag we produce things like:
always_comb begin
casez (Queue_1_io_deq_bits_id)
2'b00:
_T_1 <= _T_15;
2'b01:
_T_1 <= _T_14;
2'b10:
_T_1 <= _T_13;
2'b11:
_T_1 <= _T_12;
endcase
end // always_comb
always_comb begin
casez (Queue_1_io_deq_bits_id)
2'b00:
_T_2 <= _T_9;
2'b01:
_T_2 <= _T_8;
2'b10:
_T_2 <= _T_7;
2'b11:
_T_2 <= _T_6;
endcase
end // always_comb
wire _T_79 = _T_1 != _T_2;
This is enabled by passing -lowering-options=disallowPackedArrays to
firtool. This fixes Issue #1592.
This pass provides a structured way to handle IR features that are not
supported by all tools, and this lowering option reflects a specific
limitation of the Yosys tool.
Right now the pass isn't super helpful: it just rejects unsupported operations
with an error. This is progress towards Issue #1592.
This adds an implementation of the RemoveCHIRRTL pass called
LowerCHIRRTL. This pass takes the CHIRRTL memory operations, `seqmem`
and `combmem`, and transforms them into standard FIRRTL `mem`
operations.
Add an explicit attribute for port annotations to FModule and FExtModule. Adding a common name for port annotations, similar to instance, mem, etc, makes manipulating annotations simpler. Although this could be folded into argattr, having it in the same format as used in other ops makes annotation scatting able to be operation type invariant, thus simplifying it.
* [Calyx] Add IR support for calyx::WhileOp
This commit adds support for the Calyx While control operation. The operation takes two arguments; a boolean port and a group name. The op has a single body region representing the groups to execute when the condition evaluates to true.
This is solely for IR support and does not include:
- CalyxEmitter support (unsupported for all control ops as of now)
- CompileControl control FSM generation
Co-authored-by: Andrew Lenharth <andrew@lenharth.org>
Co-authored-by: Fabian Schuiki <fabian@schuiki.ch>
Co-authored-by: Andrew Young <youngar17@gmail.com>
This improves verilog emission quality because it allows expressions
to be inlined into input ports of the module. This eliminates some
extranous wires, shrinking `wc -l` on a big testcase by 3%. This
fixes Issue #1568
This generalizes the previous patch to sink expressions with multiple
users to the deepest common region between all the users. In the case
of FIRRTL, this sinks a shocking amount of test-only code into
"ifndef SYNTHESIS" blocks, eliminating wires at the top level.
However, because these expressions have multiple uses, they don't get
emitted inline - they get temporaries declared at their local scope,
usually as `automatic logic` values. These never get their initializer
emitted inline (see Issue #1567), but sinking these is still the right
thing to do IMO.
This allows the verilog printer to print them inline, for example we'd
turn the example from Issue #1601 into:
```
module test(
input clock, a, a2, a3);
wire _T = a2 | a3;
always @(posedge clock) begin
`ifndef SYNTHESIS
if (`PRINTF_COND_ & a)
$fwrite(32'h80000002, "thing");
if (`STOP_COND_ & _T)
$fatal;
`endif
end // always @(posedge)
endmodule
```
We now produce: `if (`STOP_COND_ & (a2 | a3))` with no temporary
wire. This is a pretty huge improvement to lots of things.
There is a more general version of this as well, but it seems best
to split into two patches.
This allows it to compose with the binary expression tree lowering
work that is already there, allowing us to handle multi-operand
additions that end with a constant.
This pass is duplicating unary ops in order to make verilog prettier,
but can result in the op being in a different block than the constant.
This causes the constant to get emitted as a weird local param, which
can even be unused in the generated verilog. Fix this to duplicate
the constant operands as well.
* [Calyx] Add IR support for calyx::IfOp
This commit adds support for the Calyx If control operation. The operation takes two arguments; a b boolean SSA value and a group name. The op has two regions, a mandatory 'then' and optional 'else' region.
This is solely for IR support and does not include:
- CalyxEmitter support (unsupported for all control ops as of now)
- CompileControl control FSM generation
When emitting two always/initial/... blocks with the same conditions, leave the
resultant block at the location of the last use, instead of at the location of
the first use. This ensures that the values used by that block are defined above
it.
This isn't necessary by the semantics of our IR, since hw.module is a graph region,
but leads to better generated verilog and puts less pressure on the cleanup passes.
When a node is used as the address (aka index) of a CHIRRTL synchronous
read-only memory port, the memory port is enabled at the declaration
location of the node op. Nodes are being removed by the parser if they
don't carry any annotations. When the node op is removed by the parser,
the enable conditions of the memory change, and sometimes the memory
port is never enabled.
This change removes the small optimization from the FIRParser so that
the memory port enable can be properly inferred. These node operations
will still be removed later on during canonicalization.
The two CHIRRTL memory operations have been renamed from `smem` to
`seqmem` and `cmem` to `combmem`. In addition, instead of returning
`!firrtl.vector<>` types, they return a new type `!firrtl.cmemory`.
This new type can only be used with CHIRRTL memories and ports, and
prevents some shenanigans where it could be used like a normal vector.
Memory ports in SFC are allowed to be used outside of the scope which they are
defined in. To work around this issue, the memory port declaration was split
into two operations:
1. `firrtl.memoryport`: This operation is the declaration of the memory port,
and it should be emitted into the body of the module.
2. `firrtl.memoryport.acccess`: This operations is emitted to the location of
the original memory port declaration, and is used for enable inference.
For more information about these new operations, and why we added them, see the
changes to FIRRTLRational.md.
This include changes to the FIR parser to emit these new operations.
Schuyler points out in Issue #1600 that it isn't correctly implemented,
and there is only one place in the compiler that forms it ... in a
theoretical case. I added this a long time ago on a theoretical basis.
It is best to remove this until there is a real need for it.
This fixes Issue #1600.
This enables LowerToHW's auto-cse of always blocks to kick in in more
cases, e.g. in the example from Issue #1594. Thanks to Schuyler for
tracking down the root issue here.
The Cell trait is used to annotate each sub-component within a component.
This consists of primitives (e.g. RegisterOp) and component instances. This will
be useful for future passes that want to work on Cells, such as resource-sharing.
I've also renamed the CellOp to InstanceOp.
Fix a bug where a spilled localparam could result in invalid Verilog (a
two-statement always block without a begin/end).
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Fix an issue where we would iterate over `op->getUses()` for each
`InvalidValueOp` to create a unique instance of the op for every use.
That iterator gets invalidated by the modifications we make though,
which caused only the second (yes, exactly the second) use to be
properly uniquified, with all others remaining the same.
`llvm::make_early_inc_range` to the rescue.
Thanks to @youngar for reducing this down from a much larger test case
and doing the awesome work of hunting this down in a >70M source file.
Add the reset network name to error messages about conflicting async and
sync drives to the same network. They now read something like:
error: reset network "foo.io.reset" simulatenously connected to async
and sync resets
Fix issues related to zero width behavior involving trailing commas and
end of instance declarations.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Block inlining of ArrayCreate into ArrayGet users. This prevents
ExportVerilog from producing invalid Verilog. Add one test that locks
in this behavior and update existing tests that incorrectly expected
this.
Fixes#1587.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Expand whens takes the following code:
```firrtl
when a:
x <= 1
else
x <= 2
```
And transforms it turns it into the (desirable) code:
```firrtl
x <= mux(a, 1, 2)
```
However for nested whens, it was being overly pessimistic in the
condition of the mux.
Expand whens takes the following code:
```firrtl
when a:
when b:
x <= 1
else:
x <= 2
else
x <= 3
```
And transforms it into
```firrtl
x <= mux(a, mux(a & b, 1, 2), 3)
```
When it should transform it into:
```firrtl
x <= mux(a, mux(b, 1, 2), 3)
```
In the code change `condition` refers to the condition of the current
WhenOp , and `thenCondition` refers to the all parent `WhenOp`
conditions `and`ed together. The `thenCondition` is intended to be used
for simulation constructs which are copied directly into the module's
body.
The following example shows how `thenCondition` is used:
```firrtl
when a:
when b:
printf(clock, UInt<1>("h1"), "hi")
```
Here, `thenCondition` is `a & b`:
```firrtl
printf(clock, a & b & 1, "hi")
```
When tracing the resets of a connect operation, the pass would
recursively trace the src and dest values. When one of the values came
from a subfield operation, it would associate the resets of the input
bundle of the subfield operation with the resets in result. The pass
neglected to recursively trace the resets of the input of each subfield
operation, which resulted in a failure to determine the correct
reset-network when there were nested aggregates.
To fix this, we need to recursively trace the resets of the input
expression of every subfield operation.
This strategy of recursively visiting the src and dest expressions of a
connect statement probably comes from the SFC, where the result of a
subfield operation can only be used once. In MFC this could result in
visiting the same subfield operation multiple times. It is more
efficient to handle subfield and subindex operations as we walk through
the module. By handling each subfield operation as we see it, we don't
need to recursively trace subfield operations.
Also update the types of extmodule ports that were inferred during reset
inference. In general we do not want to update the type of extmodules,
since these are provided from the outside and the interface is thus
fixed. However in the case of reset inference where the types all map to
the same Verilog, this is okay to do.
This currently uses the types inferred for `InstanceOp`s to determine
what types the corresponding extmodule should have. This works in the
cases we are interested in, but can break in some corner cases where a
reset network is only connected through an extmodule port. In that case,
since we don't have a `Value` for that extmodule port, the two reset
networks can remain disjoint.
This fixes#1578.
The presence of `InvalidValueOp` is problematic during reset inference.
Generally, CSE will ensure that there is at most one `InvalidValueOp` of
a given type. However, if that op is of `ResetType`, it might be
connected to multiple reset networks as a `rst is invalid` connection.
Currently, `InferResets` will consider these reset networks to become
connected along this `InvalidValueOp`, which is incorrect.
This commit adds a `InvalidValueOp` uniquification step to the beginning
of reset inference, which replicates these ops such that they have at
most one use. This is necessary, since that single `ResetType` invalid
value may become part of a `AsyncResetType` and a `UIntType` reset
network, in which case two distinct invalid values are required.
This fixes an issue uncovered by @youngar and @Ramlakshmi3733.
This takes the example in Issue #1560 from:
```
assign a = (auto_in_aw_bits_addr[37:29] ^ 9'h2) == 9'h0;
```
to:
```
assign a = auto_in_aw_bits_addr[37:29] == 9'h2;
```
which is a heck of a lot better than the starting point of:
```
assign a = ~(|({1'h0, auto_in_aw_bits_addr ^ 38'h40000000} & 39'h7FE0000000));
```
This now turns things like `(and x, 3) == 1` into `extract x[1:0] == 1`.
This composes very nicely with extract shrinking, but extract shrinking
needs to be taught some new tricks.
This generalizes the analysis beyond literal constants to handle some simple
expressions that generate known bits, starting with 'and' and 'or' expressions.
Given a value with some known and some unknown bits, we extract out the portion
of the expression that is unknown and compare just it instead of the whole
value. This composes very naturally with our existing 'truncate folding'
optimizations.
This turns the example in Issue #1560 from:
```
wire [37:0] _tmp = (auto_in_aw_bits_addr ^ 38'h40000000) & 38'h3FE0000000;
assign a = _tmp == 38'h0;
```
into:
```
assign a = (auto_in_aw_bits_addr[37:29] ^ 9'h2) == 9'h0;
```
Which is a nice step forward and enables xor folding. However, I realize
now that this whole thing can be far more general than icmp of concats.
I will take care of this in a follow-up patch.
When we know something about the bits in the concat operands we can
simplify equality comparisons, reducing the number of operands to the
concat (and eliminating it entirely in some cases.
This further simplifes the testcase in Issue 1560 from:
```
wire [37:0] _tmp = (auto_in_aw_bits_addr ^ 38'h40000000) & 38'h3FE0000000;
assign a = ~(|{1'h0, _tmp});
```
to:
```
assign a = ~(|((auto_in_aw_bits_addr ^ 38'h40000000) & 38'h3FE0000000));
```
The folder for this wasn't properly handling the single-op case
(which is a noop) and the canonicalize hook wasn't prepared to handle
it.
This also includes some minor NFC formatting tweaks.
Add a fold pattern for mux when the low and high are the same constant.
That is,
x = mux (cond, <constant1> ,<constant1>)
can be replaced with,
x = constant1
This can enable IMConstProp to constant propagate through mux trees.
A mux is cheaper than a sext+logic op. This change allows us to
handle the SevenSegmentDecoder example from Issue #675. We now
produce:
```
wire [6:0] _T = {1'h0, in == 4'h1 ? 6'h6 : 6'h3F};
wire [15:0][6:0] _tmp = {{_T}, {_T}, {7'h5B}, {7'h4F}, {7'h66}, {7'h6D}, {7'h7D}, {7'h7}, {7'h7F}, {7'h6F}, {7'h77}, {7'h7C}, {7'h39}, {7'h5E}, {7'h79}, {7'h71}};
assign out = _tmp[in];
```
which is way nicer than a pile of ternaries. The extraneous wire
is due to an explicit pad, which I'll file as another opportunity.
It is useful to strength reduce operations when it makes sense, but
mux's are "as primitive" as and, or and certainly sign extend. There
is no reasonable cost model that says we should expand them out.
This enables more aggressive analysis of mux trees and resolves
Issue #1549.
[Comb] Fold a large series of of mux ops into array_create/get
This substantially shrinks the size of the IR and generates much
better verilog. E.g. before:
```
module top_mod(
input [1:0] sel,
input [7:0] a, b, c, d,
output [7:0] y);
assign y = sel == 2'h0 ? a : sel == 2'h1 ? b : sel == 2'h2 ? c : d;
endmodule
```
and after:
```
module top_mod(
input [1:0] sel,
input [7:0] a, b, c, d,
output [7:0] y);
assign y = ({{a}, {b}, {c}, {d}})[sel];
endmodule
```
This uses a couple heuristics to keep things from going crazy. This
is progress towards closing Issue #675, but it is still not getting
some important cases due to Issue #1549. Those can be handled as
follow-up patches.
* [Comb] Canonicalize away shifts by a constant
* move some canonicalization to fold
* use c array instead of small vector
* small fix
* add builder to extract op
* clang-format
Update FIRRTLFolds to use the method getSingleConnectUserOf
that scans all the uses of the specified value, checking to see if there is
exactly one connect that sets the value as its destination. This returns
the operation if found and if all the other users are "reads" from the
value.
(Followup to address comments on #1546)
* Extract reset-related test cases from the existing Scala FIRRTL
compiler code; specifically from `InferResets`, `CheckResets`,
`RemoveReset`, and `FullAsyncResetTransform`.
* Add the `InferResets` transformation pass to the FIRRTL dialect, which
assigns asynchronous resets to registers without reset, and replaces
`reset` types with either `uint<1>` or `asyncreset`, as appropriate.
* Add the `--infer-resets` option to firtool, on by default.
This was always intended to be supported, but was removed in
862f1b4. This adds it back, and updates the parsers for the relevant
ops to actually support type aliases (they previously didn't).
In order to help avoid the need to cast away aliases everywhere, a new
base class is added to all aggregate types that support aliases. This
class can represent a type alias or the aggregate type. It implicitly
converts to the aggregate type, which helps avoid explicit casts.
Fix a bug where the subindex of a target would be sign extended instead
of zero extended. This could result in situations where the subindex
would show up as negative and the annotation would not be applied.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Placement data can now be filtered to a particular instance. Adds the SwitchInstance attribute to select an attribute from a list keyed off the instance ID (currently just the path in the instance hierarchy). This method is not robust to hierarchy changes, but it's a start.
Modified ExportTcl to respect the SwitchInstance attribute
Fix an issue where type equivalency was not existing after verifying
that two bundles were equivalent. This resulted in a fall-through check
that the widthless type of two bundles _also_ being compared. This
would cause issues where a bundle with an abstract reset would fail to
type check against a uint<1>.
Add a small test of this behavior.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Extends the basic problem model with a new operator type property 'limit', representing the maximum number of operations that can "use" a given operator type in each time step.
A register with constant reset and a single connection to a mux
with the same constant can be replaced with that constant
```
%c11_ui8 = firrtl.constant 11 : !firrtl.uint<8>
%r = firrtl.regreset %clock, %reset, %c11_ui8 : !firrtl.uint<1>, !firrtl.uint<8>, !firrtl.uint<8>
%0 = firrtl.mux(%cond, %c11_ui8, %r)
firrtl.connect %r, %0 : !firrtl.uint<8>, !firrtl.uint<8>
firrtl.connect %z, %r : !firrtl.uint<8>, !firrtl.uint<8>
```
can be replaced with
```
%c11_ui8 = firrtl.constant 11 : !firrtl.uint<8>
firrtl.connect %z, %c11_ui8 : !firrtl.uint<8>, !firrtl.uint<8>
```
Constant propagate registers that are driven by a mux tree
containing only instances of one constant and self-assigns.
Detect the case if a register only has two possible drivers:
(1) itself/uninit and (2) constant.
The mux can then be replaced with the constant.
reg = mux(cond1, reg, 3) can be replaced with --> reg = 3
reg = mux(cond2, 3, reg) can be replaced with --> reg = 3
Fixes#1483
Port the `WidthSpec` tests from the Scala FIRRTL implementation over
into an integration test for firtool. This uncovers a few integer
overflow issues in the parser/types, which this fixes alongside the
tests.
* Added Tcl bindings for loading an MLIR file.
* Ran clang-format
* Updated Tcl library path
* Update simple.tcl
* Implemented Lenharth's suggestions
* Ran clang-format
* Fixed integration test
* Added checks to integration test
* Implemented some of Mike's suggestions
* Added another argument
* Added paths to Tcl debug output in CMAKE
This scheduler uses linear programming and a handwritten simplex solver to compute the II and start times for the CyclicProblem. It's an implementation of the approach proposed in:
B. D. de Dinechin, "Simplex Scheduling: More than Lifetime-Sensitive Instruction Scheduling", PRISM 1994.22, 1994.
A third-take a implement operation narrowing, after failed attempts in #1475 and #1424 . The main fix introduced by this commit is setting insertion points at appropriate points before calling rewriter.create for narrowed operations.
This optimization rewrite arithmetic (add, mul, sub) and bitwise logical (and, xor, or) operations into the narrowest possible version without needing. For example
```mlir
%addResult = add %a, %b : i10
%addResult = extract %addResult from 0 : i10 -> i3
into addition only on bits that will be used
```
will be transformed to the following narrowed ops.
```mlir
%a' = extract %a from 0 : i3
%b' = extract %b from 0 : i3
%addResult' = add %a', %b' : i3
%c0 = hw.constant 0 : i7
%addResult = concat %c0, %addResult' : (i7, i3) -> i10
%addResult = extract %addResult from 0 : i10 -> i3
```
Fix the port order of read-write ports for FIRRTL memories. This fixes
an issue where doing an aggregate connect to a FIRRTL read-write memory
would work in the Scala FIRRTL Compiler, but not work in CIRCT.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
The annotations of all bundle type subfields (`data` and `mask`) of
MemOp ports should be filtered. This patch can avoid the unnecessary
subfield index comparisons.
Create parent output directories if needed as opposed to crashing if the
parents don't already exist.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
When lowering a FIRRTL instance marked as "lowerToBind" stop setting a
default output file. Instead, copy over an "output_file" attribute if
one exists. This provides more predictable behavior where it is the
responsibility of a FIRRTL pass to setup bind-lowering behavior as
opposed to relying on some default filename derived from a Grand Central
naming convention.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Copy an "output_file" attribute from a FIRRTL module to a HW module if
such an attribute exists. This enables FIRRTL transforms to set output
file information in a FIRRTL pass, which may be necessary if such
information is available in an annotation that that pass consumes.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This pass runs a strongly connected components (SCC) detection to check
combinational cycles in the IR. The current implementation assumes the
firrtl-lower-types and firrtl-expand-whens has been applied before this pass.
The llvm::SourceMgr class lazily builds a line table, and isn't
internally synchronized. This can cause crashes with threaded
parsing. This fixes Issue #1513.
Stop folding or/xor with invalid operands when the types of the
non-invalid operand doesn't match the result type. This covers the case
where or and xor can take SInt operands and return a UInt result.
Include a temporary test that checks that this behavior works.
This behavior is expected to be changed in the future via a
canonicalizer that will do the cast as necessary.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>