[Mlir-commits] [mlir] [MLIR][Rewrite] Support unqualified pattern names in disable/enable-patterns (PR #188988)

Mehdi Amini llvmlistbot at llvm.org
Fri Mar 27 05:59:17 PDT 2026


https://github.com/joker-eph created https://github.com/llvm/llvm-project/pull/188988

FrozenRewritePatternSet previously required exact string matching for disable-patterns and enable-patterns filter options. Pattern debug names are auto-generated as fully qualified typenames (e.g., "(anonymous namespace)::FooBar"), but users often want to filter by just the class name (e.g., "FooBar").

This change adds support for unqualified name matching: if a user-supplied filter label contains no "::", it is also matched against the unqualified part of the pattern debug name (the suffix after the last "::"). Labels containing "::" still require exact matching as before.

A new test exercises disable/enable filtering by unqualified name for a pattern living in an anonymous namespace.

Fixes #120489

Assisted-by: Claude Code

>From 7af34054d969704c21c1a1d6d62b65fb945c8d07 Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Thu, 26 Mar 2026 16:03:22 -0700
Subject: [PATCH] [MLIR][Rewrite] Support unqualified pattern names in
 disable/enable-patterns

FrozenRewritePatternSet previously required exact string matching for
disable-patterns and enable-patterns filter options. Pattern debug names
are auto-generated as fully qualified typenames (e.g.,
"(anonymous namespace)::FooBar"), but users often want to filter by just
the class name (e.g., "FooBar").

This change adds support for unqualified name matching: if a user-supplied
filter label contains no "::", it is also matched against the unqualified
part of the pattern debug name (the suffix after the last "::"). Labels
containing "::" still require exact matching as before.

A new test exercises disable/enable filtering by unqualified name for a
pattern living in an anonymous namespace.

Fixes #120489

Assisted-by: Claude Code
---
 mlir/lib/Rewrite/FrozenRewritePatternSet.cpp  | 33 ++++++++++++++-----
 .../Transforms/test-canonicalize-filter.mlir  | 23 +++++++++++++
 2 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/mlir/lib/Rewrite/FrozenRewritePatternSet.cpp b/mlir/lib/Rewrite/FrozenRewritePatternSet.cpp
index d4cd24372efbc..14a05d0f27b6c 100644
--- a/mlir/lib/Rewrite/FrozenRewritePatternSet.cpp
+++ b/mlir/lib/Rewrite/FrozenRewritePatternSet.cpp
@@ -64,10 +64,6 @@ FrozenRewritePatternSet::FrozenRewritePatternSet(
     RewritePatternSet &&patterns, ArrayRef<std::string> disabledPatternLabels,
     ArrayRef<std::string> enabledPatternLabels)
     : impl(std::make_shared<Impl>()) {
-  DenseSet<StringRef> disabledPatterns, enabledPatterns;
-  disabledPatterns.insert_range(disabledPatternLabels);
-  enabledPatterns.insert_range(enabledPatternLabels);
-
   // Functor used to walk all of the operations registered in the context. This
   // is useful for patterns that get applied to multiple operations, such as
   // interface and trait based patterns.
@@ -83,20 +79,41 @@ FrozenRewritePatternSet::FrozenRewritePatternSet(
         impl->nativeOpSpecificPatternList.push_back(std::move(pattern));
       };
 
+  // Returns true if `label` (a pattern's debug name or label) matches
+  // `userLabel` (a user-supplied filter string). Supports both exact matching
+  // and unqualified-name matching: if `userLabel` contains no "::", it is also
+  // compared against the unqualified part of `label` (after the last "::").
+  // This allows users to write, e.g., `disable-patterns=FooBar` instead of
+  // `disable-patterns=(anonymous namespace)::FooBar`.
+  auto matchesLabel = [](StringRef label, StringRef userLabel) {
+    if (label == userLabel)
+      return true;
+    if (!userLabel.contains("::")) {
+      size_t pos = label.rfind("::");
+      if (pos != StringRef::npos && label.substr(pos + 2) == userLabel)
+        return true;
+    }
+    return false;
+  };
+
   for (std::unique_ptr<RewritePattern> &pat : patterns.getNativePatterns()) {
     // Don't add patterns that haven't been enabled by the user.
-    if (!enabledPatterns.empty()) {
+    if (!enabledPatternLabels.empty()) {
       auto isEnabledFn = [&](StringRef label) {
-        return enabledPatterns.count(label);
+        return llvm::any_of(enabledPatternLabels, [&](StringRef ul) {
+          return matchesLabel(label, ul);
+        });
       };
       if (!isEnabledFn(pat->getDebugName()) &&
           llvm::none_of(pat->getDebugLabels(), isEnabledFn))
         continue;
     }
     // Don't add patterns that have been disabled by the user.
-    if (!disabledPatterns.empty()) {
+    if (!disabledPatternLabels.empty()) {
       auto isDisabledFn = [&](StringRef label) {
-        return disabledPatterns.count(label);
+        return llvm::any_of(disabledPatternLabels, [&](StringRef ul) {
+          return matchesLabel(label, ul);
+        });
       };
       if (isDisabledFn(pat->getDebugName()) ||
           llvm::any_of(pat->getDebugLabels(), isDisabledFn))
diff --git a/mlir/test/Transforms/test-canonicalize-filter.mlir b/mlir/test/Transforms/test-canonicalize-filter.mlir
index dba5f05e84345..ad1784e9e5cb4 100644
--- a/mlir/test/Transforms/test-canonicalize-filter.mlir
+++ b/mlir/test/Transforms/test-canonicalize-filter.mlir
@@ -1,6 +1,12 @@
 // RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(canonicalize))' | FileCheck %s --check-prefix=NO_FILTER
 // RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(canonicalize{enable-patterns=TestRemoveOpWithInnerOps}))' | FileCheck %s --check-prefix=FILTER_ENABLE
 // RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(canonicalize{disable-patterns=TestRemoveOpWithInnerOps}))' | FileCheck %s --check-prefix=FILTER_DISABLE
+// Test that unqualified names (without namespace prefix) also work for filtering.
+// FoldToCallOpPattern is in an anonymous namespace, so its debug name is
+// "(anonymous namespace)::FoldToCallOpPattern". Filtering by the unqualified
+// name "FoldToCallOpPattern" should still work.
+// RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(canonicalize{disable-patterns=FoldToCallOpPattern}))' | FileCheck %s --check-prefix=DISABLE_ANON
+// RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(canonicalize{enable-patterns=FoldToCallOpPattern}))' | FileCheck %s --check-prefix=ENABLE_ANON
 
 // NO_FILTER-LABEL: func @remove_op_with_inner_ops_pattern
 // NO_FILTER-NEXT: return
@@ -14,3 +20,20 @@ func.func @remove_op_with_inner_ops_pattern() {
   }) : () -> ()
   return
 }
+
+// Test filtering by unqualified pattern name (without namespace prefix).
+// FoldToCallOpPattern lives in an anonymous namespace; its debug name is
+// "(anonymous namespace)::FoldToCallOpPattern". Filters without "::" should
+// match against the unqualified part after the last "::".
+
+// NO_FILTER-LABEL: func @fold_to_call_unqualified_filter
+// NO_FILTER-NEXT: call @callee
+// DISABLE_ANON-LABEL: func @fold_to_call_unqualified_filter
+// DISABLE_ANON-NEXT: "test.fold_to_call_op"
+// ENABLE_ANON-LABEL: func @fold_to_call_unqualified_filter
+// ENABLE_ANON-NEXT: call @callee
+func.func private @callee()
+func.func @fold_to_call_unqualified_filter() {
+  "test.fold_to_call_op"() {callee = @callee} : () -> ()
+  return
+}



More information about the Mlir-commits mailing list