This has been in my backlog for months now and I finally have time to devote to it. I’d love to hear thoughts.
tdlr; Successor operands are overly restrictive, create lots of headaches, and should be removed.
Generalizing Successor Operands
The current modeling of branch successor operands is much too rigid, and makes lots of things quite awkward. They are modeled with passthrough PHI
Values that are required to exactly match the count and type of the argument list for the successor block. They are technically part of the operand list of an operation, but aren’t really controllable by the operation as they have a specific ordering/structure. They can’t be treated like
arguments(in the ODS sense) to the operation. Another major problem is that the current implementation enforces that an SSA value already be materialized, making certain classes of terminators difficult(hacky) to implement. These are terminators that want to produce values only on specific edges, think switch_enum in SIL or CallBr/Invoke in LLVM.
This simplified a lot of things in the early days of MLIR, back when there were Instructions/Statements/MLFuncs/etc., but is growing increasingly awkward in the present day infrastructure. When I originally added support for terminator operations in those days, we didn’t have things like
interfaces to allow for opaquely querying information about an operation. Now that we do, there is little incentive to keep the current structure and I argue that it is actively detrimental. As such, I propose that we detach how operands to a successor are specified and leave it up to the specific terminator operations. We can then use an interface
BranchOpInterface to recover the API that the current infrastructure provides; e.g. erasing a successor operand, getting the operands to a specific successor, etc… This would essentially move successor operands in the current sense to just be normal operands to the operation.
I’ve gone ahead and uploaded a stack for review that showcases what this looks like, ending with https://reviews.llvm.org/D75318.
Some examples of hacky-logic because of the current state:
- There are two
ConversionPatternto handle the case of successor operands.
- Note that if you have a terminator with a variadic number of successors(e.g. switch), you have to implement both methods!
- When building an operation the successors have to be added last, and the operands list needs to have null values between the success operand lists.