Phase 1, week 4retrospective

linalg iteration space

A linalg op's loops are implicit in its iteration space, not written as scf.for in the IR.


One op, no loops

linalg.matmul is a single operation:

func.func @matmul(%A: memref<16x16xf32>, %B: memref<16x16xf32>,
                  %C: memref<16x16xf32>) {
  linalg.matmul ins(%A, %B : memref<16x16xf32>, memref<16x16xf32>)
                outs(%C : memref<16x16xf32>)
  return
}

No scf.for. The loop nest is the op’s iteration space: three dimensions (m, n, k), each bounded by an operand dimension, so 16 cubed iterations. The payload region runs once per iteration and has no trip count of its own.

Where the bounds come from

Static shapes make the trip counts constants read off the operand types. memref<?x?xf32> turns them into memref.dim values, so one op serves every shape. You do not write the bounds, and you cannot disagree with them without also disagreeing with the shapes: each bound is read from an operand whose map indexes that dimension, so m is pinned by A and C, n by B and C, k by A and B.

Loops appear at lowering

mlir-opt matmul.mlir --convert-linalg-to-loops

produces three nested scf.for operations around memref.load, arith.mulf, arith.addf, and memref.store. --convert-scf-to-cf then turns them into blocks and branches. Both names are version-bound; check mlir-opt --help on the release you pinned.

That ordering is the point. Tiling, fusion, and vectorization rewrite the iteration space — splitting it, reordering it, replacing dimensions with vector lanes — and the loops are generated afterwards from whatever space is left.

Things that break

Grepping for scf.for before lowering returns nothing, and it is tempting to conclude the matmul is an opaque call. It is not: it is one op with a known iteration space, which is exactly why a pass can tile it without a loop analysis. The opposite mistake is assuming the shapes are checked. With dynamic operands a mismatched call verifies and reads whatever the dim values point at, so the reference check, not the verifier, is what catches it.

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

Where is the loop nest of a `linalg.matmul` in the IR?

You grep a module for `scf.for` to locate the matmul loop nest and find nothing. What follows?

With `memref<?x?xf32>` operands, what fixes the trip counts?

0 / 3 correct

← back to the map