Handshake FuncOp creation

Hi, everybody! I’ve come up with an idea of my custom dialect. Say, I have something like this:

mydialerct.module @name inputs(...) outputs(...)
  mydialect.pull %input // pull something out of the input channels
  ops // some other ops of upstream dialects
  mydialect.push (%something_to_push) %output // push something out to the output channels

What I want to do is to wrap all these ops inbetween pulles and pushes into a func.func and insert it at the top of the module. Instead these ops will become a mydialect.instace, which will later be lowered into hw.instance. With this approach I could easily use the existing passes to lower this new FuncOp into the core dialect of CIRCT, so I could only focus on the lowering of ops in mydialect.

But here comes the problem: In a design, it’s apparently that there won’t be only one mydialerct.module, so with this method I would have multiple func.func inserted at the top. These FuncOps can be lowered into handshake.func ops with no other efforts. But when trying to lower handshake to hw, the pass will report an error saying:

error: 'builtin.module' op multiple candidate top-level modules detected (...). Please remove one of these from the source program.

I know that if I create one handshake.func and call al the others in it, the problem is solved, because the pass will consider this func as the top one. But in my design, there is another custom op having the top function semantics, which won’t be lowered into handshake but directly into hw.

To solve this problem, I firstly thought that I could print all these new created func/func into seperate files and replace them with a hw.module.extern. But this method would require user to manually use hlstool to generate the hw modules.

So how could I manage this? And why exactly we need this check, since we can set up a top in vendors’ tool later?

Wrt. the error you’re experiencing, it’s coming from here. This code is artificially limited to only accepting one top-level module, but there isn’t a strict need for that. The only thing required by HandshakeToHW is that conversion occurs in post-order wrt. the instance graph.

If you’d like to look into fixing this issue, i’d recommend ditching the whole resolveInstanceGraph in favor of using a proper InstanceGraph.
Adding support for using InstanceGraph for handshake operations should be really simple - just take a look at InstanceGraphInterface.td and e.g. some of the operations that already implement the interface, and use an InstanceGraph.

Finally, note that I’m deprecating HandshakeToHW in favor of HandshakeToDC. You might already now be able to go successfully through HandshakeToDC, DCToHW - if not, feel free to raise an issue on the CIRCT repo. HandshakeToDC doesn’t have the same restriction wrt. top levels as HandshakeToHW.