theory, week 2source

linalg docs

linalg docs define structured ops through iteration spaces and indexing maps, the vocabulary Phase 1 depends on.


One operation, three pieces

A linalg operation is an iteration space, an indexing map per operand, and a scalar body. linalg.matmul is the named shorthand; linalg.generic carries the maps explicitly:

linalg.generic {
  indexing_maps = [affine_map<(i, j, k) -> (i, j)>,
                   affine_map<(i, j, k) -> (j, k)>,
                   affine_map<(i, j, k) -> (i, k)>],
  iterator_types = ["parallel", "parallel", "reduction"]
} ins(%A, %B : tensor<128x256xf32>, tensor<256x64xf32>)
  outs(%C : tensor<128x64xf32>) {
^bb0(%a: f32, %b: f32, %c: f32):
  %m = arith.mulf %a, %b : f32
  %s = arith.addf %c, %m : f32
  linalg.yield %s : f32
}

Read the maps as the subscripts of the loop body: A[i][j], B[j][k], C[i][k], with j marked as the reduction. That is the whole skill. Every later question about tiling, fusion and vectorisation is a question about those three lists.

Why the abstraction exists

The operation declares its space, so a transformation derives loops rather than pattern-matching a loop nest someone else wrote. The rationale document argues why this replaced the earlier habit of matching loop nests for a fixed set of named operations. Read it for that argument, not for syntax.

What the project needs from it

Iteration space, indexing maps, iterator types, named versus generic, and the tensor-to-memref boundary. Skip the catalogue of named operations and the generator on a first pass; look up a signature when you need one.

Afterwards you should be able to read any linalg.generic in a dump and write the loop nest it denotes, and to say what one tile of it looks like.

Things that break

Treating the maps as documentation and reading the body instead. Two generics with the same body and different maps compute different things, and a pass that rewrites one as the other is a miscompile. The tell is a transpose-shaped result that verifies cleanly and then disagrees with the reference.

Sources

A version records the documentation the claim was checked against, not a house pin. Confirm flags with --help on the release you installed.

Check yourself

A `linalg.generic` has input maps `(i, j)` and `(j, k)` and an output map `(i, k)`. What does it compute?

What does "structured" mean in these docs?

Why does tiling a linalg operation not require a pass that rewrites loop nests?

0 / 3 correct

← back to the map