How should non-control-flow region-bearing ops be used with by dataflow analyses?

I expect the behavior you describe to already be the default, is it not? The main caveat is, similarly to the rest of MLIR, is that the parent operation must be handling the terminators rather than doing something special for the terminator itself.

For the affine.for example, it should happen in the handling of the affine.for itself which does have results. Normally it should implement RegionBranchOpInterface, triggering this logic: llvm-project/mlir/lib/Analysis/DataFlow/SparseAnalysis.cpp at 6181f4f89d022ebf33ed8a449655347eb1b9b6c0 · llvm/llvm-project · GitHub. This interface describes how data flows between terminator operands and parent results, or arguments of another region if the control flows there.

If you have an operation that doesn’t have control flow expressible via that interface, you should be able to propagate the lattices when handling the region-containing operation itself, including the connection between operation operands/results and region arguments/terminator operands. Once you update the lattices for region arguments/terminator operands and trigger propagation (propagateIfChanged, this not being automatic is a frequently hit problem), I’d expect the operations from the region to be added to the processing queue. My team has only done this for memory-related lattices on linalg.generic, so we didn’t need to enter the body, double-check that it works.

1 Like