Phase 1, week 5retrospective

Transform dialect tiling

The transform dialect scripts matching and tiling as data, so a pipeline can be changed without recompiling MLIR.


The schedule is IR

The transform dialect keeps the tiling decision in the module as operations, not in C++:

module attributes {transform.with_named_sequence} {
  transform.named_sequence @__transform_main(%root: !transform.any_op) {
    %mm = transform.structured.match ops{["linalg.matmul"]} in %root
        : (!transform.any_op) -> !transform.any_op
    %tiled, %l0, %l1 = transform.structured.tile_using_for %mm tile_sizes [2, 2, 0]
        : (!transform.any_op) -> (!transform.any_op, !transform.any_op, !transform.any_op)
    transform.yield
  }
}

Run it with the interpreter:

mlir-opt matmul.mlir --transform-interpreter

@__transform_main is the entry point the pass looks for, and its first argument binds to the payload operation. match selects by op name, tile_using_for consumes the handle and returns a handle to the tiled op plus one per generated loop. A zero tile size means the dimension is not tiled, so [2, 2, 0] yields exactly two loops.

What the indirection buys

Change the tile sizes and rerun the same binary. That is the whole argument: the schedule is data, so a pipeline can be tuned without recompiling MLIR, and a schedule can be checked into the repository next to the IR it applies to. The price is that the script is now part of the program, and its op names, attribute spellings and result arities are as version-bound as any pass name. Confirm each one against the release you pinned, then record the working script in VERSIONS.md beside the pass list.

Things that break

A transform script is not idempotent. Run it twice and match ops{["linalg.matmul"]} finds the inner tile ops as well as the original, so the second run tiles the tiles. Run it on an already-tiled module and you get a nest nobody asked for, with no error. When the pass reports that it could not find the entry point, the module is missing transform.with_named_sequence or the sequence is not named @__transform_main. When it reports a use of an invalidated handle, a transform op reused a handle that an earlier op consumed.

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

You change `tile_sizes [2, 2, 0]` to `[4, 4, 0]` and rerun `mlir-opt`. What had to be rebuilt?

You tile with a handle and then use the same handle in a second transform op. What happens?

Why must `@__transform_main` sit inside a module with `transform.with_named_sequence`?

0 / 3 correct

← back to the map