Skip to content

Allowing for nested ref cell instantiation #2079

Open
@nathanielnrn

Description

It feels like it could be useful to allow for the passing in of cells that contain refs 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 implementations.

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?

Metadata

Assignees

No one assigned

    Labels

    C: CalyxExtension or change to the Calyx ILS: Discussion neededIssues blocked on discussion

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions