[Mlir-commits] [mlir] [mlir][transform] add ApplyEraseUnusedOperandsAndResultsPatternsOp transform op (PR #225864)
Tuomas Kärnä
llvmlistbot at llvm.org
Fri Sep 25 06:53:49 PDT 2026
https://github.com/tkarna updated https://github.com/llvm/llvm-project/pull/225864
>From 068669ed39996bfc574a2be9dc7f8e1ea0b661a3 Mon Sep 17 00:00:00 2001
From: Tuomas Karna <tuomas.karna at intel.com>
Date: Wed, 23 Sep 2026 20:04:23 +0300
Subject: [PATCH 1/4] linalg: add ApplyEraseUnusedOperandsAndResultsPatternsOp
transform op
---
.../Linalg/TransformOps/LinalgTransformOps.td | 11 +++++++
.../TransformOps/LinalgTransformOps.cpp | 5 +++
...-op-erase-unused-operands-and-results.mlir | 32 +++++++++++++++++++
mlir/test/python/dialects/transform.py | 13 ++++++++
4 files changed, 61 insertions(+)
create mode 100644 mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir
diff --git a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
index 5df9e14b8a3f06..c31cd399032986 100644
--- a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
+++ b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td
@@ -176,6 +176,17 @@ def ApplySwapExtractSliceWithFillPatternsOp : Op<Transform_Dialect,
let assemblyFormat = "attr-dict";
}
+def ApplyEraseUnusedOperandsAndResultsPatternsOp : Op<Transform_Dialect,
+ "apply_patterns.linalg.erase_unused_operands_and_results",
+ [DeclareOpInterfaceMethods<PatternDescriptorOpInterface>]> {
+ let description = [{
+ Collects patterns that deduplicate operands and remove dead results of
+ `linalg.generic` ops.
+ }];
+
+ let assemblyFormat = "attr-dict";
+}
+
//===----------------------------------------------------------------------===//
// BufferizeToAllocationOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
index 16b03ab5426a0d..9e382b61e03840 100644
--- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
+++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp
@@ -271,6 +271,11 @@ void transform::ApplySwapExtractSliceWithFillPatternsOp::populatePatterns(
linalg::populateSwapExtractSliceWithFillPatterns(patterns);
}
+void transform::ApplyEraseUnusedOperandsAndResultsPatternsOp::populatePatterns(
+ RewritePatternSet &patterns) {
+ linalg::populateEraseUnusedOperandsAndResultsPatterns(patterns);
+}
+
//===----------------------------------------------------------------------===//
// BufferizeToAllocationOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir b/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir
new file mode 100644
index 00000000000000..ed47329e197a1c
--- /dev/null
+++ b/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir
@@ -0,0 +1,32 @@
+// RUN: mlir-opt %s -transform-interpreter | FileCheck %s
+
+#map0 = affine_map<(d0) -> (d0)>
+func.func @remove_deadargs_generic_basic(%arg0: tensor<?xf32>) -> (tensor<?xf32>) {
+ %c0 = arith.constant 0 : index
+ %cst = arith.constant 7.0 : f32
+ %0 = tensor.dim %arg0, %c0 : tensor<?xf32>
+ %1 = tensor.empty(%0) : tensor<?xf32>
+ %2 = tensor.empty(%0) : tensor<?xf32>
+ %3 = linalg.generic {indexing_maps = [#map0, #map0, #map0], iterator_types=["parallel"]} ins(%arg0, %1 : tensor<?xf32>, tensor<?xf32>) outs (%2:tensor<?xf32>) {
+ ^bb0(%arg1: f32, %arg2: f32, %arg3: f32):
+ %4 = arith.addf %arg1, %cst : f32
+ linalg.yield %4 : f32
+ } -> tensor<?xf32>
+ return %3 : tensor<?xf32>
+}
+
+module attributes {transform.with_named_sequence} {
+ transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+ %f = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op
+ transform.apply_patterns to %f {
+ transform.apply_patterns.linalg.erase_unused_operands_and_results
+ } : !transform.any_op
+ transform.yield
+ }
+}
+
+// CHECK-LABEL: func @remove_deadargs_generic_basic
+// CHECK-SAME: (%[[ARG0:.*]]: tensor<?xf32>) -> tensor<?xf32> {
+// CHECK: %[[GENERIC_OP:.*]] = linalg.generic
+// CHECK-SAME: ins(%[[ARG0]] : tensor<?xf32>)
+// CHECK-SAME: outs({{.*}} : tensor<?xf32>) {
diff --git a/mlir/test/python/dialects/transform.py b/mlir/test/python/dialects/transform.py
index 4b7a2bb39c8800..55643f2bba870a 100644
--- a/mlir/test/python/dialects/transform.py
+++ b/mlir/test/python/dialects/transform.py
@@ -315,6 +315,19 @@ def testApplyLinalgSwapExtractSliceWithFillPattern(module: Module):
# CHECK: transform.apply_patterns.linalg.swap_extract_slice_with_fill
+ at run
+def testApplyLinalgEraseUnusedOperandsAndResultsPattern(module: Module):
+ sequence = transform.SequenceOp(
+ transform.FailurePropagationMode.Propagate, [], transform.AnyOpType.get()
+ )
+ with InsertionPoint(sequence.body):
+ with InsertionPoint(transform.ApplyPatternsOp(sequence.bodyTarget).patterns):
+ structured.apply_patterns_linalg_erase_unused_operands_and_results()
+ transform.YieldOp()
+ # CHECK-LABEL: TEST: testApplyLinalgEraseUnusedOperandsAndResultsPattern
+ # CHECK: transform.apply_patterns.linalg.erase_unused_operands_and_results
+
+
@run
def testReplicateOp(module: Module):
with_pdl = transform_pdl.WithPDLPatternsOp(transform.AnyOpType.get())
>From c8fcbdd8330489ef5d31ad209793dd4216549b79 Mon Sep 17 00:00:00 2001
From: Tuomas Karna <tuomas.karna at intel.com>
Date: Wed, 23 Sep 2026 21:00:07 +0300
Subject: [PATCH 2/4] formatting
---
.../Linalg/transform-op-erase-unused-operands-and-results.mlir | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir b/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir
index ed47329e197a1c..bd6d8399ba73bf 100644
--- a/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir
+++ b/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir
@@ -10,11 +10,12 @@ func.func @remove_deadargs_generic_basic(%arg0: tensor<?xf32>) -> (tensor<?xf32>
%3 = linalg.generic {indexing_maps = [#map0, #map0, #map0], iterator_types=["parallel"]} ins(%arg0, %1 : tensor<?xf32>, tensor<?xf32>) outs (%2:tensor<?xf32>) {
^bb0(%arg1: f32, %arg2: f32, %arg3: f32):
%4 = arith.addf %arg1, %cst : f32
- linalg.yield %4 : f32
+ linalg.yield %4 : f32
} -> tensor<?xf32>
return %3 : tensor<?xf32>
}
+
module attributes {transform.with_named_sequence} {
transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
%f = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op
>From 4848afc3a614c824d827125cbf5937427cd1ec19 Mon Sep 17 00:00:00 2001
From: Tuomas Karna <tuomas.karna at intel.com>
Date: Thu, 24 Sep 2026 20:20:28 +0300
Subject: [PATCH 3/4] run transform op tests in the same
erase-unused-operands-and-results.mlir file
---
.../erase-unused-operands-and-results.mlir | 3 ++
.../td/erase-unused-operands-and-results.mlir | 11 +++++++
...-op-erase-unused-operands-and-results.mlir | 33 -------------------
3 files changed, 14 insertions(+), 33 deletions(-)
create mode 100644 mlir/test/Dialect/Linalg/td/erase-unused-operands-and-results.mlir
delete mode 100644 mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir
diff --git a/mlir/test/Dialect/Linalg/erase-unused-operands-and-results.mlir b/mlir/test/Dialect/Linalg/erase-unused-operands-and-results.mlir
index ff2bb0e1d24b7c..4dc10a5fde1874 100644
--- a/mlir/test/Dialect/Linalg/erase-unused-operands-and-results.mlir
+++ b/mlir/test/Dialect/Linalg/erase-unused-operands-and-results.mlir
@@ -1,4 +1,7 @@
// RUN: mlir-opt %s -split-input-file -test-linalg-transform-patterns=test-erase-unused-operands-and-results | FileCheck %s
+// RUN: mlir-opt %s -split-input-file \
+// RUN: -transform-preload-library='transform-library-paths=%p/td/erase-unused-operands-and-results.mlir' \
+// RUN: -transform-interpreter=entry-point=erase_unused_operands_and_results | FileCheck %s
// RUN: mlir-opt %s -split-input-file -test-linalg-transform-patterns=test-erase-unnecessary-inputs | FileCheck %s --check-prefix=CHECK-INPUT
// CHECK-LABEL: func @remove_deadargs_generic_basic
diff --git a/mlir/test/Dialect/Linalg/td/erase-unused-operands-and-results.mlir b/mlir/test/Dialect/Linalg/td/erase-unused-operands-and-results.mlir
new file mode 100644
index 00000000000000..99324e9ed5e3b0
--- /dev/null
+++ b/mlir/test/Dialect/Linalg/td/erase-unused-operands-and-results.mlir
@@ -0,0 +1,11 @@
+module @transforms attributes { transform.with_named_sequence } {
+ transform.named_sequence @erase_unused_operands_and_results(%module: !transform.any_op {transform.readonly}) {
+ %func = transform.structured.match ops{["func.func"]} in %module : (!transform.any_op) -> !transform.any_op
+
+ transform.apply_patterns to %func {
+ transform.apply_patterns.linalg.erase_unused_operands_and_results
+ } : !transform.any_op
+
+ transform.yield
+ }
+}
diff --git a/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir b/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir
deleted file mode 100644
index bd6d8399ba73bf..00000000000000
--- a/mlir/test/Dialect/Linalg/transform-op-erase-unused-operands-and-results.mlir
+++ /dev/null
@@ -1,33 +0,0 @@
-// RUN: mlir-opt %s -transform-interpreter | FileCheck %s
-
-#map0 = affine_map<(d0) -> (d0)>
-func.func @remove_deadargs_generic_basic(%arg0: tensor<?xf32>) -> (tensor<?xf32>) {
- %c0 = arith.constant 0 : index
- %cst = arith.constant 7.0 : f32
- %0 = tensor.dim %arg0, %c0 : tensor<?xf32>
- %1 = tensor.empty(%0) : tensor<?xf32>
- %2 = tensor.empty(%0) : tensor<?xf32>
- %3 = linalg.generic {indexing_maps = [#map0, #map0, #map0], iterator_types=["parallel"]} ins(%arg0, %1 : tensor<?xf32>, tensor<?xf32>) outs (%2:tensor<?xf32>) {
- ^bb0(%arg1: f32, %arg2: f32, %arg3: f32):
- %4 = arith.addf %arg1, %cst : f32
- linalg.yield %4 : f32
- } -> tensor<?xf32>
- return %3 : tensor<?xf32>
-}
-
-
-module attributes {transform.with_named_sequence} {
- transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
- %f = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op
- transform.apply_patterns to %f {
- transform.apply_patterns.linalg.erase_unused_operands_and_results
- } : !transform.any_op
- transform.yield
- }
-}
-
-// CHECK-LABEL: func @remove_deadargs_generic_basic
-// CHECK-SAME: (%[[ARG0:.*]]: tensor<?xf32>) -> tensor<?xf32> {
-// CHECK: %[[GENERIC_OP:.*]] = linalg.generic
-// CHECK-SAME: ins(%[[ARG0]] : tensor<?xf32>)
-// CHECK-SAME: outs({{.*}} : tensor<?xf32>) {
>From e846d44979664b023ffdd5c1c77c924c9b75c009 Mon Sep 17 00:00:00 2001
From: Tuomas Karna <tuomas.karna at intel.com>
Date: Fri, 25 Sep 2026 16:50:22 +0300
Subject: [PATCH 4/4] Unify swap-extract-slice-with-fill tests in a similar way
---
.../Linalg/swap-extract-slice-with-fill.mlir | 5 +++-
.../td/swap-extract-slice-with-fill.mlir | 11 ++++++++
...sform-op-swap-extract-slice-with-fill.mlir | 25 -------------------
3 files changed, 15 insertions(+), 26 deletions(-)
create mode 100644 mlir/test/Dialect/Linalg/td/swap-extract-slice-with-fill.mlir
delete mode 100644 mlir/test/Dialect/Linalg/transform-op-swap-extract-slice-with-fill.mlir
diff --git a/mlir/test/Dialect/Linalg/swap-extract-slice-with-fill.mlir b/mlir/test/Dialect/Linalg/swap-extract-slice-with-fill.mlir
index 03093016287142..a49f177d06b0f6 100644
--- a/mlir/test/Dialect/Linalg/swap-extract-slice-with-fill.mlir
+++ b/mlir/test/Dialect/Linalg/swap-extract-slice-with-fill.mlir
@@ -1,4 +1,7 @@
-//RUN: mlir-opt -split-input-file -test-linalg-transform-patterns=test-swap-extract-slice-with-fill-pattern %s | FileCheck %s
+// RUN: mlir-opt %s -split-input-file -test-linalg-transform-patterns=test-swap-extract-slice-with-fill-pattern | FileCheck %s
+// RUN: mlir-opt %s -split-input-file \
+// RUN: -transform-preload-library='transform-library-paths=%p/td/swap-extract-slice-with-fill.mlir' \
+// RUN: -transform-interpreter=entry-point=swap_extract_slice_with_fill | FileCheck %s
// CHECK-LABEL: func.func @swap_fill_insert_slice
// CHECK-SAME: (%[[INIT:.+]]: tensor<?x?x?xf32>, %[[OFFSET0:.+]]: index, %[[SIZE1:.+]]: index)
diff --git a/mlir/test/Dialect/Linalg/td/swap-extract-slice-with-fill.mlir b/mlir/test/Dialect/Linalg/td/swap-extract-slice-with-fill.mlir
new file mode 100644
index 00000000000000..00e08f1ce2183c
--- /dev/null
+++ b/mlir/test/Dialect/Linalg/td/swap-extract-slice-with-fill.mlir
@@ -0,0 +1,11 @@
+module @transforms attributes { transform.with_named_sequence } {
+ transform.named_sequence @swap_extract_slice_with_fill(%module: !transform.any_op {transform.readonly}) {
+ %func = transform.structured.match ops{["func.func"]} in %module : (!transform.any_op) -> !transform.any_op
+
+ transform.apply_patterns to %func {
+ transform.apply_patterns.linalg.swap_extract_slice_with_fill
+ } : !transform.any_op
+
+ transform.yield
+ }
+}
diff --git a/mlir/test/Dialect/Linalg/transform-op-swap-extract-slice-with-fill.mlir b/mlir/test/Dialect/Linalg/transform-op-swap-extract-slice-with-fill.mlir
deleted file mode 100644
index c4d2cec5e50345..00000000000000
--- a/mlir/test/Dialect/Linalg/transform-op-swap-extract-slice-with-fill.mlir
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: mlir-opt %s -transform-interpreter | FileCheck %s
-
-func.func @swap_fill_extract_slice(%init : tensor<?x?x?xf32>, %offset0: index, %size1: index) -> tensor<?x6xf32> {
- %f0 = arith.constant 0.000000e+00 : f32
- %0 = linalg.fill ins(%f0 : f32) outs(%init : tensor<?x?x?xf32>) -> tensor<?x?x?xf32>
- %1 = tensor.extract_slice %0[%offset0, 8, 4] [1, %size1, 6] [1, 3, 1]
- : tensor<?x?x?xf32> to tensor<?x6xf32>
- return %1: tensor<?x6xf32>
-}
-
-module attributes {transform.with_named_sequence} {
- transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
- %f = transform.structured.match ops{["func.func"]} in %arg0 : (!transform.any_op) -> !transform.any_op
- transform.apply_patterns to %f {
- transform.apply_patterns.linalg.swap_extract_slice_with_fill
- } : !transform.any_op
- transform.yield
- }
-}
-
-// CHECK-LABEL: func.func @swap_fill_extract_slice
-// CHECK: %[[F0:.*]] = arith.constant 0.000000e+00 : f32
-// CHECK: %[[EXT:.*]] = tensor.extract_slice %{{.*}}[%{{.*}}, 8, 4] [1, %{{.*}}, 6] [1, 3, 1]
-// CHECK: %[[FILL:.*]] = linalg.fill ins(%[[F0]] : f32) outs(%[[EXT]] : tensor<?x6xf32>) -> tensor<?x6xf32>
-// CHECK: return %[[FILL]] : tensor<?x6xf32>
More information about the Mlir-commits
mailing list