Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static Primitive Signatures #1601

Closed
calebmkim opened this issue Jul 14, 2023 · 3 comments
Closed

Static Primitive Signatures #1601

calebmkim opened this issue Jul 14, 2023 · 3 comments
Labels
C: Calyx Extension or change to the Calyx IL Calyx 2.0 Things that move us towards Calyx 2.0

Comments

@calebmkim
Copy link
Contributor

Problem

  • When we add the static keyword to a primitive, and the @static attribute to ports of primitives, what does this mean exactly?
  • How are we going to capture the difference in the behavior of pipelined_mult primitive and the std_mult_pipe primitive in their signatures?
  • What about primitives with multiple go ports that have different latencies (e.g., memories w/ different read/write latencies)?

Idea

One idea is the following:

  • Only mark primitive@go ports with the @static attribute, and don't attach the static keyword to primitives. So, for example, both pipelined_mult and std_mult_pipe will have their @go ports marked with the @static attribute. The difference in the signatures will be that pipelined_mult does not have a done port, whereas std_mult_pipe does, which lets us know the difference in behavior between the two primitives.

  • One thing I was thinking of, is do we want something in the signature in the primitives that tells us that a primitive is a pipelined primitive (i.e., it can take a new input every cycle, and that its output is available for exactly one cycle before you lose it). Hector literally has 3 "scheduling maners": dynamic, static, and pipeline. Do we want something similar for Calyx primitives, where as pipelined primitive is explicitly stated, i.e., we have a literally pipeline attribute that can be attached to ports? This just a thought and not that well thought out, but I decided to put it down.

@calebmkim calebmkim added C: Calyx Extension or change to the Calyx IL Calyx 2.0 Things that move us towards Calyx 2.0 labels Jul 14, 2023
@rachitnigam
Copy link
Contributor

Only mark primitive@go ports with the @static attribute, and don't attach the static keyword to primitives. So, for example, both pipelined_mult and std_mult_pipe will have their @go ports marked with the @static attribute.

I think this is why we decided to deprecate @static #1429; in the first case, we're using it to specify then latency of the computation. In the second, we're using it to define the calling convention for a component. I think these are orthogonal concerns and should be represented as such. For example, what does it mean for std_mult_pipe to be marked @static? If it has a specific latency, why does it ever need to use the @done port?

Put differently: If a component is statically scheduled (i.e., has a computation independent timing behavior), it should be turned into a static primitive and use the compiler to generate wrappers to be used in a dynamic context.

Hector literally has 3 "scheduling maners": dynamic, static, and pipeline

This is an intriguing question that often comes up. Pipelining is about resource reuse while the other two are about the calling convention of the interface. There are four possible interfaces: (dynamic, static) X (pipelined, unpipelined). The HECTOR interface seem to only capture three of those?

My gut reaction is that we don't really want to get into the business of specifying reuse properties in Calyx because then we'd have to think about the guarantees that we're providing when they mix together (HECTOR uses a stratified IR to work around this) but I think @sampsyo and @andrewb1999 should chime in on this as well.

@sampsyo
Copy link
Contributor

sampsyo commented Jul 17, 2023

I generally concur with this notion:

Put differently: If a component is statically scheduled (i.e., has a computation independent timing behavior), it should be turned into a static primitive and use the compiler to generate wrappers to be used in a dynamic context.

That is, in "Calyx v1," we had this philosophy: "Statically-timed hardware is a subset of dynamically-timed hardware. Some hardware is exclusively dynamically-timed; you use this with its go/done interface only. Some hardware is both statically-timed and dynamically-timed; you use this hardware either as in the previous sentence or by ignoring the done port and waiting the appropriate amount of time instead."

In "Calyx v2," we have changed this to instead be: "There are two calling conventions: static and dynamic. All hardware is either one or the other. If you want to use static hardware in a dynamic context, you first have to wrap it in a go/done interface."

Stuff like std_mult_pipe is a vestige of the Calyx v1 philosophy; now is the time to drag it into the future.

The clearest way to extend this philosophy to primitives is that they also get either duplicated or wrapped. That is, we have two choices, which are the same choices as for when we implement stuff in Calyx:

  1. There is one primitive, std_mult, and it uses the static keyword. If you want to use it in a dynamic context, you must wrap it first.
  2. There are two primitives, std_mult_static and std_mult_dyn. You pick the one you want based on your context.

I think option 1 is probably a little easier? Option 2 trends into "virtual operator" territory and would be useful if we ever think the implementations would be meaningfully different.

My gut reaction is that we don't really want to get into the business of specifying reuse properties in Calyx because then we'd have to think about the guarantees that we're providing when they mix together (HECTOR uses a stratified IR to work around this) but I think @sampsyo and @andrewb1999 should chime in on this as well.

Yeah, super interesting. I am inclined to agree that we do not yet have a use for knowing about pipelines in the calling convention. Someday, I can imagine needing to write a pass that has to know a component's II to do its job; I don't think we have that yet. It seems best to avoid this until we need it, maybe?

It is also possible that what we eventually want is full-blown Filament types for these interfaces…

@rachitnigam
Copy link
Contributor

Subsumed by #1725

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C: Calyx Extension or change to the Calyx IL Calyx 2.0 Things that move us towards Calyx 2.0
Projects
None yet
Development

No branches or pull requests

3 participants