[MLIR][Transforms] `control-flow-sink` produces invalid IR by moving an affine subscript's definition into a region
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
Affine validity is positional: whether an index value may be used as a dimension or symbol depends in part on where its definition and use occur. `--control-flow-sink` can move a definition into a conditionally executed region without preserving that property, turning a valid `affine.load` into invalid IR.
`control-flow-sink` currently admits an operation for sinking when it is memory-effect-free. In this example, `%n` is initially valid because it is defined at the top level of the enclosing `AffineScope`. After `index.remu` is sunk into the `scf.if`, that rule no longer applies. For this value, the relevant producer-based affine validity rule would require the defining operation to be `Pure`, but `index.remu` is `NoMemoryEffect` and not `Pure`. Thus it satisfies the sinking pass's condition, but moving it removes the property that made its result a valid affine dimension operand.
## Reproducer
### small.mlir
```mlir
func.func @f(%m: memref<8xi32>, %arg0: index, %cond: i1) -> i32 {
%c8 = index.constant 8
%n = index.remu %arg0, %c8
%zero = arith.constant 0 : i32
%r = scf.if %cond -> (i32) {
%v = affine.load %m[%n] : memref<8xi32>
scf.yield %v : i32
} else {
scf.yield %zero : i32
}
return %r : i32
}
```
### To reproduce:
```bash
$ mlir-opt small.mlir -o /dev/null
(input parses and verifies)
$ mlir-opt small.mlir --control-flow-sink -o /dev/null
small.mlir:8:10: error: 'affine.load' op operand cannot be used as a dimension id
%v = affine.load %m[%n] : memref<8xi32>
^
small.mlir:8:10: note: see current operation: %4 = "affine.load"(%arg0, %3) <{map = affine_map<(d0) -> (d0)>}> : (memref<8xi32>, index) -> i32
```
The pass sinks the computation of `%n` into the `scf.if`:
```bash
$ mlir-opt small.mlir --control-flow-sink --verify-each=false -o -
```
```mlir
%0 = "scf.if"(%arg2) ({
%2 = "index.constant"() <{value = 8 : index}> : () -> index
%3 = "index.remu"(%arg1, %2) : (index, index) -> index
%4 = "affine.load"(%arg0, %3) <{map = #map}> : (memref<8xi32>, index) -> i32
...
```
### Actual Output:
```
error: 'affine.load' op operand cannot be used as a dimension id
```
### Expected Output:
```
(the pass either sinks legally or declines; the module still verifies)
```
Contributor guide
Research direction
Start by running the issue's small.mlir reproducer with mlir-opt, both with and without --control-flow-sink. Locate the control-flow-sink pass and inspect its memory-effect-free sinking check alongside the affine validity rule described here. Done means the pass either sinks the computation legally or declines, and the module still verifies.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100