[Mlir-commits] [mlir] [mlir][linalg] Fix Linalg runtime verification pass to handle tensors with dimensions of size 0 (PR #163791)
    llvmlistbot at llvm.org 
    llvmlistbot at llvm.org
       
    Mon Oct 20 11:22:36 PDT 2025
    
    
  
================
@@ -103,6 +103,11 @@ func.func @main() {
   // CHECK: unexpected negative result on dimension #0 of input/output operand #0
   func.call @reverse_from_3(%d5x) : (tensor<?xf32>) -> (tensor<?xf32>)
 
+  %c0x = arith.constant dense<1.0> : tensor<0xf32>
+  %d0x = tensor.cast %c0x : tensor<0xf32> to tensor<?xf32>
+  // CHECK-NOT: ERROR: Runtime op verification failed
+  func.call @fill_empty_1d(%d0x) : (tensor<?xf32>) -> (tensor<?xf32>)
----------------
Hanumanth04 wrote:
Thanks for looking into this PR :) I will try to clarify, so please let me know if this helps answer your questions.
**1. Why check startIndex/endIndex instead of just loop iteration count?**
I believe we do this because the loop iteration space is decoupled from the tensor access space because of indexing maps. We can't just verify the loop runs N times—we need to check for the actual min and max tensor indices accessed.
Probably the below example will help:
```mlir
linalg.generic {
  indexing_maps = [
    affine_map<(d0) -> (d0)>,      // Input: forward
    affine_map<(d0) -> (4 - d0)>   // Output: backward
  ],
  iterator_types = ["parallel"]
} ins(%input : tensor<5xf32>) outs(%output : tensor<5xf32>)
```
**Execution:**
- Loop variable d0: 0, 1, 2, 3, 4
- Input accesses: [0, 1, 2, 3, 4]
- Output accesses: [4, 3, 2, 1, 0]
So the verifier needs to check both output[4] (first access, d0=0) and output[0] (last access, d0=4) are within bounds.
This is why the code computes:
```cpp
min(startIndex, endIndex) = min(4, 0) = 0  // Lowest accessed index
max(startIndex, endIndex) = max(4, 0) = 4  // Highest accessed index
```
---
**2. Can loops run in reverse order?**
You're correct that the loop induction variable always increments (d0 = 0, 1, 2, ...). However, tensor accesses can be in reverse order due to the indexing map.
In the example above with `affine_map<(d0) -> (4 - d0)>`, as d0 goes 0→4, the tensor is accessed 4→3→2→1→0.
So the verifier needs to check both the highest index (4, from d0=0) and lowest index (0, from d0=4) are in bounds, which is why `min/max` are used to find the true access range regardless of direction.
---
**3. Can Linalg loops start from non-zero?**
You're right that in canonical linalg-on-tensors form, loops inside `linalg.generic` are normalized to start at 0. However, the indexing map can introduce an offset, causing tensor accesses to start at non-zero indices.
I believe this can happen during transformations like tiling or fusion. For example, after tiling:
```mlir
// Operating on a slice starting at index 64
linalg.generic {
  indexing_maps = [affine_map<(d0) -> (d0 + 64)>],
  iterator_types = ["parallel"]
} ...
```
- Loop variable d0: 0, 1, 2, ... (starts at 0)
- Tensor accesses: 64, 65, 66, ... (starts at 64)
The verifier checks the computed access indices (64+) against the tensor's dimension.
---
https://github.com/llvm/llvm-project/pull/163791
    
    
More information about the Mlir-commits
mailing list