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

Instance bundles and systemverilog generate labels #367

Open
UnsignedByte opened this issue Oct 16, 2023 · 3 comments
Open

Instance bundles and systemverilog generate labels #367

UnsignedByte opened this issue Oct 16, 2023 · 3 comments
Labels
C: language Component: the Filament language S: discussion needed topic needs discussion

Comments

@UnsignedByte
Copy link
Collaborator

One of the current limitations of the filament language quite severly limits optimization of pipelining. SayI have a component that requires me to instantiate N registers, which I will reuse such that

  1. Each register holds input for a different amount of time
  2. The same register may have different (non-overlapping) behavior in different stages.

This is currently directly applicable to the PEASE FFT, which needs to take synchronized input and stagger it so that the combinational butterflies can iterate through chunks of registers and perform combinational logic on the data, then passing it back to the same register. Between stages all registers hold their data for the same number of cycles, and at the end each register needs to re-synchronize their outputs.

Possible Solutions

Instance Bundles

Regs[N] := for<i> new Register[i];

invoke := Regs{0}<'G>(in);

This is probably the simplest and easiest to understand implementation.

Loop Labeling

This is a weird idea I had thinking about this issue in the middle of the night, but I what if we consider labeling for loops? For example, we can do

label: for i in 0..N {
   Reg := new Register[i];
   bundle b[N] = ['G, 'G+1] W;
}

invoke := label{0}::Reg<'G>(label{1}::b{2});

Typechecking this should be as simple as plugging in the expression in {} for i, just like we do bundle typechecking now. This is an odd idea but with some syntax highlighting it should allow us to eliminate bundles and implement all forms of "array" structures at once. For example, if we use let port syntax or let param syntax we can do the following:

label: for i in 0..N {
  let param = i*2;
  let port ['G+param, 'G+param+1] W;
}

reg := new Delay[W]<'G+label{0}::param>(label{1}::port);

and we can even use nested for loops to automatically support n-dimensional arrays. Therefore, an n-d bundle can be desugared as follows:

bundle b[A, B]: for<i, j> ['G + i*j, 'G + i*j+1] i;

out{0..B} = b{A-1}{0..B};
out{B..B+A} = b{0..A}{B-1};
// becomes
label1: for i in 0..A {
    label2: for j in 0..B {
       let port ['G + i*j, 'G+ i*j+1] i;
    }
}

out{0..B} = label1{A-1}::label2{0..B}::port;
out{0..B} = label1{0..A}::label2{B-1}::port;

The syntax could definitely be discussed but this is just an idea that seemed very interesting to me.

@UnsignedByte UnsignedByte added C: language Component: the Filament language S: needs triage Status: Needs some more thinking before being actionable labels Oct 16, 2023
@rachitnigam
Copy link
Member

rachitnigam commented Oct 16, 2023

This seems interesting but I don't quite yet understand the example you've used to motivate the problem. Can you either draw out the pipeline to show how exactly the registers are being reused or discuss in more details?

Given this, if I'm understanding this correctly, the TLDR is that you need some generative way to define N registers and then use them in different loops. One very terrible way to do this is to define M bundles to "forward-declare" the uses of the register:

bundle I0[N]: ...; // the first set of uses
bundle O0[N]: ...; 
bundle I1[N]: ...; // The second set of uses
bundle O1[N]: ...;

// Instantiate the registers 
for i in 0..N {
  R := new Register[32];
  // First use
  r0 := R<'G, 'G+4>(I0{i});
  O0{i} = r0.out;
  // Second use
  r1 := R<'G+4, 'G+10>(I1{i})
  O1 = r1.out;
}

// First use of the register values
for i in 0..N {
  p0 := new Producer<'G>(in);
  I0{i} = p0.out;
  c0 := new Consumer<'G + 4>(O0{i})
}

// Second use of register values
for i in 0..N {
  p1 := new Producer<'G>(in);
  I1{i} = p1.out;
  c1 := new Consumer<'G + 10>(O1{i})
}

In general, I think bundles should be able to solve these generative problems but there is a high-overhead in modeling them like this. OTOH, there are particular challenges in proving resource reuse safe and we haven't implement the right checks yet (#76).

@rachitnigam rachitnigam added S: discussion needed topic needs discussion and removed S: needs triage Status: Needs some more thinking before being actionable labels Oct 16, 2023
@UnsignedByte
Copy link
Collaborator Author

Oh my god this isn't an approach I had considered at all... What a solution! I'll definitely try it out, thanks! I think the labeling idea might still have some worth discussing though at least in the future so I'll hold off on closing this for now.

@rachitnigam
Copy link
Member

Yeah, I think framing this as "instance bundles" is not a bad idea at all and perhaps can be a syntactic feature (#138) but we need to be careful about encoding it. You can imagine a source-to-source transformation that takes all those Reg{0} and allocates the O and I bundles but you'd need some syntax to distinguish which particular Reg{0} invoke you're talking about.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C: language Component: the Filament language S: discussion needed topic needs discussion
Projects
None yet
Development

No branches or pull requests

2 participants