PSA: Transform Dialect tutorial is now available

The textual version of the Transform dialect tutorial is now available at Transform Dialect Tutorial - MLIR. It comes with compilable code examples in llvm-project/mlir/examples/transform at main · llvm/llvm-project · GitHub.

This is an offline version of the live tutorial I presented at the 2023 EuroLLVM earlier this month, the slides for which are available at Controllable Transformations in MLIR – Google Research and the recording will be made available by EuroLLVM organizers later. The offline version currently covers a subset of the live presentation material relevant to defining and using transform operations. The intention for this version is to provide an up-to-date, tested example.

As usual with documentation, patches are more than welcome.


Please use separate threads or file a bug on GitHub: a PSA isn’t meant for “support”.

Here it seems that some of the examples in the doc aren’t reflected in the test, mlir/test/Examples/transform/Ch1/ contains the running examples (and we should make sure all of the code samples from the doc are there).

I tried the command listed in tutorial Ch1 and something went wrong.

Chaining Transformations with Handles

the mlir as below:

transform.sequence failures(propagate) {
^bb0(%arg0: !transform.any_op,
     %arg1: !transform.op<"linalg.matmul">,
     %arg2: !transform.op<"linalg.elemwise_binary">):
  // Since the %arg2 handle is associated with both elementwise operations,
  // we need to split it into two handles so we can target only the second
  // elementwise operation.
  %add, %max = transform.split_handle %arg2
      : (!transform.op<"linalg.elemwise_binary">)
      -> (!transform.any_op, !transform.any_op)

  // The actual tiling transformation takes tile sizes as attributes. It produces a
  // handle to the loop generated during tiling.
  %loop, %tiled = transform.structured.tile_to_forall_op %max tile_sizes [8, 32]
      : (!transform.any_op) -> (!transform.any_op, !transform.any_op)

  // We can now fuse the other operations into the loop. Here, we fuse
  // operations one-by-one. This requires the operation that is being fused
  // to define the value used within the loop, so the order of such fusions
  // is important. We could also use "transform.merge_handles" to obtain
  // a single handle to all operations and give it to `fuse_into_containing_op`
  // that would take care of the ordering in this case.
  %add_fused = transform.structured.fuse_into_containing_op %add into %loop
      : (!transform.any_op, !transform.any_op) -> !transform.any_op
  %matmul_fused = transform.structured.fuse_into_containing_op %arg1 into %loop
      : (!transform.op<"linalg.matmul">, !transform.any_op) -> !transform.any_op


I tried command as below:

mlir-opt matmul.mlir --pass-pipeline="
        enable-expensive-checks})" > matmul_out.mlir

and it made the error:

matmul.mlir:49:16: error: 'transform.structured.fuse_into_containing_op' op expected 2 results
  %add_fused = transform.structured.fuse_into_containing_op %add into %loop
matmul.mlir:49:16: note: see current operation: %2 = "transform.structured.fuse_into_containing_op"(%0#0, %1#0) : (!transform.any_op, !transform.any_op) -> !transform.any_op

the transform.structured.fuse_into_containing_op in doc has only one returns while two returns exist in mlir/test/Examples/transform/Ch1/invalidation-2.mlir.
I check the transform dialect which also said it has 2 results.