[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