- Loops with 0 iterations always branch back to the parent.
- Loops with 1 iteration always branch into the loop, then immediately
back to the parent.
This change improves the quality of data flow analyses (e.g., dead code
analysis). It is also in preparation of adding a generic region inlining
canonicalization pattern for `RegionBranchOpInterface` ops (#176641).
---------
Co-authored-by: Jakub Kuderski <jakub@nod-labs.com>
`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.
Dead code analysis crashed because a symbol that is called/used didn't appear in the symbol
table.
This patch fixes this by adding a nullptr check after symbol table lookup.
Fix for a crash reported in #64975.
The crash occurs in the cast located
[here](ece5dd101c/mlir/lib/Analysis/DataFlow/DeadCodeAnalysis.cpp (L262))
because `llvm.unreachable` doesn't implement
`RegionBranchTerminatorOpInterface`.
The crash is caused by `DeadCodeAnalysis` assuming that
`isa<RegionBranchOpInterface>(op->getParentOp())` implies
`isa<RegionBranchTerminatorOpInterface>(op)` in
`DeadCodeAnalysis::visit()`.
This patch tried to fix this by enabling the analysis to proceed
regardless of whether `op` is a `RegionBranchTerminatorOpInterface`.
The PredecessorState in dead code analysis does not register
zero-operand returns as predecessors of their corresponding call ops.
This causes bugs with dense dataflow analyses that use dead code
analysis to query for the predecessors of CallOpInterfaces.
This was reasonable for sparse analyses, but isn't for dense ones.
This is generated by running
```
sed --in-place 's/[[:space:]]\+$//' mlir/**/*.td
sed --in-place 's/[[:space:]]\+$//' mlir/**/*.mlir
```
Reviewed By: rriddle, dcaballe
Differential Revision: https://reviews.llvm.org/D138866
This patch implements the analysis state classes needed for sparse data-flow analysis and implements a dead-code analysis using those states to determine liveness of blocks, control-flow edges, region predecessors, and function callsites.
Depends on D126751
Reviewed By: rriddle, phisiart
Differential Revision: https://reviews.llvm.org/D127064