[Mlir-commits] [mlir] [MLIR][Rewrite] Support unqualified pattern names in disable/enable-patterns (PR #188988)
Mehdi Amini
llvmlistbot at llvm.org
Wed Apr 22 06:59:03 PDT 2026
https://github.com/joker-eph updated https://github.com/llvm/llvm-project/pull/188988
>From 38b2f8d84896e684786ca3464bf9e0b14fa90c71 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 | 34 ++++++++++++++-----
.../Transforms/test-canonicalize-filter.mlir | 29 ++++++++++++++++
2 files changed, 55 insertions(+), 8 deletions(-)
diff --git a/mlir/lib/Rewrite/FrozenRewritePatternSet.cpp b/mlir/lib/Rewrite/FrozenRewritePatternSet.cpp
index d4cd24372efbc..65ee7b91ddba3 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,42 @@ FrozenRewritePatternSet::FrozenRewritePatternSet(
impl->nativeOpSpecificPatternList.push_back(std::move(pattern));
};
+ // Returns true if `label` (a pattern's debug name or one of its debug
+ // labels) matches any entry in `userLabels`. A user label matches on exact
+ // string equality; additionally, a user label that does not contain "::"
+ // matches against the suffix of `label` after its last "::", so users can
+ // write e.g. `disable-patterns=FooBar` instead of
+ // `disable-patterns=(anonymous namespace)::FooBar`. Note: an unqualified
+ // user label matches *any* pattern whose unqualified name is the same,
+ // regardless of namespace.
+ auto matchesAnyUserLabel = [](StringRef label,
+ ArrayRef<std::string> userLabels) {
+ size_t pos = label.rfind("::");
+ StringRef unqualified =
+ (pos == StringRef::npos) ? label : label.substr(pos + 2);
+ for (StringRef ul : userLabels) {
+ if (label == ul)
+ return true;
+ if (!ul.contains("::") && unqualified == ul)
+ 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 matchesAnyUserLabel(label, enabledPatternLabels);
};
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 matchesAnyUserLabel(label, disabledPatternLabels);
};
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..a61ebc2bbae8b 100644
--- a/mlir/test/Transforms/test-canonicalize-filter.mlir
+++ b/mlir/test/Transforms/test-canonicalize-filter.mlir
@@ -1,6 +1,15 @@
// 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
+// 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
+// A label containing "::" is treated as qualified and requires exact match;
+// a wrong-namespace suffix must NOT accidentally match.
+// RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(canonicalize{disable-patterns=foo::FoldToCallOpPattern}))' | FileCheck %s --check-prefix=NO_FILTER
+// A non-existent label is a no-op (no pattern gets disabled).
+// RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(canonicalize{disable-patterns=DoesNotExist}))' | FileCheck %s --check-prefix=NO_FILTER
+// Mixing multiple labels (both unqualified) in one list.
+// RUN: mlir-opt %s -pass-pipeline='builtin.module(func.func(canonicalize{disable-patterns=FoldToCallOpPattern,TestRemoveOpWithInnerOps}))' | FileCheck %s --check-prefix=DISABLE_BOTH
// NO_FILTER-LABEL: func @remove_op_with_inner_ops_pattern
// NO_FILTER-NEXT: return
@@ -8,9 +17,29 @@
// FILTER_ENABLE-NEXT: return
// FILTER_DISABLE-LABEL: func @remove_op_with_inner_ops_pattern
// FILTER_DISABLE-NEXT: "test.op_with_region_pattern"()
+// DISABLE_BOTH-LABEL: func @remove_op_with_inner_ops_pattern
+// DISABLE_BOTH-NEXT: "test.op_with_region_pattern"()
func.func @remove_op_with_inner_ops_pattern() {
"test.op_with_region_pattern"() ({
"test.op_with_region_terminator"() : () -> ()
}) : () -> ()
return
}
+
+// FoldToCallOpPattern lives in an anonymous namespace; its debug name is
+// "(anonymous namespace)::FoldToCallOpPattern". Unqualified filter labels
+// match against the suffix 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"
+// DISABLE_BOTH-LABEL: func @fold_to_call_unqualified_filter
+// DISABLE_BOTH-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