-
Notifications
You must be signed in to change notification settings - Fork 52
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
The four hard problems in FuTIL: groups, holes, visible signals, and time #270
Comments
Let's explore the idea of requiring every group to commit it's results (and thus banning combinational groups). Imposing this requirement allows groups to always be composable, but also puts the burden of synthesizability on the frontend because they have to make sure that every group generated is small enough. To mitigate this, we need to be able to remove registers and merge groups. Consider the following program:
We want to merge the groups
To be able to do this transformation, we need to prove a few things about the register
If we have liveness information about registers alongside being able to prove how a register effects the internal control flow of a group then we can perform this optimization. I think there are two questions from here to answer:
|
There is nothing to be done for this issue. The intellectual heritage of this discussion was:
At the time of writing, there are ongoing discussions on interfaces that more precisely track the visibility of signals. The origins of that discussion can be traced back to this issue. |
A brain-dump of various thoughts on groups, holes, and visible signals. I'm not yet sure how to fix these problems. Any solution of the form "Replace groups with components" needs to address some of these problems.
Groups
Motivation for Groups
The primary motivation for groups was to have an encapsulation for assignments that would compose nicely. Due to this, groups have the following properties:
Group != Components
From their conception, groups have been considered separate from components. The specified distinction between the two is that a component has a control program and owns cells while a group does not.
I'm not convinced that this is distinction is meaningful:
Same expressive power
Consider this group:
vs the component
(Instead of owning an "x" and "y" cell, the component sends signals to another component)
Group enables are already "function calls"
We've thrown around the idea for an "invoke" control operator for invoking complex components. However, a group enable is already an invoke that takes no arguments. The reason groups need a "calling convention" in the first place is because they already approximating a component.
Compilation Holes
Compilation holes are a mechanism for FuTIL groups to interact with the control program.
Motivation for Holes
The primary motivation for holes was the desire to aggressively inline guards of enables in FuTIL programs and eliminate any extra registers.
By and large, our implementation of holes fails to do this. This is not because we've designed holes badly but because we didn't correctly think about combinational cycles when designing the interface.
I posit that every hole can be replaced by a named wire with zero overhead.
Control-Structure Interface
We often throw around this statement:
This is only true because of the current uses of holes. The various other proposals to add "input" and "output" holes tells the real story: holes are just ports. This is especially true because they cannot do anything that ports can't already.
Visible signals
Groups provide no guarantees about what signals are visible after they execute. #207 and various other discussions about combinational groups seek to make some signals visible conditioned on
done
signals.This break groups' fundamental encapsulation guarantee. By making all signals invisible, groups allows the compiler to ruthlessly change anything and everything about the group. However, if a signal is visible across a group boundary, the compiler needs to be careful.
For example, consider:
add0
and guarantees thatadd0.out
is valid for the one cycle whenA[done]
is high.add0.out
in its body because it knows that it will be valid.In this case, if a compiler wants to change
add0.out
toadd1.out
, it has to track all the uses ofadd0.out
that come fromA
(but not any other group becauseadd0
can be used by multiple groups) and change them. This amounts to alias analysis.Time
Hardware design is fundamentally different from software design because it involves an explicit notion of time. FuTIL's complexity on the edges come from this problem
Two Notions of Time
There are two kinds of hardware circuits: combinational and sequential. This means that for any signal, we have to answer the question: When is this signal used? Now (in the current cycle) or later (in a future cycle).
These two are the only interesting possibilities to me because once you register a signal, it becomes easier to use it in the future.
The question at the heart of all discussions about signal visibility, operation chaining optimizations, etc., are about the nature of time in FuTIL. While groups, components, and control programs all operate with the assumption that there are time steps,
there are privileged primitives like
add
that take no time to execute. This property of the primitives leaks into everything else (some groups take no time) and breaks various assumptions.So the question is why have this privilege? Or rather, is there a way for us to always insert registers and use state and opportunistically eliminate it when we can?
The text was updated successfully, but these errors were encountered: