[Mlir-commits] [mlir] [mlir][Transform dial] Expose convert-linalg-to-affine-loops transf (PR #211308)

Guillaume Iooss llvmlistbot at llvm.org
Fri Jul 31 07:21:47 PDT 2026


https://github.com/guillaumeiooss updated https://github.com/llvm/llvm-project/pull/211308

>From 38f0eb80e63a92479f58ac8eb657dcdf8c6bdd50 Mon Sep 17 00:00:00 2001
From: Guillaume I <guillaume.iooss at gmail.com>
Date: Wed, 22 Jul 2026 17:57:08 +0200
Subject: [PATCH 1/2] [mlir][Transform dialect] Expose
 convert-linalg-to-affine-loops transformation

---
 .../Linalg/TransformOps/LinalgTransformOps.td | 33 +++++++
 .../TransformOps/LinalgTransformOps.cpp       | 35 +++++++
 ...orm-op-convert-linalg-to-affine-loops.mlir | 94 +++++++++++++++++++
 3 files changed, 162 insertions(+)
 create mode 100644 mlir/test/Dialect/Linalg/transform-op-convert-linalg-to-affine-loops.mlir

diff --git a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
index 09a6c4c4d652f..e227bacb635e1 100644
--- a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
+++ b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
@@ -3075,4 +3075,37 @@ def DecomposeWinogradOp : Op<Transform_Dialect,
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// LinAlgToAffine
+//===----------------------------------------------------------------------===//
+
+def LinAlgToAffineOp : Op<Transform_Dialect, "structured.linalg_to_affine",
+    [FunctionalStyleTransformOpTrait,
+     MemoryEffectsOpInterface,
+     TransformOpInterface, TransformEachOpTrait,
+     ReportTrackingListenerFailuresOpTrait]> {
+  let description = [{
+    Convert a linalg operator into affine for loops.
+    The hypothesis are the same than the convert-linalg-to-affine
+    pass: we assume that the linalg operator is already generalized
+    (into linalg.generic operators) and that "memref" are used.
+  }];
+
+  let arguments = (ins TransformHandleTypeInterface:$target);
+  let results = (outs TransformHandleTypeInterface:$transformed);
+
+  let assemblyFormat = [{
+      $target attr-dict `:` 
+      custom<SemiFunctionType>(type($target), type($transformed), "false")
+  }];
+
+  let extraClassDeclaration = [{
+    ::mlir::DiagnosedSilenceableFailure applyToOne(
+        ::mlir::transform::TransformRewriter &rewriter,
+        ::mlir::linalg::LinalgOp target,
+        ::mlir::transform::ApplyToEachResultList &results,
+        ::mlir::transform::TransformState &state);
+  }];
+}
+
 #endif // LINALG_TRANSFORM_OPS
diff --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
index 8c5bd50bd6f8b..3dccdf2b96102 100644
--- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
+++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
@@ -4593,6 +4593,41 @@ DiagnosedSilenceableFailure transform::DecomposeWinogradOp::applyToOne(
   return DiagnosedSilenceableFailure::success();
 }
 
+//===----------------------------------------------------------------------===//
+// LinAlgToAffine
+//===----------------------------------------------------------------------===//
+
+DiagnosedSilenceableFailure transform::LinAlgToAffineOp::applyToOne(
+    transform::TransformRewriter &rewriter, linalg::LinalgOp target,
+    ApplyToEachResultList &results, TransformState &state) {
+  if (! isa<GenericOp>(target)) {
+    return DiagnosedSilenceableFailure::definiteFailure();
+  }
+
+  rewriter.setInsertionPoint(target);
+
+  FailureOr<LinalgLoops> generic = linalgOpToAffineLoops(rewriter, target);
+  if (succeeded(generic)) {
+    assert(! generic->empty() && "expected at least one loop");
+
+    // "generic" contains all new "AffineForOp", while we need to topmost one.
+    // Since all linalg operators are perfectly nested loops, these operators
+    //   are totally ordered through the ancestor relation.
+    Operation* opFirst = *(generic->begin());
+    for (auto itop = generic->begin(); itop!=generic->end(); itop++) {
+      if ( (*itop)->isProperAncestor(opFirst)) {
+        opFirst = *itop;
+      }
+    }
+
+    rewriter.replaceOp(target, opFirst);
+
+    results.push_back(opFirst);
+    return DiagnosedSilenceableFailure::success();
+  }
+  return DiagnosedSilenceableFailure::definiteFailure();
+}
+
 #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOpsEnums.cpp.inc"
 
 #define GET_OP_CLASSES
diff --git a/mlir/test/Dialect/Linalg/transform-op-convert-linalg-to-affine-loops.mlir b/mlir/test/Dialect/Linalg/transform-op-convert-linalg-to-affine-loops.mlir
new file mode 100644
index 0000000000000..a5e206a38eec8
--- /dev/null
+++ b/mlir/test/Dialect/Linalg/transform-op-convert-linalg-to-affine-loops.mlir
@@ -0,0 +1,94 @@
+// RUN: mlir-opt  %s --transform-interpreter -verify-diagnostics \
+// RUN:     --split-input-file | FileCheck %s
+
+//     CHECK: #[[MAP:.+]] = affine_map<(d0) -> (d0)>
+//     CHECK: func.func @convert_affine_matmul_buffer(%arg0: memref<16x8xf32>, %arg1: memref<8x32xf32>, %arg2: memref<16x32xf32>)
+// CHECK-DAG:   affine.for %[[arg3:.*]] = 0 to 16
+// CHECK-DAG:   affine.for %[[arg4:.*]] = 0 to 32
+// CHECK-DAG:   affine.for %[[arg5:.*]] = 0 to 8
+// CHECK-DAG:   %[[v0:.*]] = affine.apply #[[MAP]](%[[arg3]])
+// CHECK-DAG:   %[[v1:.*]] = affine.apply #[[MAP]](%[[arg5]])
+// CHECK-DAG:   %[[v2:.*]] = affine.load %arg0[%[[v0]], %[[v1]]] : memref<16x8xf32>
+// CHECK-DAG:   %[[v3:.*]] = affine.apply #[[MAP]](%[[arg5]])
+// CHECK-DAG:   %[[v4:.*]] = affine.apply #[[MAP]](%[[arg4]])
+// CHECK-DAG:   %[[v5:.*]] = affine.load %arg1[%[[v3]], %[[v4]]] : memref<8x32xf32>
+// CHECK-DAG:   %[[v6:.*]] = affine.apply #[[MAP]](%[[arg3]])
+// CHECK-DAG:   %[[v7:.*]] = affine.apply #[[MAP]](%[[arg4]])
+// CHECK-DAG:   %[[v8:.*]] = affine.load %arg2[%[[v6]], %[[v7]]] : memref<16x32xf32>
+// CHECK-DAG:   %[[v9:.*]] = affine.apply #[[MAP]](%[[arg3]])
+// CHECK-DAG:   %[[v10:.*]] = affine.apply #[[MAP]](%[[arg4]])
+// CHECK-DAG:   %[[v11:.*]] = arith.mulf %[[v2]], %[[v5]] : f32
+// CHECK-DAG:   %[[v12:.*]] = arith.addf %[[v8]], %[[v11]] : f32
+//     CHECK:   affine.store %[[v12]], %arg2[%[[v9]], %[[v10]]] : memref<16x32xf32>
+
+#map = affine_map<(d0, d1, d2) -> (d0, d2)>
+#map1 = affine_map<(d0, d1, d2) -> (d2, d1)>
+#map2 = affine_map<(d0, d1, d2) -> (d0, d1)>
+func.func @convert_affine_matmul_buffer(%arg0: memref<16x8xf32>, %arg1: memref<8x32xf32>, %arg2: memref<16x32xf32>) {
+  linalg.generic
+    {indexing_maps = [#map, #map1, #map2], iterator_types = ["parallel", "parallel", "reduction"]}
+    ins(%arg0, %arg1 : memref<16x8xf32>, memref<8x32xf32>) outs(%arg2 : memref<16x32xf32>) {
+      ^bb0(%in: f32, %in_0: f32, %out: f32):
+        %0 = arith.mulf %in, %in_0 : f32
+        %1 = arith.addf %out, %0 : f32
+        linalg.yield %1 : f32
+    }
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
+    %0 = transform.structured.match interface{LinalgOp} in %arg1 : (!transform.any_op) -> !transform.any_op
+    %1 = transform.structured.linalg_to_affine %0 : (!transform.any_op) -> !transform.any_op
+    transform.yield
+  }
+}
+
+// -----
+
+//     CHECK: #[[MAP:.+]] = affine_map<(d0) -> (d0)>
+//     CHECK: func.func @convert_affine_tc_buffer(%arg0: memref<16x8x4xf32>, %arg1: memref<8x4x32xf32>, %arg2: memref<16x32xf32>)
+// CHECK-DAG:   affine.for %[[arg3:.*]] = 0 to 16
+// CHECK-DAG:   affine.for %[[arg4:.*]] = 0 to 32
+// CHECK-DAG:   affine.for %[[arg5:.*]] = 0 to 8
+// CHECK-DAG:   affine.for %[[arg6:.*]] = 0 to 4
+// CHECK-DAG:   %[[v0:.*]] = affine.apply #[[MAP]](%[[arg3]])
+// CHECK-DAG:   %[[v1:.*]] = affine.apply #[[MAP]](%[[arg5]])
+// CHECK-DAG:   %[[v2:.*]] = affine.apply #[[MAP]](%[[arg6]])
+// CHECK-DAG:   %[[v3:.*]] = affine.load %arg0[%[[v0]], %[[v1]], %[[v2]]] : memref<16x8x4xf32>
+// CHECK-DAG:   %[[v4:.*]] = affine.apply #[[MAP]](%[[arg5]])
+// CHECK-DAG:   %[[v5:.*]] = affine.apply #[[MAP]](%[[arg6]])
+// CHECK-DAG:   %[[v6:.*]] = affine.apply #[[MAP]](%[[arg4]])
+// CHECK-DAG:   %[[v7:.*]] = affine.load %arg1[%[[v4]], %[[v5]], %[[v6]]] : memref<8x4x32xf32>
+// CHECK-DAG:   %[[v8:.*]] = affine.apply #[[MAP]](%[[arg3]])
+// CHECK-DAG:   %[[v9:.*]] = affine.apply #[[MAP]](%[[arg4]])
+// CHECK-DAG:   %[[v10:.*]] = affine.load %arg2[%[[v8]], %[[v9]]] : memref<16x32xf32>
+// CHECK-DAG:   %[[v11:.*]] = affine.apply #[[MAP]](%[[arg3]])
+// CHECK-DAG:   %[[v12:.*]] = affine.apply #[[MAP]](%[[arg4]])
+// CHECK-DAG:   %[[v13:.*]] = arith.mulf %[[v3]], %[[v7]] : f32
+// CHECK-DAG:   %[[v14:.*]] = arith.addf %[[v10]], %[[v13]] : f32
+//     CHECK:   affine.store %[[v14]], %arg2[%[[v11]], %[[v12]]] : memref<16x32xf32>
+
+#map = affine_map<(d0, d1, d2, d3) -> (d0, d2, d3)>
+#map1 = affine_map<(d0, d1, d2, d3) -> (d2, d3, d1)>
+#map2 = affine_map<(d0, d1, d2, d3) -> (d0, d1)>
+func.func @convert_affine_tc_buffer(%arg0: memref<16x8x4xf32>, %arg1: memref<8x4x32xf32>, %arg2: memref<16x32xf32>) {
+  linalg.generic
+    {indexing_maps = [#map, #map1, #map2], iterator_types = ["parallel", "parallel", "reduction", "reduction"]}
+    ins(%arg0, %arg1 : memref<16x8x4xf32>, memref<8x4x32xf32>) outs(%arg2 : memref<16x32xf32>) {
+      ^bb0(%in: f32, %in_0: f32, %out: f32):
+        %0 = arith.mulf %in, %in_0 : f32
+        %1 = arith.addf %out, %0 : f32
+        linalg.yield %1 : f32
+    }
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
+    %0 = transform.structured.match interface{LinalgOp} in %arg1 : (!transform.any_op) -> !transform.any_op
+    %1 = transform.structured.linalg_to_affine %0 : (!transform.any_op) -> !transform.any_op
+    transform.yield
+  }
+}
+

>From ffbf7a5bae883c3d7d2265dd215b60f7c7f953c1 Mon Sep 17 00:00:00 2001
From: Guillaume I <guillaume.iooss at gmail.com>
Date: Fri, 31 Jul 2026 15:32:12 +0200
Subject: [PATCH 2/2] [mlir][Transform dialect] Added support for 0-D
 linalg.generic to structured.to_affine

---
 .../Linalg/TransformOps/LinalgTransformOps.td |  11 +-
 .../TransformOps/LinalgTransformOps.cpp       | 107 +++++++++---
 ...orm-op-convert-linalg-to-affine-loops.mlir | 153 +++++++++++++-----
 3 files changed, 210 insertions(+), 61 deletions(-)

diff --git a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
index e227bacb635e1..fb8df04acccaa 100644
--- a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
+++ b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
@@ -3076,19 +3076,20 @@ def DecomposeWinogradOp : Op<Transform_Dialect,
 }
 
 //===----------------------------------------------------------------------===//
-// LinAlgToAffine
+// LinalgToAffine
 //===----------------------------------------------------------------------===//
 
-def LinAlgToAffineOp : Op<Transform_Dialect, "structured.linalg_to_affine",
+def LinalgToAffineOp : Op<Transform_Dialect, "structured.to_affine",
     [FunctionalStyleTransformOpTrait,
      MemoryEffectsOpInterface,
      TransformOpInterface, TransformEachOpTrait,
      ReportTrackingListenerFailuresOpTrait]> {
   let description = [{
-    Convert a linalg operator into affine for loops.
+    Convert a linalg operation into affine for loops.
     The hypothesis are the same than the convert-linalg-to-affine
-    pass: we assume that the linalg operator is already generalized
-    (into linalg.generic operators) and that "memref" are used.
+    pass: we assume that the linalg operation is already generalized
+    (into a linalg.generic operation) and that "memref" are used.
+    If these hypothesis are not satisfied, a silenceable failure is raised.
   }];
 
   let arguments = (ins TransformHandleTypeInterface:$target);
diff --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
index 3dccdf2b96102..052d4a1fabbf0 100644
--- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
+++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
@@ -4594,38 +4594,107 @@ DiagnosedSilenceableFailure transform::DecomposeWinogradOp::applyToOne(
 }
 
 //===----------------------------------------------------------------------===//
-// LinAlgToAffine
+// LinalgToAffine
 //===----------------------------------------------------------------------===//
 
-DiagnosedSilenceableFailure transform::LinAlgToAffineOp::applyToOne(
+DiagnosedSilenceableFailure transform::LinalgToAffineOp::applyToOne(
     transform::TransformRewriter &rewriter, linalg::LinalgOp target,
     ApplyToEachResultList &results, TransformState &state) {
-  if (! isa<GenericOp>(target)) {
-    return DiagnosedSilenceableFailure::definiteFailure();
+  if (!isa<GenericOp>(target)) {
+    DiagnosedSilenceableFailure diag =
+        emitSilenceableError() << "this operation is not a linalg.generic";
+    diag.attachNote(target.getLoc()) << "target op";
+    return diag;
+  }
+  if (!target.hasPureBufferSemantics()) {
+    DiagnosedSilenceableFailure diag =
+        emitSilenceableError() << "this operation does not use only memRef";
+    diag.attachNote(target.getLoc()) << "target op";
+    return diag;
   }
 
   rewriter.setInsertionPoint(target);
 
-  FailureOr<LinalgLoops> generic = linalgOpToAffineLoops(rewriter, target);
-  if (succeeded(generic)) {
-    assert(! generic->empty() && "expected at least one loop");
-
-    // "generic" contains all new "AffineForOp", while we need to topmost one.
-    // Since all linalg operators are perfectly nested loops, these operators
-    //   are totally ordered through the ancestor relation.
-    Operation* opFirst = *(generic->begin());
-    for (auto itop = generic->begin(); itop!=generic->end(); itop++) {
-      if ( (*itop)->isProperAncestor(opFirst)) {
-        opFirst = *itop;
-      }
+  // Special case where the generic operator is 0-dimensional
+  // We create a scf::ExecuteRegionOp in order to be able to output a single
+  // operation in this case
+  if (target.getNumLoops() == 0) {
+    scf::ExecuteRegionOp opReg = scf::ExecuteRegionOp::create(
+        rewriter, target->getLoc(), target->getResultTypes());
+    Block *blOpReg = &opReg.getRegion().emplaceBlock();
+    rewriter.setInsertionPointToStart(blOpReg);
+
+    Block *blockTarget = target.getBlock();
+    IRMapping map; // Old value |--> New value
+
+    // a. Load (convert memref<X> to X)
+    SmallVector<Value> indexedValues; // New load values
+    indexedValues.reserve(target.getNumDpsInputs());
+    for (OpOperand *inputOperand : target.getDpsInputOperands()) {
+      Value valNewInput = affine::AffineLoadOp::create(
+          rewriter, target.getLoc(), inputOperand->get());
+      indexedValues.push_back(valNewInput);
     }
+    for (OpOperand &outputOperand : target.getDpsInitsMutable()) {
+      Value valNewOutput = affine::AffineLoadOp::create(
+          rewriter, target.getLoc(), outputOperand.get());
+      indexedValues.push_back(valNewOutput);
+    }
+    map.map(blockTarget->getArguments(), indexedValues);
 
-    rewriter.replaceOp(target, opFirst);
+    // b. Operations
+    for (auto &op : blockTarget->without_terminator()) {
+      Operation *newOp = rewriter.clone(op, map);
+      map.map(op.getResults(), newOp->getResults());
+    }
+
+    // c. Store (convert X to memref<X>)
+    SmallVector<Value> outputBuffers;
+    for (OpOperand &outputOperand : target.getDpsInitsMutable()) {
+      if (!isa<MemRefType>(outputOperand.get().getType()))
+        continue;
+      outputBuffers.push_back(outputOperand.get());
+    }
 
-    results.push_back(opFirst);
+    Operation *terminator = blockTarget->getTerminator();
+    for (OpOperand &operand : terminator->getOpOperands()) {
+      Value valtoStore = map.lookupOrDefault(operand.get());
+      affine::AffineStoreOp::create(
+        rewriter, target.getLoc(), valtoStore,
+        outputBuffers[operand.getOperandNumber()], {});
+    }
+
+    // d. Terminator
+    SmallVector<Value> emptyYield;
+    scf::YieldOp::create(rewriter, target.getLoc(), emptyYield);
+
+    rewriter.replaceOp(target, opReg.getResults());
+    results.push_back(opReg);
     return DiagnosedSilenceableFailure::success();
   }
-  return DiagnosedSilenceableFailure::definiteFailure();
+
+  // At least one dimension in the targeted linalg.generic
+  FailureOr<LinalgLoops> genericLoops = linalgOpToAffineLoops(rewriter, target);
+  if (!succeeded(genericLoops)) {
+    return DiagnosedSilenceableFailure::definiteFailure();
+  }
+
+  assert(!genericLoops->empty() && "expected at least one loop");
+
+  // "genericLoops" contains all new "AffineForOp", while we need to topmost
+  // one. Since all linalg operators are perfectly nested loops, these operators
+  //   are totally ordered through the ancestor relation.
+  Operation *opFirst = *(genericLoops->begin());
+  for (auto itop = genericLoops->begin(); itop != genericLoops->end(); itop++) {
+    if ((*itop)->isProperAncestor(opFirst)) {
+      opFirst = *itop;
+    }
+  }
+
+  rewriter.replaceOp(target, opFirst);
+
+  results.push_back(opFirst);
+  return DiagnosedSilenceableFailure::success();
 }
 
 #include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOpsEnums.cpp.inc"
diff --git a/mlir/test/Dialect/Linalg/transform-op-convert-linalg-to-affine-loops.mlir b/mlir/test/Dialect/Linalg/transform-op-convert-linalg-to-affine-loops.mlir
index a5e206a38eec8..41eba6882852b 100644
--- a/mlir/test/Dialect/Linalg/transform-op-convert-linalg-to-affine-loops.mlir
+++ b/mlir/test/Dialect/Linalg/transform-op-convert-linalg-to-affine-loops.mlir
@@ -3,22 +3,22 @@
 
 //     CHECK: #[[MAP:.+]] = affine_map<(d0) -> (d0)>
 //     CHECK: func.func @convert_affine_matmul_buffer(%arg0: memref<16x8xf32>, %arg1: memref<8x32xf32>, %arg2: memref<16x32xf32>)
-// CHECK-DAG:   affine.for %[[arg3:.*]] = 0 to 16
-// CHECK-DAG:   affine.for %[[arg4:.*]] = 0 to 32
-// CHECK-DAG:   affine.for %[[arg5:.*]] = 0 to 8
-// CHECK-DAG:   %[[v0:.*]] = affine.apply #[[MAP]](%[[arg3]])
-// CHECK-DAG:   %[[v1:.*]] = affine.apply #[[MAP]](%[[arg5]])
-// CHECK-DAG:   %[[v2:.*]] = affine.load %arg0[%[[v0]], %[[v1]]] : memref<16x8xf32>
-// CHECK-DAG:   %[[v3:.*]] = affine.apply #[[MAP]](%[[arg5]])
-// CHECK-DAG:   %[[v4:.*]] = affine.apply #[[MAP]](%[[arg4]])
-// CHECK-DAG:   %[[v5:.*]] = affine.load %arg1[%[[v3]], %[[v4]]] : memref<8x32xf32>
-// CHECK-DAG:   %[[v6:.*]] = affine.apply #[[MAP]](%[[arg3]])
-// CHECK-DAG:   %[[v7:.*]] = affine.apply #[[MAP]](%[[arg4]])
-// CHECK-DAG:   %[[v8:.*]] = affine.load %arg2[%[[v6]], %[[v7]]] : memref<16x32xf32>
-// CHECK-DAG:   %[[v9:.*]] = affine.apply #[[MAP]](%[[arg3]])
-// CHECK-DAG:   %[[v10:.*]] = affine.apply #[[MAP]](%[[arg4]])
-// CHECK-DAG:   %[[v11:.*]] = arith.mulf %[[v2]], %[[v5]] : f32
-// CHECK-DAG:   %[[v12:.*]] = arith.addf %[[v8]], %[[v11]] : f32
+//     CHECK:   affine.for %[[arg3:.*]] = 0 to 16
+//     CHECK:   affine.for %[[arg4:.*]] = 0 to 32
+//     CHECK:   affine.for %[[arg5:.*]] = 0 to 8
+//     CHECK:   %[[v0:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v1:.*]] = affine.apply #[[MAP]](%[[arg5]])
+//     CHECK:   %[[v2:.*]] = affine.load %arg0[%[[v0]], %[[v1]]] : memref<16x8xf32>
+//     CHECK:   %[[v3:.*]] = affine.apply #[[MAP]](%[[arg5]])
+//     CHECK:   %[[v4:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v5:.*]] = affine.load %arg1[%[[v3]], %[[v4]]] : memref<8x32xf32>
+//     CHECK:   %[[v6:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v7:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v8:.*]] = affine.load %arg2[%[[v6]], %[[v7]]] : memref<16x32xf32>
+//     CHECK:   %[[v9:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v10:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v11:.*]] = arith.mulf %[[v2]], %[[v5]] : f32
+//     CHECK:   %[[v12:.*]] = arith.addf %[[v8]], %[[v11]] : f32
 //     CHECK:   affine.store %[[v12]], %arg2[%[[v9]], %[[v10]]] : memref<16x32xf32>
 
 #map = affine_map<(d0, d1, d2) -> (d0, d2)>
@@ -39,7 +39,7 @@ func.func @convert_affine_matmul_buffer(%arg0: memref<16x8xf32>, %arg1: memref<8
 module attributes {transform.with_named_sequence} {
   transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
     %0 = transform.structured.match interface{LinalgOp} in %arg1 : (!transform.any_op) -> !transform.any_op
-    %1 = transform.structured.linalg_to_affine %0 : (!transform.any_op) -> !transform.any_op
+    %1 = transform.structured.to_affine %0 : (!transform.any_op) -> !transform.any_op
     transform.yield
   }
 }
@@ -48,25 +48,25 @@ module attributes {transform.with_named_sequence} {
 
 //     CHECK: #[[MAP:.+]] = affine_map<(d0) -> (d0)>
 //     CHECK: func.func @convert_affine_tc_buffer(%arg0: memref<16x8x4xf32>, %arg1: memref<8x4x32xf32>, %arg2: memref<16x32xf32>)
-// CHECK-DAG:   affine.for %[[arg3:.*]] = 0 to 16
-// CHECK-DAG:   affine.for %[[arg4:.*]] = 0 to 32
-// CHECK-DAG:   affine.for %[[arg5:.*]] = 0 to 8
-// CHECK-DAG:   affine.for %[[arg6:.*]] = 0 to 4
-// CHECK-DAG:   %[[v0:.*]] = affine.apply #[[MAP]](%[[arg3]])
-// CHECK-DAG:   %[[v1:.*]] = affine.apply #[[MAP]](%[[arg5]])
-// CHECK-DAG:   %[[v2:.*]] = affine.apply #[[MAP]](%[[arg6]])
-// CHECK-DAG:   %[[v3:.*]] = affine.load %arg0[%[[v0]], %[[v1]], %[[v2]]] : memref<16x8x4xf32>
-// CHECK-DAG:   %[[v4:.*]] = affine.apply #[[MAP]](%[[arg5]])
-// CHECK-DAG:   %[[v5:.*]] = affine.apply #[[MAP]](%[[arg6]])
-// CHECK-DAG:   %[[v6:.*]] = affine.apply #[[MAP]](%[[arg4]])
-// CHECK-DAG:   %[[v7:.*]] = affine.load %arg1[%[[v4]], %[[v5]], %[[v6]]] : memref<8x4x32xf32>
-// CHECK-DAG:   %[[v8:.*]] = affine.apply #[[MAP]](%[[arg3]])
-// CHECK-DAG:   %[[v9:.*]] = affine.apply #[[MAP]](%[[arg4]])
-// CHECK-DAG:   %[[v10:.*]] = affine.load %arg2[%[[v8]], %[[v9]]] : memref<16x32xf32>
-// CHECK-DAG:   %[[v11:.*]] = affine.apply #[[MAP]](%[[arg3]])
-// CHECK-DAG:   %[[v12:.*]] = affine.apply #[[MAP]](%[[arg4]])
-// CHECK-DAG:   %[[v13:.*]] = arith.mulf %[[v3]], %[[v7]] : f32
-// CHECK-DAG:   %[[v14:.*]] = arith.addf %[[v10]], %[[v13]] : f32
+//     CHECK:   affine.for %[[arg3:.*]] = 0 to 16
+//     CHECK:   affine.for %[[arg4:.*]] = 0 to 32
+//     CHECK:   affine.for %[[arg5:.*]] = 0 to 8
+//     CHECK:   affine.for %[[arg6:.*]] = 0 to 4
+//     CHECK:   %[[v0:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v1:.*]] = affine.apply #[[MAP]](%[[arg5]])
+//     CHECK:   %[[v2:.*]] = affine.apply #[[MAP]](%[[arg6]])
+//     CHECK:   %[[v3:.*]] = affine.load %arg0[%[[v0]], %[[v1]], %[[v2]]] : memref<16x8x4xf32>
+//     CHECK:   %[[v4:.*]] = affine.apply #[[MAP]](%[[arg5]])
+//     CHECK:   %[[v5:.*]] = affine.apply #[[MAP]](%[[arg6]])
+//     CHECK:   %[[v6:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v7:.*]] = affine.load %arg1[%[[v4]], %[[v5]], %[[v6]]] : memref<8x4x32xf32>
+//     CHECK:   %[[v8:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v9:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v10:.*]] = affine.load %arg2[%[[v8]], %[[v9]]] : memref<16x32xf32>
+//     CHECK:   %[[v11:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v12:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v13:.*]] = arith.mulf %[[v3]], %[[v7]] : f32
+//     CHECK:   %[[v14:.*]] = arith.addf %[[v10]], %[[v13]] : f32
 //     CHECK:   affine.store %[[v14]], %arg2[%[[v11]], %[[v12]]] : memref<16x32xf32>
 
 #map = affine_map<(d0, d1, d2, d3) -> (d0, d2, d3)>
@@ -87,7 +87,86 @@ func.func @convert_affine_tc_buffer(%arg0: memref<16x8x4xf32>, %arg1: memref<8x4
 module attributes {transform.with_named_sequence} {
   transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
     %0 = transform.structured.match interface{LinalgOp} in %arg1 : (!transform.any_op) -> !transform.any_op
-    %1 = transform.structured.linalg_to_affine %0 : (!transform.any_op) -> !transform.any_op
+    %1 = transform.structured.to_affine %0 : (!transform.any_op) -> !transform.any_op
+    transform.yield
+  }
+}
+
+// -----
+
+//     CHECK: #[[MAP:.+]] = affine_map<(d0) -> (d0)>
+//     CHECK: func.func @convert_affine_nored_buffer(%arg0: memref<16x8xf32>, %arg1: memref<8x16xf32>, %arg2: memref<16x8xf32>)
+//     CHECK:   affine.for %[[arg3:.*]] = 0 to 16
+//     CHECK:   affine.for %[[arg4:.*]] = 0 to 8
+//     CHECK:   %[[v0:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v1:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v2:.*]] = affine.load %arg0[%[[v0]], %[[v1]]] : memref<16x8xf32>
+//     CHECK:   %[[v3:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v4:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v5:.*]] = affine.load %arg1[%[[v3]], %[[v4]]] : memref<8x16xf32>
+//     CHECK:   %[[v6:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v7:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v8:.*]] = affine.load %arg2[%[[v6]], %[[v7]]] : memref<16x8xf32>
+//     CHECK:   %[[v9:.*]] = affine.apply #[[MAP]](%[[arg3]])
+//     CHECK:   %[[v10:.*]] = affine.apply #[[MAP]](%[[arg4]])
+//     CHECK:   %[[v11:.*]] = arith.mulf %[[v2]], %[[v5]] : f32
+//     CHECK:   %[[v12:.*]] = arith.addf %[[v8]], %[[v11]] : f32
+//     CHECK:   affine.store %[[v12]], %arg2[%[[v9]], %[[v10]]] : memref<16x8xf32>
+#map = affine_map<(d0, d1) -> (d0, d1)>
+#map1 = affine_map<(d0, d1) -> (d1, d0)>
+#map2 = affine_map<(d0, d1) -> (d0, d1)>
+
+func.func @convert_affine_nored_buffer(%arg0: memref<16x8xf32>, %arg1: memref<8x16xf32>, %arg2: memref<16x8xf32>) {
+  linalg.generic
+    {indexing_maps = [#map, #map1, #map2], iterator_types = ["parallel", "parallel"]}
+    ins(%arg0, %arg1 : memref<16x8xf32>, memref<8x16xf32>) outs(%arg2 : memref<16x8xf32>) {
+      ^bb0(%in: f32, %in_0: f32, %out: f32):
+        %0 = arith.mulf %in, %in_0 : f32
+        %1 = arith.addf %out, %0 : f32
+        linalg.yield %1 : f32
+    }
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
+    %0 = transform.structured.match interface{LinalgOp} in %arg1 : (!transform.any_op) -> !transform.any_op
+    %1 = transform.structured.to_affine %0 : (!transform.any_op) -> !transform.any_op
+    transform.yield
+  }
+}
+
+
+
+// -----
+
+//     CHECK: func.func @convert_affine_0dim_generic_buffer(%arg0: memref<f32>, %arg1: memref<f32>, %arg2: memref<f32>)
+//     CHECK:   %[[v0:.*]] = affine.load %arg0[] : memref<f32>
+//     CHECK:   %[[v1:.*]] = affine.load %arg1[] : memref<f32>
+//     CHECK:   %[[v2:.*]] = affine.load %arg2[] : memref<f32>
+//     CHECK:   %[[v3:.*]] = arith.mulf %[[v0]], %[[v1]] : f32
+//     CHECK:   %[[v4:.*]] = arith.addf %[[v2]], %[[v3]] : f32
+//     CHECK:   affine.store %[[v4]], %arg2[] : memref<f32>
+#map  = affine_map<() -> ()>
+#map1 = affine_map<() -> ()>
+#map2 = affine_map<() -> ()>
+
+func.func @convert_affine_0dim_generic_buffer(%arg0: memref<f32>, %arg1: memref<f32>, %arg2: memref<f32>) {
+  linalg.generic
+    {indexing_maps = [#map, #map1, #map2], iterator_types = []}
+    ins(%arg0, %arg1 : memref<f32>, memref<f32>) outs(%arg2 : memref<f32>) {
+      ^bb0(%in: f32, %in_0: f32, %out: f32):
+        %0 = arith.mulf %in, %in_0 : f32
+        %1 = arith.addf %out, %0 : f32
+        linalg.yield %1 : f32
+    }
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg1: !transform.any_op {transform.readonly}) {
+    %0 = transform.structured.match interface{LinalgOp} in %arg1 : (!transform.any_op) -> !transform.any_op
+    %1 = transform.structured.to_affine %0 : (!transform.any_op) -> !transform.any_op
     transform.yield
   }
 }



More information about the Mlir-commits mailing list