Thanks to everyone who could make my talk on Calyx today. Relevant links:
- Talk recording, password: ^v3aP1yt
- Slides linked in meeting doc.
Next Steps
I apologize for the lack of reference links. Discourse limits new user posts to 2 links.
The document references the source code documentation. When you see something like calyx::passes::Papercut
, you can navigate to it through that link by clicking passes
> Papercut
.
While the design is fresh in everyone’s mind, I also want to get started on steps to integrate Calyx into the CIRCT ecosystem. A quick pitch for why we should integrate Calyx:
- Calyx already has a frontend for Dahlia which is an imperative language. This means Calyx (probably) already supports enough things to enable compilation from NPComp.
- Calyx supports mixed latency-insensitive & latency-sensitive compilation. This has the potential to inform the design of StaticLogic and Handshake.
- Calyx already lowers to synthesizable RTL and is relatively well tested.
- Calyx implements a bunch of useful optimizations (
calyx::passes
) and analyses (calyx::analysis
). - Calyx has a systolic arrays frontend. This might not have any short tem importance beyond demonstrating that we can represent a variety of architectures in Calyx.
CIRCT-Calyx
V1
The fastest route to a useful MVP would be enabling generation of Calyx from CIRCT. This can either be done by defining the Calyx AST as a dialect, or by directly exposing Calyx’s IR builder (calyx::ir::Builder
).
Once CIRCT can emit Calyx code, the Calyx compiler can take it all the way to RTL.
V2
A followup PR can work on implementing the lowering step from purely structural Calyx (no groups or control) down to the RTL dialect. This will enable Calyx to feed code back into the tools below it.
V3
Port lowering passes to CIRCT. This would enable CIRCT-Calyx to go all the way to RTL without leaving CIRCT. The core lowering pass (calyx::ir::TopDownCompileControl
) is pretty short and the tested using the existing frontends.
A Calyx Dialect
Calyx programs are structured as components, each of of which contains cells, wires, and control. The interesting representation choices are for groups (contained within wires) and the control sub-language.
Groups
Groups are Calyx’s main form of structural abstraction. They give a name to a set of assignments which can then be used by the control sub-language to define a schedule:
group incr_count {
reg.in = add.out;
add.left = reg.out;
add.right = 1'd1;
reg.write_en = 1'd1;
incr_count[done] = reg.done;
}
At this point, I’m not quite sure what MLIR concept should be used to represent groups. Graph regions are a tempting choice but I don’t fully understand what the trade-off space is here.
@clattner had some thoughts about groups relating to basic blocks. Maybe we can flesh this out in more detail here with examples.
Control Sub-language
The control language is used to define the execution schedule for a group. Currently, it has the following constructs (cn
are control programs,):
-
seq { c1; c2; c3 ... }
: Execute in sequence. Done when the last control statement is done. -
par { c1; c2; c3 ... }
: Execute all in parallel. Done when all control statements have executed once. -
if <port> with <group> { c1 } else { c2 }
: After executinggroup
, use the value onport
to either runc1
orc2
. -
while <port> with <group> { c1 }
: After executinggroup
, use the value onport
to either runc1
or exit loop. -
invoke <cell>(in1 = p1, in2 = p2)(out1 = p3, out = p4)
: “Call”cell
with input-output port mapping and return when thedone
signal oncell
is high.
One consideration for future Calyx development: We’d like the control language to be easily extensible so that we can add more operations. One idea we’ve been playing with is “level-2” operations which are operations that can be represented using other, more primitive operators. pipeline
is an example of such an operation. A pipeline
is “just”:
while <ready> {
par {
if <ready> { s0 };
if s0.valid { s1 };
if s1.valid { s2 };
}
}
The additional structure of a pipeline
operator let’s us implement specific optimizations. Once lowered, the rest of the Calyx compiler can use all of its other optimizations.
Go/done interface
The go
/done
interface I showcased in the talk is pervasive: For example, each Calyx component gets additional ports to represent the go
/done
signals (this also makes them invoke
-able).
@stephenneuendorffer and other mentioned that this interface can be limiting (and I agree). However, for an MVP, I want to understand if we can’t build upon this interface in the future. If there is possibility for extension to support more paradigms, I’d propose merging this interface first and working on extensions in the future.
More Information on Calyx
We’ve attempted to document a lot of the source code in the Calyx compiler. Plus, we have documentation on getting started:
https://capra.cs.cornell.edu/calyx/
Finally, if you’re looking for examples of Calyx code, I’d recommend the test suite in the repository root (we use expect tests and have checked in the golden files).
Getting Involved
I work on graduate student hours which means I often get submerged with deadlines. I’d love to get other people involved. I can see a few places where people can help:
- Helping with the design of the Calyx dialect.
- Building frontends for Calyx
- Playing with the compiler and breaking it in fun ways (if you do, please file an issue!)