Description
It feels like it could be useful to allow for the passing in of cells that contain ref
s to other components that also take in ref
cells. Currently, there isn't a way to express this in the language. I imagine this will be even more powerful once subtyping #2015 is introduced.
As a motivating example we can imagine a binary_op
component that takes in a reference to some op, which itself takes in a reference to an implementation of an op. (To actually be useful this would require subtyping to allow to pass in all kinds of ops, for now we can assume this is a multiply.
I can imagine a case where during one invocation of op
we want to use a fast multiplier, and during another invocation we want to use an efficient multiplier. This could be expressed as different implementation
s.
component bin_op () -> (){
cells{
ref op = multiplier();
}
//...
}
component multiplier () -> (){
cells{
ref impl = implementation();
}
//...
}
component implementation () -> (){
//...
}
comp main () -> () {
cells{
my_impl = implementation();
my_multiplier = multiplier();
my_op = my_op();
}
control{
invoke my_multiplier[impl = my_impl]()(); //this attaches my_impl cell to ref cell impl
invoke my_op[op = my_multiplier]()(); //this seems like it would have an "empty" impl?
}
}
Note the last line passes in my_multiplier
into an invocation of my_op
, but my_multiplier
doesn't have any implementation
cell hooked up to it.
A work around could be to create high-level components with all the cells needed by lower-level components. In the above case this would mean that the high-level bin_op
would need a reference to an implementation
:
component bin_op () -> (){
cells{
ref bin_op_impl = implementation(); //added cell
ref op = multiplier();
}
//...
control{
invoke op[impl = bin_op_impl]()();
}
}
We could then thread the concrete implementation
found in main
through a single invocation of my_op
comp main () -> () {
cells{
my_impl = implementation();
my_multiplier = multiplier();
my_op = my_op();
}
control{
//Not needed anymore: invoke my_multiplier[impl = my_impl]()();
invoke my_op[op = my_multiplier, bin_op_impl = my_impl]()(); //this seems like it would have an "empty" impl?
}
}
But this seems equivalent to manually hoisting up all lower level ref
cells and isn't very scalable.
An idea that came up for how to address this via @anshumanmohan
It may be useful to hook up ref
cells in the cells
block of a component. This would allow us to refer to "partially applied" cell instantiation within control blocks.
So going back to our initial example, we could change the cells
section of main as follows.
component bin_op () -> (){
cells{
ref op = multiplier();
}
//...
}
component multiplier () -> (){
cells{
ref impl = implementation();
}
//...
}
component implementation () -> (){
//...
}
comp main () -> () {
cells{
my_impl = implementation();
my_multiplier = multiplier[impl = my_impl](); //now we can refer to my_multiplier in the control block and know that it has some some implementation component passed in
my_op = my_op();
}
control{
//also not needed anymore: invoke my_multiplier[impl = my_impl]()();
invoke my_op[op = my_multiplier]()(); //this should be enough to perform an operation with a multiplier that uses `implementation`
}
}
I think this would allow for the threading of concrete cells through component hierarchies by only worrying about them in the single component they are referenced in? So the only place we'd have to keep track of/instantiate an implementation
cell would be in multiplier
, which is exactly where a ref
of implementation
is expected, and we wouldn't have to "hoist up" an implementation
cell into bin_op
.
This might ruin some assumptions about invocations/passing in cells? Right now the only way to pass in cells to references is via invokes
, and this would introduce such passing to cell declaration? It might be problematic w.r.t to the IR or the current passes, but hopefully this wouldn't be too big of a change. Maybe @calebmkim @sampsyo or @rachitnigam has thoughts about this aspect.
Perhaps this is worth talking about in the next Calyx meeting as well?