Commit Graph

63 Commits

Author SHA1 Message Date
John Demme 8c1865c5a9
[ESI] Make RAM delarations' addresses unsigned (#8658)
Using signless ints as the address was just wrong. It was probably done
to avoid incomplete lowerings, which have been addressed. Changes RAM
declaration addresses to use unsigned integer types throughout the
ESI dialect and its tests, updating both the code generator and
expected outputs.

- Switch address ports to unsigned (uiN) in MLIR tests and service
  definitions.
- Update service port generation and SystemVerilog memory
  instantiation to use unsigned address types, inserting bitcasts to
  signless for indexing.
- Adjust PyCDE front end and software integration tests to use
  UInt addressing.
2025-07-07 12:43:12 -07:00
John Demme aa8b980f6a [Handshake] Create unique AppIDs while lowering with ESI wrapper
When lowering with ESI memory requests, we need to generate unique
AppIDs otherwise the ESI service connection pass fails.
2025-05-14 00:47:46 +00:00
John Demme a40aed047d
[Handshake] Adding func instance op for integration (#7812)
Adds the ESIInstanceOp. This op allows a non-handshake design to
instantiate `handshake.func`s. Since handshake needs elastic inputs and
produces elastic outputs, this uses ESI channels.
2024-11-15 12:00:40 -08:00
Will Dietz 8cd116d370 [NFC] Fix missing eof newline. 2024-08-15 15:09:33 -05:00
Girish Pai bf7c4e722e
Bump LLVM (#7223) 2024-06-26 13:19:37 -07:00
Morten Borup Petersen aba85bf470
[Handshake] Add control_merge deconstruction pattern (#6934)
This pass deconstructs the (rather complex) semantics of a >2 input cmerge operation into a series of 2-input cmerge operations + supporting logic. This simpler structure is better suited for `dc` lowering, which only supports lowering 2-input control merge operations.

Simplify

fix test

Also split regular merges

nit

Fix index type propagation for cmerge

Also zext non-`builtin.index`-typed `control_merge` operations
2024-05-07 11:08:04 +02:00
John Demme 6212d2ed21
[ESI] Simplify services by standardizing on `to_client` ports (#6633)
Having a direction on the service ports which just reversed the bundle directions was far too complicated. Standardize on the service always packing the bundle and sending it to the client. Standardizing that way has the additional benefit that this was already the canonical form which all the service generators saw. Remove all to_client verbiage from the IR.
2024-02-01 11:58:50 -08:00
John Demme d89f7d825b
[ESI] Service requests now track AppIDs rather than instance hierarchy (#6328)
This makes for far more sensible hierarchies. Also makes the index field of AppIDs optional.
2023-10-23 14:00:08 -07:00
John Demme db6112698d
[ESI] Move services over to bundles (#6302)
Services now only support bundle ports. Bundles pretty significantly simplify services at the expense of some nomenclature complexity.
2023-10-19 12:03:49 -07:00
Andrew Lenharth 164dbaf9cd
[HW] Change printer for modules (#6205)
This is quite invasive.  This converts from the functiontype printer to the moduletype printer.

---------

Co-authored-by: Mike Urbach <mikeurbach@gmail.com>
2023-09-28 16:30:15 -05:00
Nandor Licker 0fc8656168
[Seq] Switch all seq ops to use seq.clock (#6139) 2023-09-18 16:38:32 +03:00
Morten Borup Petersen 83abbfc0f4
[Handshake] Allow handshake ops to be used outside of a `handshake.func` (#6132)
... 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".
2023-09-18 10:42:02 +02:00
Lucas Ramirez 0fa1b01f15
[Handshake] Remove cmerge return type inference (#5021)
This commit removes the InferTypeOpInterface from ControlMergeOp because
it no longer made sense w.r.t. the variable type of the index result introduced in
#4929). Additionally, when parsing a control_merge with an index type different
than "index", it would raise an error because of the mismatch between the
parsed and inferred types. Example code that would trigger it below.

```
handshake.func @test(%arg1: i32, %arg2: i32) {
    %result, %index = control_merge %arg1, %arg2 : i32, i64
    return
}
```

The commit also adds a custom builder for ControlMergeOp (that was
previously auto-generated by InferTypeOpInterface) to allow creating
the operation without explicitly providing return types. The builder defaults
to an Index type for the op's second result.
2023-04-13 11:11:29 +02:00
Lucas Ramirez 469ba91a54
[Handshake] Make ControlMergeOp index result AnyType (#4929)
[Handshake] Make ControlMergeOp idx result AnyType

This commit changes the type of ControlMergeOp's second result
(representing the index of the propagated input) from an Index to an
AnyType. A verifier is implemented for the operation that checks that
this result is either an Index or IntegerType of large enough bitwidth
to support indexing the operation's operands. This aligns the
verification logic of this result with the one for the select operand of
MuxOp's, which is semantically similar.

ControlMergeOp's assembly format is changed to also print the type of
the second result, since it is no longer necessarily an Index. If the
result types are not specified explicitly during operation construction,
the second result will default to an Index. Tests are modified to
reflect the change in assembly format.
2023-04-05 10:33:46 +02:00
Lucas Ramirez 083de301f0
[Handshake] Fix incorrect operation deletion in EliminateCBranchIntoMux canonicalization pattern (#4650)
This fixes a bug in the `EliminateCBranchIntoMuxPattern` canonicalization pattern where a `cond_br` operation would get deleted despite still having uses. Below is an example handshake.func which would trigger the bug.

```mlir
handshake.func @cbranch_into_mux_elim(%arg0 : i1, %arg1 : index, %arg2 : i32, %arg3: none) -> (i32, i32, none) {
  %trueResult, %falseResult = cond_br %arg0, %arg2 : i32
  %0 = mux %arg1 [%trueResult, %falseResult] : index, i32
  %1 = arith.addi %trueResult, %trueResult : i32 
  handshake.return %0, %1, %arg3 : i32, i32, none
}
```

Here the `cond_br` would get deleted despite `%trueResult` still being used by `arith.addi`.
The above example is added to Handshake canonicalization tests.
2023-02-22 15:14:30 +01:00
Lucas Ramirez 88de5cd00c
[Handshake] Cleanup Handshake operations builders (#4416)
* isControl paramater for some HandshakeOps builders

Logic to determine whether a Handshake operation is control-only
or not was moved outside the builders and into the
StandardToHandshake conversion pass. Modified builders now take an
isControl parameter.

* Cleaned up merge-like operations builders

This commit refactors and cleans up the merge insertion logic in
StandardToHandshake. The pass now creates valid merge-like operations
from the beginning with backedges as operands. All backedges are then
resolved in reconnectMergeOps. This allows us to remove some operation
builders that were only used during StandardToHandshake.

* Handshake builders cleanup and SOST interface

This commit removes a lot of custom builders for Handshake operations,
and re-enables default builders for most operations. The commit also
replaces the sost namespace (along with its operation attributes logic)
with an SOSTInterface that Handshake operations can implement to achieve
the same purpose with less code and more reliability. This in turns
facilitates the deletion of some operation attributes that were
redundant.

A lot of tests still fail on this commit due to largely unupdated
parse and print logic for Handshake operations.

* Fixed many issues, all tests passing

This commit fixes many issues introduced during Handshake operation
builders cleanup, many related to parsing, printing, or constructing
operations. In the HandshakeToFIRRTL pass, the control-ness of each
Handshake operation is cached in an attribute before lowering to
accomodate the new logic to determine whether an operation is
control-only.

* Verification and type inference for HandshakeOps

This commit adds some verification logic as well as return type
inference for a number of Handshake operations. The latter allows to
shorten the creation of Handshake operations in many places as the
return type(s) need no longer be specified at creation.

The commit also introduces a simple builder for ForkOp and LazyForkOp.
2022-12-09 08:04:23 +01:00
Christian Ulmann 327bad9b2e
[Handshake][lit] Move buf insertion tests to correct dir (#4329)
Instead of having the buffer insertion tests as part of the
std-to-handshake tests, they are now part of the handshake specific
tests.
2022-11-18 16:28:13 +01:00
Lucas Ramirez 58a114d8f6
[Handshake] Canonicalize away simple mux+cbranch structures (#4272)
This commit adds a new MuxOp rewrite pattern that canonicalizes
muxes with two data operands originating from the same conditional
branch, resulting in the removal of at least one mux and one
cbranch. It also adds three new tests to check for the correctness
of the rewrite pattern, and updates existing tests to reflect the
expected change in canonicalized IR.
2022-11-09 15:04:40 +01:00
Morten Borup Petersen bac3f28cbf
[HandshakeToHW] Fix extmem lowering (#4198) 2022-10-27 11:58:15 +02:00
Morten Borup Petersen 1db9d8499d
[Handshake] Add memref legalization pass (#4191) 2022-10-26 21:35:51 +02:00
Morten Borup Petersen 39850eec8e
[Handshake/ESI] Resolve esi wrapper predeclaration in HandshakeToHW (#4073) 2022-10-11 08:37:37 +02:00
Morten Borup Petersen da1ad9df93
[Handshake+ESI] Generate ESI memory service wrapper duing extmem lowering (#4033)
This turned out to be a bit more complicated than I had expected (assumptions placed on the hardware interface of the module, this pass still need high-level memory info, index types are used for memory in Handshake, ESI strictly requires clog2(memory size) for address signals). I'm sure there's a more principled way of doing this, but that was not what flowed out of the fingers.

A wrapper is created which instantiates an `esi.mem.ram` service for each `memref` argument of the original handshake function. This wrapper also instantiates an external module which is a stand-in for the module that will be created during `HandshakeToHW`. The load- and store ports of the to-be-lowered instance are plumbed up with esi service requests.

Given a handshake function as follows, with 1 load and 1 store port:
```mlir
handshake.func @main(%arg0: index, %arg1: index, %v: i32, %mem : memref<10xi32>, %argCtrl: none) -> none
```

the following IR is generated:
```mlir
  hw.module.extern @_main_hw(%arg0: !esi.channel<i64>, %arg1: !esi.channel<i64>, %v: !esi.channel<i32>, %mem_ld0.data: !esi.channel<i32>, %mem_st0.done: !esi.channel<i0>, %argCtrl: !esi.channel<i0>, %clock: i1, %reset: i1) -> (out0: !esi.channel<i0>, mem_ld0.addr: !esi.channel<i4>, mem_st0: !esi.channel<!hw.struct<address: i4, data: i32>>)
  esi.mem.ram @mem i32 x 10
  hw.module @main_esi_wrapper(%arg0: !esi.channel<i64>, %arg1: !esi.channel<i64>, %v: !esi.channel<i32>, %argCtrl: !esi.channel<i0>, %clock: i1, %reset: i1) -> (out0: !esi.channel<i0>) {
    esi.service.instance @mem impl as "cosim" opts {}(%clock, %reset) : (i1, i1) -> ()
    %0 = esi.service.req.inout %main.mem_ld0.addr -> <@mem::@read>([]) : !esi.channel<i4> -> !esi.channel<i32>
    %1 = esi.service.req.inout %main.mem_st0 -> <@mem::@write>([]) : !esi.channel<!hw.struct<address: i4, data: i32>> -> !esi.channel<i0>
    %main.out0, %main.mem_ld0.addr, %main.mem_st0 = hw.instance "main" @_main_hw(arg0: %arg0: !esi.channel<i64>, arg1: %arg1: !esi.channel<i64>, v: %v: !esi.channel<i32>, mem_ld0.data: %0: !esi.channel<i32>, mem_st0.done: %1: !esi.channel<i0>, argCtrl: %argCtrl: !esi.channel<i0>, clock: %clock: i1, reset: %reset: i1) -> (out0: !esi.channel<i0>, mem_ld0.addr: !esi.channel<i4>, mem_st0: !esi.channel<!hw.struct<address: i4, data: i32>>)
    hw.output %main.out0 : !esi.channel<i0>
  }
  handshake.func @main(%arg0: index, %arg1: index, %arg2: i32, %arg3: i32, %arg4: none, %arg5: none, ...) -> (none, i4, !hw.struct<address: i4, data: i32>) attributes {argNames = ["arg0", "arg1", "v", "mem_ld0.data", "mem_st0.done", "argCtrl"], resNames = ["out0", "mem_ld0.addr", "mem_st0"]}
```
2022-10-07 10:43:58 +02:00
Christian Ulmann 41c9ab471f
[Handshake] Drop ctrl requirement from InstanceOp (#4047) 2022-10-03 22:45:46 +02:00
Morten Borup Petersen cd3d1a2285
[Handshake] Add `handshake.extmem` lowering pass (#4020)
This is intended to be a lowering used for transforming Handshake to hardware.
The transformation materializes the top-level `memref` to a new set of in- and output arguments, and plumbs to the in- and output values of the `handshake.extmem` operation which referenced the memref. This is essentially what is was done by `HandshakeToFIRRTL`/`HandshakeToHW` but can be moved as a preprocessing step.

Another motivation for doing so is to create a more natural interface for external users to interact with:
- Store ports now have a single handshake'd output port with combined addr+data.
- Load ports now only requires a single handshake'd data input. This input is then forked into its data+control parts to feed the load- and store operations.

In doing so, we also use `!hw.struct` types to ensure that correct names are being maintained for the in- and output values. This is opposed to using tuples, which does not have named fields.
The tuple requires use of `hw.struct_create` - in HandshakeToHW, this can be supported identically to `handshake.pack` which itself uses `hw.struct_create` after tuple types have been lowered to structs.
2022-09-30 12:24:04 +02:00
Christian Ulmann 7eed8f45e6
[Handshake] Expose bufferRegion for other users (#3992)
This commit exposes a new `bufferRegion` function that is independent of
`handshake.func`. Additionally, it cleans up some of the code in the
buffer insertion.
2022-09-26 10:50:18 +02:00
Christian Ulmann 20891276ff
[Handshake] Remove default arg and res name for ctrl signals (#3974) 2022-09-22 16:14:19 +02:00
Christian Ulmann a49d283eeb
[Handshake] Ignore external funcs when performing a transform (#3972) 2022-09-22 14:51:26 +02:00
Christian Ulmann 1ec0160bc6
[Handshake] Fix external func parsing (#3971) 2022-09-22 13:16:04 +02:00
Christian Ulmann 5aab28c0c1
[Handshake] Add pass that locks functions (#3855)
This PR introduces a handshake pass that adds a lock mechanism for functions.
Such a mechanism ensures that there is only one active control token in a function at each point in time.

An additional "RUN" directive/command was added to the integration tests that otherwise require a task-pipelining transformation. These test runs disable task-pipelining in favor of locking but should still yield the same results (albeit with lower throughput)
2022-09-20 10:57:43 +02:00
Christian Ulmann d18142046b
[Handshake] Add sync op (#3912)
A `SyncOp` will make its results available once all inputs have arrived.
2022-09-16 13:27:39 +02:00
Christian Ulmann a610303a74
[Handshake] Relax the ctrl in/output requirement (#3867)
The ctrl in- and outputs are mandatory for DHLS style usage, but in
general, they aren't required for well-formed handshaked circuits.
2022-09-12 14:39:24 +02:00
Christian Ulmann d75838177a
[Handshake] Change join to accept all input types (#3860)
This commit lifts the unnecessary limitation of `JoinOp`'s only having one input type.
2022-09-12 10:11:54 +02:00
Fabian Schuiki 93112d40df
Bump LLVM (#3649)
* Bump LLVM

Bump LLVM to the current top-of-tree.

This requires changing a few `Attribute`s to the new `TypedAttr`
interface, since attributes no longer carry a type by default. We rely
on this type in quite a few places in the CIRCT codebase, which required
a switch over to `TypedAttr`.

See: https://reviews.llvm.org/D130092

Co-authored-by: John Demme <john.demme@microsoft.com>
2022-08-07 09:21:55 +02:00
Christian Ulmann cce079c8ae [StandardToHandshake] Always emit `extmemory`, even when unused
This commit ensures that all memrefs are connected to memory.
2022-06-05 09:42:56 +02:00
Christian Ulmann bf9f2d540a [Handshake] Add missing `lsq` attribute to `MemoryOp` 2022-06-02 15:14:41 +02:00
Christian Ulmann f7bb6b460d [Handshake] Add type equality checks to InstanceOp
This commit adds the `SymbolUserOpInterface` to the `InstanceOp` which
is used to enforce type equality of the operation and the `FuncOp` it
calls.
2022-05-20 08:00:45 +02:00
Christian Ulmann da0c16a8ac [Handshake] Add tuple pack and unpack operations 2022-05-06 08:03:57 +02:00
Christian Ulmann be3f5b530b [Handshake] Add sink materialization for block arguments 2022-05-03 15:44:27 +02:00
Christian Ulmann a2e0dc63d5 [Handshake] Add optional visibility parsing for `FuncOp` 2022-05-02 21:29:07 +02:00
Richard Xia 9127a771d2
Update LLVM to 1aa4f0bb (#2901)
* [Conversions][Transforms] Add missing includes due to refactoring in upstream MLIR.

LLVM commit 36d3efea15e6202edd64b05de38d8379e2baddb2 removed a few
include statements from mlir/Pass/Pass.h, so we have to update a few of
the files here to add back in some includes.

* [Handshake][SV] Migrate from StrEnumAttr to EnumAttr.

StrEnumAttr was removed in upstream LLVM commit
60e34f8dddb4a3ae5b82e8d55728c021126c4af8. It has been replaced with
EnumAttr, which can do everything that StrEnumAttr could do but more
efficiently.

This affected two specific attributes: Handshake's BufferType, and SV's
ModportDirectionAttr. Both have been converted over to EnumAttrs. Their
parsers had to be updated, since the new EnumAttr no longer likes having
double quotes around the enum value in the assembly format.
Consequently, the tests were also updated.

* Bump llvm to 1aa4f0bb6cc21b7666718f5534c88d03152ddfb1.
2022-04-15 16:07:46 -07:00
Nandor Licker d0f1d99581 [NFC] Added newlines to the end of files 2022-03-28 18:58:23 +03:00
huanghuang 0dff6bb8a6
[Handshake] Replace BufferOp sequential attribute with StrEnumAttr bufferType (#2670)
For better semantics, replace bufferOp sequential attribute with bufferType attribute
and use StrEnumAttr to represent seq or fifo.
Now  the format of bufferOp in mlir past like,
     %5 = buffer [1] %12 {initValues = [0], sequential = true } : i1
     %0 = buffer [2] %arg0 {sequential = false} : i32
 will be
     %5 = buffer [1] seq %12 {initValues = [0]} : i1
     %0 = buffer [2] fifo %arg0: i32
2022-03-01 17:41:39 +08:00
Schuyler Eldridge 61b2eda047
Bump LLVM, Remove Unnecessary Handshake Test (#2702)
Bump LLVM.

Remove one Handshake test that was testing a verifier that is superseded
by an internal LLVM/MLIR check.

Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
2022-02-28 15:09:48 -05:00
Morten Borup Petersen 5fc6ef49b7
[StandardToHandshake] Add loop handling networks (#2444)
While testing handshake accelerators, it has been a general issue that kernels were not able to be function pipelined. That is, having multiple activations of a kernel live, concurrently.
The reason for this is due to the previous use of control-merge operations at backedges in the CFG (loops). By doing so, multiple kernel invocations are able to enter the loop control network, which itself is already loop pipelining. In most scenarios, this then leads to a deadlock due to insufficient buffering inside the loop, due to having to accomodate multiple invocations + loop pipelining, all at once.

The solution to this is a new structure for loop entry control. Instead of a single control merge to allow for control entry to the loop, we now have a combination of a mux + a loop "priming" register. The priming register drives the mux, and the mux selects from either external control or internal, loop control. By doing so, we essentially guard loop control to be exclusively allowed for that inside of the loop, or an external loop activation. A similar mux structure is used for the inputs to the loop header; block data input muxes are split in two, containing inputs from external loop predecessors and internal loop predecessors, and a mux - driven by the loop priming register - selects between either of these, based on where control originated from.

The loop priming register is driven by the loop exit condition. Thus, when the loop exits, the priming mux is "re-primed" allowing for control to again enter from an external activation.

Related changes:
- Merge op "dataflow conversion check" has been relaxed to now not require that all merge-like ops have an operand from all predecessor blocks. This will not be the case for the externalCtrlMerge/loopCtrlMerge.
- Allow single-input muxes, but canonicalize them away. This simplifies lowering (removes a special case), and is more easily taken care of by a canonicalization pattern.
2022-02-01 10:02:05 +01:00
Morten Borup Petersen 6515ddcb70
Revert "[Handshake] Allow simple merges in canonical form (#2430)" (#2455)
This reverts commit 8e44671.

The problem which I thought this commit (partially) solved is actually solved by #2444. In light of that, this commit is technically a regression and should be reverted.
2022-01-13 11:16:53 +01:00
Morten Borup Petersen 185b9c6d85
[Handshake] Support buffer initialization (#2436)
This commit adds support for buffer initialization. A list of integer values may be provided to sequential buffers, which will be made the reset values of the buffer registers when lowering to hardware.
2022-01-11 19:58:41 +01:00
Morten Borup Petersen 8e4467132c
[Handshake] Allow simple merges in canonical form (#2430)
In trying to get function pipelining to work, it finally seems like we've found the issue for why this hasn't been working. If we keep simple merges, and then add buffers to their outputs, function pipelining looks to be working.
This commit allows simple merges in canonical handshake IR, but keeps the option of removing them through a separate pass. After buffer insertion, the merges will be redundant, but we must keep them (at least for now) to guide buffer insertion.
2022-01-07 18:59:22 +01:00
Morten Borup Petersen 7406aadb1b
[Handshake] Canonicalize away sunk buffers (#2431) 2022-01-07 17:14:06 +01:00
Morten Borup Petersen 811fa5fd28
[Handshake] Always add buffers to unbuffered channels in bufferAllStrategy (#2418)
Due to the previous implementation of this function being based on a graph traversal which stopped at buffer ops, running bufferAllStrategy did not actually "buffer all" unbuffered channels, if some buffers already existed.

This commit simplifies bufferAllStrategy to do what is promised.
2022-01-05 13:46:28 +01:00
Morten Borup Petersen 1e10bea5ee [Handshake] add constant operation verifier 2021-12-17 16:06:37 +01:00