-
Notifications
You must be signed in to change notification settings - Fork 15.9k
[mlir][Interfaces][NFC] Document that RegionBranchTerminatorOpInterface is mandatory
#174978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[mlir][Interfaces][NFC] Document that RegionBranchTerminatorOpInterface is mandatory
#174978
Conversation
|
@llvm/pr-subscribers-mlir Author: Matthias Springer (matthias-springer) ChangesDocument that implementing the This commit does not change the op/interface semantics. It just puts in writing an assumption that is made throughout the code base. For example:
Full diff: https://github.com/llvm/llvm-project/pull/174978.diff 1 Files Affected:
diff --git a/mlir/include/mlir/Interfaces/ControlFlowInterfaces.td b/mlir/include/mlir/Interfaces/ControlFlowInterfaces.td
index ff99e220c179f..74c7841d52b3f 100644
--- a/mlir/include/mlir/Interfaces/ControlFlowInterfaces.td
+++ b/mlir/include/mlir/Interfaces/ControlFlowInterfaces.td
@@ -127,7 +127,8 @@ def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
A "region branch point" indicates a point from which a branch originates. It
can indicate:
- 1. A terminator in any of the immediately nested region of this op.
+ 1. A `RegionBranchTerminatorOpInterface` terminator in any of the
+ immediately nested region of this op.
2. `RegionBranchPoint::parent()`: the branch originates from outside of the
op, i.e., when first executing this op.
@@ -147,6 +148,15 @@ def RegionBranchOpInterface : OpInterface<"RegionBranchOpInterface"> {
results must have the same type. `areTypesCompatible` can be implemented to
allow non-equal types.
+ Note: This interface works in conjunction with
+ `RegionBranchTerminatorOpInterface`. All immediately nested block
+ terminators that model branching between regions must implement the
+ `RegionBranchTerminatorOpInterface`. Otherwise, analyses/transformations
+ may miss control flow edges and produce incorrect results. Not every block
+ terminator is necessarily a region branch terminator: e.g., in the presence
+ of unstructured control flow, a block terminator could indicate a branch to
+ a different block within the same region.
+
Example:
```
@@ -379,7 +389,8 @@ def RegionBranchTerminatorOpInterface :
let description = [{
This interface provides information for branching terminator operations
in the presence of a parent `RegionBranchOpInterface` implementation. It
- specifies which operands are passed to which region successor.
+ acts as a marker for valid region branch points and specifies which
+ operands are passed to which region successor.
}];
let cppNamespace = "::mlir";
|
linuxlonelyeagle
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.please wait for the other reviewer.
|
I am thinking about whether this conclusion is correct: |
ff3af1d to
94c1209
Compare
|
Yes, that's correct. I added a note to the |
Thanks. |
94c1209 to
7787a1d
Compare
7787a1d to
8e04b6b
Compare
|
Rebased to |
…terminator (#174221) `scf.forall` does not completely implement the `RegionBranchOpInterface`: `scf.forall.in_parallel` does not implement the `RegionBranchTerminatorOpInterface`. Incomplete interface implementation is a problem for transformations that try to understand the control flow by querying the `RegionBranchOpInterface`. Detailed explanation of what is wrong with the current implementation. - There is exactly one region branch point: "parent". `in_parallel` is not a region branch point because it does not implement the `RegionBranchTerminatorOpInterface`. (Clarified in #174978.) - `ForallOp::getSuccessorRegions(parent)` returns one region successors: the region of the `scf.forall` op. - Since there is no region branch point in the region, there is no way to leave the region. This means: once you enter the region, you are stuck in it indefinitely. (It is unspecified what happens once you are in the region, but we can be sure that you cannot leave it.) This commit adds the `RegionBranchTerminatorOpInterface` (via `ReturnLike`) to `scf.forall.in_parallel` to indicate the after leaving the region, the control flow returns to the parent. (Note: Only block terminators in directly nested regions can be region branch terminators, so `in_parallel` is the only possible op. I.e., `parallel_insert_slice` cannot be a region branch terminator.) This commit also removes all successor operands / inputs from the implementation. The number of successor operands and successor inputs must match, but `scf.forall.in_parallel` has no operands. Therefore, the region must also have 0 successor inputs. Therefore, the `scf.forall` op must also have 0 successor operands. This commit also adds a missing control flow edge from "parent" to "parent": in case of 0 threads, the region is not entered. Depends on #174978.
…ace` is mandatory (llvm#174978) Document that implementing the `RegionBranchTerminatorOpInterface` is mandatory. Omitting this interface on a block terminator that models region branching may lead to invalid/incomplete analyses and transformations. This commit does not change the op/interface semantics. It just puts in writing an assumption that is made throughout the code base. For example: - It is baked into the API design of the `RegionBranchOpInterface`. You cannot query the region successors of block terminators that do not implement the `RegionBranchTerminatorOpInterface`: `RegionBranchOpInterface::getSuccessors()` takes a `RegionBranchPoint` parameter, and such region branch points can be constructed only from `RegionBranchTerminatorOpInterface` and not arbitrary `Operation *`. - Helper functions + default interface method implementations enumerate region branch points by looking for `RegionBranchTerminatorOpInterface` and ignoring other operations. E.g., `RegionBranchOpInterface::getAllRegionBranchPoints`, default implementation of `RegionBranchOpInterface::getSuccessorRegions(Region &)`, default implementation of `RegionBranchOpInterface::getPredecessorValues`. - Core analyses such as `DeadCodeAnalysis` look for `RegionBranchTerminatorOpInterface` and misbehave when the interface is not implemented. The analysis does not (and cannot) query region successors of a region branching terminator that does not implement the `RegionBranchTerminatorOpInterface`. In practice, this means that forgetting to implement the `RegionBranchTerminatorOpInterface` may incorrectly classify regions as dead. - Other analyses / transformations that look for and depend on the implementation of `RegionBranchTerminatorOpInterface`: `mlir::getControlFlowPredecessors`, `AbstractDenseBackwardDataFlowAnalysis`, ownership-based buffer deallocation pass.
…terminator (llvm#174221) `scf.forall` does not completely implement the `RegionBranchOpInterface`: `scf.forall.in_parallel` does not implement the `RegionBranchTerminatorOpInterface`. Incomplete interface implementation is a problem for transformations that try to understand the control flow by querying the `RegionBranchOpInterface`. Detailed explanation of what is wrong with the current implementation. - There is exactly one region branch point: "parent". `in_parallel` is not a region branch point because it does not implement the `RegionBranchTerminatorOpInterface`. (Clarified in llvm#174978.) - `ForallOp::getSuccessorRegions(parent)` returns one region successors: the region of the `scf.forall` op. - Since there is no region branch point in the region, there is no way to leave the region. This means: once you enter the region, you are stuck in it indefinitely. (It is unspecified what happens once you are in the region, but we can be sure that you cannot leave it.) This commit adds the `RegionBranchTerminatorOpInterface` (via `ReturnLike`) to `scf.forall.in_parallel` to indicate the after leaving the region, the control flow returns to the parent. (Note: Only block terminators in directly nested regions can be region branch terminators, so `in_parallel` is the only possible op. I.e., `parallel_insert_slice` cannot be a region branch terminator.) This commit also removes all successor operands / inputs from the implementation. The number of successor operands and successor inputs must match, but `scf.forall.in_parallel` has no operands. Therefore, the region must also have 0 successor inputs. Therefore, the `scf.forall` op must also have 0 successor operands. This commit also adds a missing control flow edge from "parent" to "parent": in case of 0 threads, the region is not entered. Depends on llvm#174978.
Document that implementing the
RegionBranchTerminatorOpInterfaceis mandatory. Omitting this interface on a block terminator that models region branching may lead to invalid/incomplete analyses and transformations.This commit does not change the op/interface semantics. It just puts in writing an assumption that is made throughout the code base. For example:
RegionBranchOpInterface. You cannot query the region successors of block terminators that do not implement theRegionBranchTerminatorOpInterface:RegionBranchOpInterface::getSuccessors()takes aRegionBranchPointparameter, and such region branch points can be constructed only fromRegionBranchTerminatorOpInterfaceand not arbitraryOperation *.RegionBranchTerminatorOpInterfaceand ignoring other operations. E.g.,RegionBranchOpInterface::getAllRegionBranchPoints, default implementation ofRegionBranchOpInterface::getSuccessorRegions(Region &), default implementation ofRegionBranchOpInterface::getPredecessorValues.DeadCodeAnalysislook forRegionBranchTerminatorOpInterfaceand misbehave when the interface is not implemented. The analysis does not (and cannot) query region successors of a region branching terminator that does not implement theRegionBranchTerminatorOpInterface. In practice, this means that forgetting to implement theRegionBranchTerminatorOpInterfacemay incorrectly classify regions as dead.RegionBranchTerminatorOpInterface:mlir::getControlFlowPredecessors,AbstractDenseBackwardDataFlowAnalysis, ownership-based buffer deallocation pass.