This is an archive of the discontinued LLVM Phabricator instance.

[mlir][NFC] Make `ReturnLike` trait imply `RegionBranchTerminatorOpInterface`
ClosedPublic

Authored by zero9178 on Aug 8 2023, 8:10 AM.

Details

Summary

This implication was already done de-facto and there were plenty of users and wrapper functions specifically used to handle the "return-like or RegionBranchTerminatorOpInterface" case. These simply existed due to up until recently missing features in ODS.

With the new capabilities of traits, we can make ReturnLike imply RegionBranchTerminatorOpInterface and auto generate proper definitions for its methods.
Various occurrences and wrapper methods used for isa<RegionBranchTerminatorOpInterface>() || hasTrait<ReturnLike>() have all been removed.

Diff Detail

Event Timeline

zero9178 created this revision.Aug 8 2023, 8:10 AM
Herald added a project: Restricted Project. · View Herald Transcript
zero9178 requested review of this revision.Aug 8 2023, 8:10 AM
jpienaar accepted this revision.Aug 8 2023, 12:29 PM

I like all the red :-)

This revision is now accepted and ready to land.Aug 8 2023, 12:29 PM
olegshyshkov added inline comments.
mlir/include/mlir/Interfaces/ControlFlowInterfaces.td
281–286

This commit is causing errors in our codebase and I'm not sure how to best approach it. We have ReturnLike ops with custom implementations of getMutableSuccessorOperands. https://github.com/tensorflow/tensorflow/blob/675d73c284396a100555300fe2eab5d02f4bd847/tensorflow/core/ir/ops.cc#L1299.

Is it intentional that now there is not way to define custom getMutableSuccessorOperands and add ReturnLike trait at the same time? Or am I missing something and there is a workaround?

zero9178 marked an inline comment as done.Aug 9 2023, 9:17 AM
zero9178 added inline comments.
mlir/include/mlir/Interfaces/ControlFlowInterfaces.td
281–286

Hi!

Is it intentional that now there is not way to define custom getMutableSuccessorOperands and add ReturnLike trait at the same > time?

Admittedly no, it was somewhat of a misconception of mine that ReturnLike would only be used for ops that simpyl forward all its operands like the ReturnLike ops upstream.

Or am I missing something and there is a workaround?

I would first try to reevaluate whether you need ReturnLike on the op. At least the upstream ops that have the trait essentially use it as a default implementation for RegionBranchTerminatorOpInterface. Upstream ops like scf.condition, which seems similar to the op you linked, are not marked ReturnLike e.g..

If you do end up really requiring it, a workaround would be to instead use NativeOpTrait<"ReturnLike"> instead of just ReturnLike in the trait list of the ops.
Do tell if there is something fundamentally wrong with this patch that needs upstream rather than downstream changes.

Is it intentional that operations like the upstream func.return now implement RegionBranchTerminatorOpInterface but func.func does not (and cannot, at least in its current form) implement the RegionBranchOpInterface? As far as I understand, the parent of the op implementing the RegionBranchTerminatorOpInterface has to implement RegionBranchOpInterface which is also assumed in the default implementation of the getSuccessorRegions method.
Should the RegionBranchOpInterface be modified such that it can be implemented by func.func (or is it already possible and I'm misunderstanding something?) or should ReturnLike be dropped from func.return and NativeOpTrait<"ReturnLike"> or something else (e.g., some new trait specific to FunctionOpInterface) be used instead to determine somewhat generically in a pass that a terminator has function-return-like properties?

zero9178 marked an inline comment as done.Aug 17 2023, 5:55 AM

Is it intentional that operations like the upstream func.return now implement RegionBranchTerminatorOpInterface but func.func does not (and cannot, at least in its current form) implement the RegionBranchOpInterface? As far as I understand, the parent of the op implementing the RegionBranchTerminatorOpInterface has to implement RegionBranchOpInterface which is also assumed in the default implementation of the getSuccessorRegions method.
Should the RegionBranchOpInterface be modified such that it can be implemented by func.func (or is it already possible and I'm misunderstanding something?) or should ReturnLike be dropped from func.return and NativeOpTrait<"ReturnLike"> or something else (e.g., some new trait specific to FunctionOpInterface) be used instead to determine somewhat generically in a pass that a terminator has function-return-like properties?

With the concerns you and @olegshyshkov raised, it sounds to me like there should be some kind of split of what is currently "ReturnLike", one being RegionBranchReturnLike and the other possibly CallableReturnLike (to mirror CallableOpInterface). The latter can even live in the TableGen file defining CallableOpInterface while the former remains in ControlFlowInterfaces.
Would that make sense to you?

The documentation of the ReturnLike trait is not very descriptive IMO and does not properly describe what it entails. Just doing a grep through upstream shows it essentially being used as return for CallableOpInterfaces (the uses of it as region branch terminators having been removed in this patch).
I suppose this might be worth an RFC.

zero9178 added a comment.EditedAug 17 2023, 6:01 AM

Is it intentional that operations like the upstream func.return now implement RegionBranchTerminatorOpInterface but func.func does not (and cannot, at least in its current form) implement the RegionBranchOpInterface? As far as I understand, the parent of the op implementing the RegionBranchTerminatorOpInterface has to implement RegionBranchOpInterface which is also assumed in the default implementation of the getSuccessorRegions method.
Should the RegionBranchOpInterface be modified such that it can be implemented by func.func (or is it already possible and I'm misunderstanding something?) or should ReturnLike be dropped from func.return and NativeOpTrait<"ReturnLike"> or something else (e.g., some new trait specific to FunctionOpInterface) be used instead to determine somewhat generically in a pass that a terminator has function-return-like properties?

To directly answer your questions. It was intentional, but I am not a big fan of it at all. The assumption was that one would never call the methods of RegionBranchTerminatorOpInterface if it wasn't nested inside a RegionBranchOpInterface. I believe that RegionBranchOpInterface is only supposed to be used for ops that can only ever directly execute their regions, as opposed to something like func.func or a dialect that has a "lambda" like nested-function op, where the region execution is deffered to a call op.
These ops should be implementing the CallableOpInterface instead.