Skip to content

dialects: (linalg) write tiles back into the tensors carried by tile loops - #6370

Draft
dipo101 wants to merge 2 commits into
xdslproject:mainfrom
dipo101:linalg-tiling-tensor-writeback
Draft

dialects: (linalg) write tiles back into the tensors carried by tile loops#6370
dipo101 wants to merge 2 commits into
xdslproject:mainfrom
dipo101:linalg-tiling-tensor-writeback

Conversation

@dipo101

@dipo101 dipo101 commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Part of the tensor-based tiling checkbox on #6140.

A tile of a memref is written through the subview that views it, but a tile of a tensor is a new value, so it has to be written back explicitly and carried out of the loops it was computed in.

This passes the outputs of an op with tensor semantics as the loop nest iteration arguments, slices those outputs from the values the innermost loop carries rather than from the originals, and writes each computed tile back with a tensor.insert_slice. The innermost loop yields the updated tensors and each enclosing loop yields the results of the loop nested inside it, so the outermost loop produces the fully updated tensors, which then replace the results of the original op:

%C = scf.for %i = ... iter_args(%accI = %B) -> (tensor<4x4xf32>) {
  %r = scf.for %j = ... iter_args(%accJ = %accI) -> (tensor<4x4xf32>) {
    %in   = tensor.extract_slice %A[%i, %j] ...
    %out  = tensor.extract_slice %accJ[%i, %j] ...     // from the carried value
    %tile = linalg.generic ins(%in) outs(%out) ... -> tensor<2x2xf32>
    %upd  = tensor.insert_slice %tile into %accJ[%i, %j] ...
    scf.yield %upd : tensor<4x4xf32>
  }
  scf.yield %r : tensor<4x4xf32>
}

Two things here are easy to get wrong, and both give IR that verifies while dropping the work of the surrounding iterations: slicing an output from the original tensor rather than from the carried value, and erasing the op rather than replacing its results.

A tile is written back exactly where it was extracted from, so both use the same SliceParameters.

Tiling memrefs carries nothing, writes nothing back and yields nothing, so its generated IR is unchanged and the existing filecheck expectations are untouched. Tiling tensors is still rejected during analysis, so this is not yet reachable from the pass; a later PR lifts that.

@codecov

codecov Bot commented Aug 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.22222% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.93%. Comparing base (7da3e2a) to head (0e88664).

Files with missing lines Patch % Lines
xdsl/dialects/linalg/transforms/tiling.py 82.22% 7 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6370      +/-   ##
==========================================
- Coverage   86.94%   86.93%   -0.02%     
==========================================
  Files         440      440              
  Lines       65973    65999      +26     
  Branches     7493     7493              
==========================================
+ Hits        57360    57376      +16     
- Misses       7036     7044       +8     
- Partials     1577     1579       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@dipo101
dipo101 marked this pull request as ready for review August 15, 2026 23:44
Comment thread xdsl/dialects/linalg/transforms/tiling.py
Comment thread xdsl/dialects/linalg/transforms/tiling.py
Building the slice of an operand computes where the tile sits within that
operand and then materializes it, which are separate concerns: the geometry
is the same whether the operand is a memref or a tensor, while the op that
materializes the slice is not.

Move that computation into `SliceParameters.compute`, and have
`_build_tiled_slice` take the result along with the type it is slicing. This
mirrors how upstream separates `computeSliceParameters` from
`materializeTiledShape`, and makes the geometry testable on its own.

Generated IR is unchanged.
…loops

A tile of a memref is written through the subview that views it, but a tile
of a tensor is a new value, so it has to be written back explicitly and
carried out of the loops it was computed in.

Pass the outputs of an op with tensor semantics as the loop nest iteration
arguments, slice those outputs from the values the innermost loop carries
rather than from the originals, and write each computed tile back with a
`tensor.insert_slice`. The innermost loop yields the updated tensors and
each enclosing loop yields the results of the loop nested inside it, so the
outermost loop produces the fully updated tensors, which then replace the
results of the original op.

Slicing an output from the original tensor rather than from the carried
value, or erasing the op rather than replacing its results, would both give
IR that verifies but drops the work of the surrounding iterations.

The offsets, sizes and strides of a tile are now computed once as
`SliceParameters`, since a tile has to be written back exactly where it was
extracted from.

Tiling memrefs carries nothing, writes nothing back, and yields nothing, so
its generated IR is unchanged. Tiling tensors is still rejected during
analysis, so this is not yet reachable from the pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants