[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:39:29 PDT 2026
https://github.com/joker-eph updated https://github.com/llvm/llvm-project/pull/188988
>From f1b75d1d3bcece49e6d4c7efd6b3f20fa0c3a06e 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 | 55 ++++++++++++++++---
.../Transforms/test-canonicalize-filter.mlir | 23 ++++++++
2 files changed, 70 insertions(+), 8 deletions(-)
diff --git a/mlir/lib/Rewrite/FrozenRewritePatternSet.cpp b/mlir/lib/Rewrite/FrozenRewritePatternSet.cpp
index d4cd24372efbc..2c1d4635cb235 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,63 @@ FrozenRewritePatternSet::FrozenRewritePatternSet(
impl->nativeOpSpecificPatternList.push_back(std::move(pattern));
};
+ // Pre-compute for each user-supplied filter label whether it is qualified
+ // (contains "::"). Unqualified labels additionally match against the
+ // suffix of a pattern's debug name after its last "::", allowing users to
+ // write, e.g., `disable-patterns=FooBar` instead of
+ // `disable-patterns=(anonymous namespace)::FooBar`.
+ auto computeQualifiedFlags = [](ArrayRef<std::string> labels) {
+ SmallVector<bool> flags;
+ flags.reserve(labels.size());
+ for (StringRef ul : labels)
+ flags.push_back(ul.contains("::"));
+ return flags;
+ };
+ SmallVector<bool> enabledQualified =
+ computeQualifiedFlags(enabledPatternLabels);
+ SmallVector<bool> disabledQualified =
+ computeQualifiedFlags(disabledPatternLabels);
+
+ // Returns true if `label` (a pattern's debug name or label) matches
+ // `userLabel`. If `userLabelQualified` is false, also match `userLabel`
+ // against the unqualified part of `label` (after the last "::").
+ auto matchesLabel = [](StringRef label, StringRef userLabel,
+ bool userLabelQualified) {
+ if (label == userLabel)
+ return true;
+ if (!userLabelQualified) {
+ size_t pos = label.rfind("::");
+ if (pos != StringRef::npos && label.substr(pos + 2) == userLabel)
+ return true;
+ }
+ return false;
+ };
+
+ auto anyUserLabelMatches = [&](StringRef label,
+ ArrayRef<std::string> userLabels,
+ ArrayRef<bool> qualifiedFlags) {
+ for (auto [ul, qualified] : llvm::zip_equal(userLabels, qualifiedFlags))
+ if (matchesLabel(label, ul, qualified))
+ 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 anyUserLabelMatches(label, enabledPatternLabels,
+ enabledQualified);
};
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 anyUserLabelMatches(label, disabledPatternLabels,
+ disabledQualified);
};
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