Replies: 4 comments 9 replies
-
One additional thought regarding the information attached to llvm::lambda: I think that it would be better to distinguish between "lambda" (the callable object) and "function def" (the thing that binds a callable object to a symbol/name + linkage). Otherwise, anonymous lambdas are a bit odd as they should be ephemeral objects without any specified linkage etc. It is only after deciding to turn them into "real" functions (instead of e.g. inlining them at all use sites) that they even need a name, linkage etc. |
Beta Was this translation helpful? Give feedback.
-
I can see the desire to only specialize operations, as we currently specialize a subset of the nodes, which makes copying nodes require a virtual function that the implementer needs to remember to override. An alternative would be to make If I understand them correctly, classes like If it was somehow possible to use accessor functions defined on the operations, to easily work with the nodes holding those operations, it might no longer be that useful to use custom subclasses of I am still not entirely sure about the role of operations in the pipeline. As far as I can tell they also exist outside of RVSDG, in something called TAC, and in some sort of intermediate control flow graph. This makes it a bit unclear if operations are primarily a way of specializing RVSDG nodes, or if operations are more general than that, with the RVSDG nodes being designed around holding them temporarily. |
Beta Was this translation helpful? Give feedback.
-
I believe that I am at fault with the naming here.
Yes.
This is not true. The delta node is a structural node and contains a single region. Please see its constructor and how it invokes the structural_node constructor with argument 1 as last parameter. The delta node needs to stay a structural node as its subregion can contain other simple nodes.
I am fine with this as long as you do give me a way to access the individual inputs/outputs of a simple node. I do not want to write:
but rather (as it is right now):
In other words, please do not make me remember which operand is at which index, but give me concrete accessors to individual (groups) of inputs/outputs. Everything else simply becomes a mess of indices that is unreadable and requires intricate knowledge of the individual operations and their type signatures.
What about the hls::loop_nodes from the HLS dialect? I am okay with this, as long as you provide me a convenient (and intuitive way) to access the individual inputs/outputs/etc. of these specific nodes. I do not want to iterate through all the lambda subregion arguments and filter out myself which of those are the function arguments (and not the input arguments). Rather, I want accessors to them such that I only get these.
I agree with you. The plan in my head (so far) was to remove the operations for structural nodes altogether, as they do not really serve a purpose (as compared to operations for simple nodes). The semantics is already in the structural node.
I really appreciate that. Thanks a lot!
Makes sense, I can get behind this. |
Beta Was this translation helpful? Give feedback.
-
After trying this out on gamma, theta and lambda, I have a clearer picture and more specific proposal on API structure. Inputs & outputs: There really exist only two classes, namely "inputs / outputs to nodes" and "results / arguments" of regions. So, when code needs to handle an input or output of unknown kind, they should canonically proceed like this:
presently, there is a bit of a mixture of casting variously the output type or the node type, and I think this would benefit from being made regular and uniform throughout the code base. In principle one could also write convenience helpers to "flatten" the above into a single if-cascade again:
Routing things into and out of structural nodes as well as tracing paths through structural nodes: When routing a variable e.g. into a theta node, one needs to have 1. the input into the theta, 2. inside the theta region the pre-loop value, 3. inside a theta a way to assign a new post-loop value to it, and 4. get the loop exit value for later code. Currently, this is accomplished by
so providing this as a "uniform representation" to handle aspects of a specific loop var. Using this in the places where required also makes it clear that the code is presently handling a loop variable as a whole, and retains its context. Then, to add a loopvar:
returns the full thing. This actually satisfies >95% of the use cases where one presently needs to resolve "the other pieces of the loop variable, given just an input". For code stepping and tracing through loops, it should also handle similarly:
So there is a uniform way of handling this. |
Beta Was this translation helpful? Give feedback.
-
While working on generalizing the structural nodes (esp. lambda and gamma nodes), I noticed that the division of responsibilities between what is a "node" and what is an "operation" is not very clear. In my mind the difference should be:
This is mostly the case for everything that is of kind "simple_node" (which TBH I should have named "operation node" or similar), but is rather fuzzy for everything else.
The division among node types should roughly be:
This is today mostly enforced, except for delta::node which is structural but does not contain a region. It should be possible to turn it into simple_node, as delta::operation contains "almost everything", except for a few small bits.
I would like to proceed towards the following organization:
To this end I would like to start restructuring towards the above goals while implementig the generic lambda. The transformation will not be completed in a single PR, but I would like to see whether the direction makes sense before committig something that goes into a direction not agreed upon.
@phate @haved @sjalander
Beta Was this translation helpful? Give feedback.
All reactions