[Mlir-commits] [mlir] [mlir][Rewrite] Add match failure/success diagnostics to `PatternApplicator` (PR #180165)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Feb 6 03:00:33 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Matthias Springer (matthias-springer)

<details>
<summary>Changes</summary>

It is a best practice to write "negative" test cases to check that a (canonicalization) does not accidentally apply to IR where it should not match. To that end, users have to FileCheck for the original IR to make sure that no pattern was applied.

This commit adds a new testing flag to `mlir-opt`: `-mlir-emit-pattern-match-diagnostics="match-success"` emits a diagnostic remark for every successful pattern application. Together with `-verify-diagnostics`, this flag can be used to ensure that no pattern was applied to a certain piece of IR.

Note: This flag was motivated by a test case pattern that I found in a downstream project:
```
// RUN: mlir-opt -split-input-file %s -canonicalize -debug 2>&1 | FileCheck %s
// CHECK: Trying to match "(pattern name)"
// CHECK-NEXT: matchAndRewrite failed
```


---
Full diff: https://github.com/llvm/llvm-project/pull/180165.diff


4 Files Affected:

- (modified) mlir/include/mlir/Rewrite/PatternApplicator.h (+3) 
- (modified) mlir/lib/Rewrite/PatternApplicator.cpp (+55) 
- (modified) mlir/lib/Tools/mlir-opt/MlirOptMain.cpp (+2) 
- (added) mlir/test/Rewrite/test-pattern-applicator-diagnostics.mlir (+10) 


``````````diff
diff --git a/mlir/include/mlir/Rewrite/PatternApplicator.h b/mlir/include/mlir/Rewrite/PatternApplicator.h
index f7871f819a273..0fb00154a67b7 100644
--- a/mlir/include/mlir/Rewrite/PatternApplicator.h
+++ b/mlir/include/mlir/Rewrite/PatternApplicator.h
@@ -96,6 +96,9 @@ class PatternApplicator {
   std::unique_ptr<detail::PDLByteCodeMutableState> mutableByteCodeState;
 };
 
+/// Register command-line options for the pattern applicator.
+void registerPatternApplicatorCLOptions();
+
 } // namespace mlir
 
 #endif // MLIR_REWRITE_PATTERNAPPLICATOR_H
diff --git a/mlir/lib/Rewrite/PatternApplicator.cpp b/mlir/lib/Rewrite/PatternApplicator.cpp
index e1b56fd6efda0..1d64dc2df1706 100644
--- a/mlir/lib/Rewrite/PatternApplicator.cpp
+++ b/mlir/lib/Rewrite/PatternApplicator.cpp
@@ -13,7 +13,10 @@
 
 #include "mlir/Rewrite/PatternApplicator.h"
 #include "ByteCode.h"
+#include "mlir/IR/Diagnostics.h"
+#include "llvm/Support/CommandLine.h"
 #include "llvm/Support/DebugLog.h"
+#include "llvm/Support/ManagedStatic.h"
 
 #ifndef NDEBUG
 #include "llvm/ADT/ScopeExit.h"
@@ -24,6 +27,41 @@
 using namespace mlir;
 using namespace mlir::detail;
 
+namespace {
+enum PatternMatchingRemarkMode {
+  /// Do not emit any diagnostic remarks for pattern matching.
+  None,
+  /// Emit a remark for successful pattern matching.
+  MatchSuccess,
+  /// Emit a remark for failed pattern matching.
+  MatchFailure,
+  /// Emit a remark for both successful and failed pattern matching.
+  MatchSuccessAndFailure,
+};
+struct PatternApplicatorOptions {
+  llvm::cl::opt<PatternMatchingRemarkMode> mode{
+      "mlir-emit-pattern-match-diagnostics",
+      llvm::cl::desc("Emit diagnostic remarks for pattern matching"),
+      llvm::cl::init(PatternMatchingRemarkMode::None), // default value
+      llvm::cl::values(
+          clEnumValN(PatternMatchingRemarkMode::None, "none", "no remarks"),
+          clEnumValN(PatternMatchingRemarkMode::MatchSuccess, "match-success",
+                     "pattern match success"),
+          clEnumValN(PatternMatchingRemarkMode::MatchFailure, "match-failure",
+                     "pattern match failure"),
+          clEnumValN(PatternMatchingRemarkMode::MatchSuccessAndFailure,
+                     "match-success-and-failure",
+                     "pattern match success and failure"))};
+};
+} // namespace
+
+static llvm::ManagedStatic<PatternApplicatorOptions> clOptions;
+
+void mlir::registerPatternApplicatorCLOptions() {
+  // Make sure that the options struct has been initialized.
+  *clOptions;
+}
+
 PatternApplicator::PatternApplicator(
     const FrozenRewritePatternSet &frozenPatternList)
     : frozenPatternList(frozenPatternList) {
@@ -220,9 +258,26 @@ LogicalResult PatternApplicator::matchAndRewrite(
             llvm::scope_exit resetListenerCallback(
                 [&] { rewriter.setListener(oldListener); });
 #endif
+            Location loc = op->getLoc();
             result = pattern->matchAndRewrite(op, rewriter);
             LDBG() << " -> matchAndRewrite "
                    << (succeeded(result) ? "successful" : "failed");
+            bool shouldEmitMatchSuccessRemark =
+                clOptions->mode == PatternMatchingRemarkMode::MatchSuccess ||
+                clOptions->mode ==
+                    PatternMatchingRemarkMode::MatchSuccessAndFailure;
+            bool shouldEmitMatchFailureRemark =
+                clOptions->mode == PatternMatchingRemarkMode::MatchFailure ||
+                clOptions->mode ==
+                    PatternMatchingRemarkMode::MatchSuccessAndFailure;
+            if (succeeded(result) && shouldEmitMatchSuccessRemark) {
+              mlir::emitRemark(loc)
+                  << "pattern match success: " << pattern->getDebugName();
+            }
+            if (failed(result) && shouldEmitMatchFailureRemark) {
+              mlir::emitRemark(loc)
+                  << "pattern match failure: " << pattern->getDebugName();
+            }
           }
 
           // Process the result of the pattern application.
diff --git a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
index 560ef6effd2fb..4d03ae66dbea2 100644
--- a/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
+++ b/mlir/lib/Tools/mlir-opt/MlirOptMain.cpp
@@ -28,6 +28,7 @@
 #include "mlir/Pass/PassManager.h"
 #include "mlir/Pass/PassRegistry.h"
 #include "mlir/Remark/RemarkStreamer.h"
+#include "mlir/Rewrite/PatternApplicator.h"
 #include "mlir/Support/FileUtilities.h"
 #include "mlir/Support/Timing.h"
 #include "mlir/Support/ToolUtilities.h"
@@ -688,6 +689,7 @@ std::string mlir::registerCLIOptions(llvm::StringRef toolName,
   registerMLIRContextCLOptions();
   registerPassManagerCLOptions();
   registerDefaultTimingManagerCLOptions();
+  registerPatternApplicatorCLOptions();
   tracing::DebugCounter::registerCLOptions();
 
   // Build the list of dialects as a header for the --help message.
diff --git a/mlir/test/Rewrite/test-pattern-applicator-diagnostics.mlir b/mlir/test/Rewrite/test-pattern-applicator-diagnostics.mlir
new file mode 100644
index 0000000000000..77cc465db323b
--- /dev/null
+++ b/mlir/test/Rewrite/test-pattern-applicator-diagnostics.mlir
@@ -0,0 +1,10 @@
+// RUN: mlir-opt %s -canonicalize -mlir-emit-pattern-match-diagnostics="match-success"
+
+func.func @tensor_empty_canonicalization() -> tensor<?xf32> {
+  %c4 = arith.constant 4 : index
+  // Do not match "(anonymous namespace)::", as it may render differently
+  // depending on the C++ compiler.
+  // expected-remark-re @+1 {{pattern match success: {{.*}}ReplaceEmptyTensorStaticShapeDims}}
+  %r = tensor.empty(%c4) : tensor<?xf32>
+  return %r : tensor<?xf32>
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/180165


More information about the Mlir-commits mailing list