[Mlir-commits] [mlir] 7caf12d - [mlir][core] Add an MLIR "pattern catalog" generator (#146228)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Jul 17 09:09:16 PDT 2025
Author: Jeremy Kun
Date: 2025-07-17T09:09:12-07:00
New Revision: 7caf12da0bb09d6b6992bf42afd256d453753dcb
URL: https://github.com/llvm/llvm-project/commit/7caf12da0bb09d6b6992bf42afd256d453753dcb
DIFF: https://github.com/llvm/llvm-project/commit/7caf12da0bb09d6b6992bf42afd256d453753dcb.diff
LOG: [mlir][core] Add an MLIR "pattern catalog" generator (#146228)
This PR adds a feature that attaches a listener to all RewritePatterns that
logs information about the modified operations.
When the MLIR test suite is run, these debug outputs can
be filtered and combined into an index linking operations to the
patterns that insert, modify, or replace them. This index is intended to
be used to create a website that allows one to look up patterns from an
operation name.
The debug logs emitted can be viewed with --debug-only=generate-pattern-catalog,
and the lit config is modified to do this when the env var MLIR_GENERATE_PATTERN_CATALOG is set.
Example usage:
```
mkdir build && cd build
cmake -G Ninja ../llvm \
-DLLVM_ENABLE_PROJECTS="mlir" \
-DLLVM_TARGETS_TO_BUILD="host" \
-DCMAKE_BUILD_TYPE=DEBUG
ninja -j 24 check-mlir
MLIR_GENERATE_PATTERN_CATALOG=1 bin/llvm-lit -j 24 -v -a tools/mlir/test | grep 'pattern-logging-listener' | sed 's/^# | [pattern-logging-listener] //g' | sort | uniq > pattern_catalog.txt
```
Sample pattern catalog output (that fits in a gist):
https://gist.github.com/j2kun/02d1ab8d31c10d71027724984c89905a
---------
Co-authored-by: Jeremy Kun <j2kun at users.noreply.github.com>
Co-authored-by: Mehdi Amini <joker.eph at gmail.com>
Added:
mlir/lib/IR/PatternLoggingListener.cpp
mlir/test/IR/test-pattern-logging-listener.mlir
Modified:
mlir/include/mlir/IR/PatternMatch.h
mlir/lib/IR/CMakeLists.txt
mlir/lib/Rewrite/PatternApplicator.cpp
mlir/test/lit.cfg.py
Removed:
################################################################################
diff --git a/mlir/include/mlir/IR/PatternMatch.h b/mlir/include/mlir/IR/PatternMatch.h
index afeb784b85a12..3a2dbd136b438 100644
--- a/mlir/include/mlir/IR/PatternMatch.h
+++ b/mlir/include/mlir/IR/PatternMatch.h
@@ -475,6 +475,25 @@ class RewriterBase : public OpBuilder {
RewriterBase::Listener *rewriteListener;
};
+ /// A listener that logs notification events to llvm::dbgs() before
+ /// forwarding to the base listener.
+ struct PatternLoggingListener : public RewriterBase::ForwardingListener {
+ PatternLoggingListener(OpBuilder::Listener *listener, StringRef patternName)
+ : RewriterBase::ForwardingListener(listener), patternName(patternName) {
+ }
+
+ void notifyOperationInserted(Operation *op, InsertPoint previous) override;
+ void notifyOperationModified(Operation *op) override;
+ void notifyOperationReplaced(Operation *op, Operation *newOp) override;
+ void notifyOperationReplaced(Operation *op,
+ ValueRange replacement) override;
+ void notifyOperationErased(Operation *op) override;
+ void notifyPatternBegin(const Pattern &pattern, Operation *op) override;
+
+ private:
+ StringRef patternName;
+ };
+
/// Move the blocks that belong to "region" before the given position in
/// another region "parent". The two regions must be
diff erent. The caller
/// is responsible for creating or updating the operation transferring flow
diff --git a/mlir/lib/IR/CMakeLists.txt b/mlir/lib/IR/CMakeLists.txt
index 4cabac185171c..3ef69cea18f0a 100644
--- a/mlir/lib/IR/CMakeLists.txt
+++ b/mlir/lib/IR/CMakeLists.txt
@@ -29,6 +29,7 @@ add_mlir_library(MLIRIR
ODSSupport.cpp
Operation.cpp
OperationSupport.cpp
+ PatternLoggingListener.cpp
PatternMatch.cpp
Region.cpp
RegionKindInterface.cpp
diff --git a/mlir/lib/IR/PatternLoggingListener.cpp b/mlir/lib/IR/PatternLoggingListener.cpp
new file mode 100644
index 0000000000000..ce2123ae1a19a
--- /dev/null
+++ b/mlir/lib/IR/PatternLoggingListener.cpp
@@ -0,0 +1,50 @@
+#include "mlir/IR/PatternMatch.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "pattern-logging-listener"
+#define DBGS() (llvm::dbgs() << "[" << DEBUG_TYPE << "] ")
+#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n")
+
+using namespace mlir;
+
+void RewriterBase::PatternLoggingListener::notifyOperationInserted(
+ Operation *op, InsertPoint previous) {
+ LDBG(patternName << " | notifyOperationInserted"
+ << " | " << op->getName());
+ ForwardingListener::notifyOperationInserted(op, previous);
+}
+
+void RewriterBase::PatternLoggingListener::notifyOperationModified(
+ Operation *op) {
+ LDBG(patternName << " | notifyOperationModified"
+ << " | " << op->getName());
+ ForwardingListener::notifyOperationModified(op);
+}
+
+void RewriterBase::PatternLoggingListener::notifyOperationReplaced(
+ Operation *op, Operation *newOp) {
+ LDBG(patternName << " | notifyOperationReplaced (with op)"
+ << " | " << op->getName() << " | " << newOp->getName());
+ ForwardingListener::notifyOperationReplaced(op, newOp);
+}
+
+void RewriterBase::PatternLoggingListener::notifyOperationReplaced(
+ Operation *op, ValueRange replacement) {
+ LDBG(patternName << " | notifyOperationReplaced (with values)"
+ << " | " << op->getName());
+ ForwardingListener::notifyOperationReplaced(op, replacement);
+}
+
+void RewriterBase::PatternLoggingListener::notifyOperationErased(
+ Operation *op) {
+ LDBG(patternName << " | notifyOperationErased"
+ << " | " << op->getName());
+ ForwardingListener::notifyOperationErased(op);
+}
+
+void RewriterBase::PatternLoggingListener::notifyPatternBegin(
+ const Pattern &pattern, Operation *op) {
+ LDBG(patternName << " | notifyPatternBegin"
+ << " | " << op->getName());
+ ForwardingListener::notifyPatternBegin(pattern, op);
+}
diff --git a/mlir/lib/Rewrite/PatternApplicator.cpp b/mlir/lib/Rewrite/PatternApplicator.cpp
index 4a12183492fd4..b2b372b7b1249 100644
--- a/mlir/lib/Rewrite/PatternApplicator.cpp
+++ b/mlir/lib/Rewrite/PatternApplicator.cpp
@@ -15,6 +15,10 @@
#include "ByteCode.h"
#include "llvm/Support/Debug.h"
+#ifndef NDEBUG
+#include "llvm/ADT/ScopeExit.h"
+#endif
+
#define DEBUG_TYPE "pattern-application"
using namespace mlir;
@@ -206,11 +210,19 @@ LogicalResult PatternApplicator::matchAndRewrite(
} else {
LLVM_DEBUG(llvm::dbgs() << "Trying to match \""
<< bestPattern->getDebugName() << "\"\n");
-
const auto *pattern =
static_cast<const RewritePattern *>(bestPattern);
- result = pattern->matchAndRewrite(op, rewriter);
+#ifndef NDEBUG
+ OpBuilder::Listener *oldListener = rewriter.getListener();
+ auto loggingListener =
+ std::make_unique<RewriterBase::PatternLoggingListener>(
+ oldListener, pattern->getDebugName());
+ rewriter.setListener(loggingListener.get());
+ auto resetListenerCallback = llvm::make_scope_exit(
+ [&] { rewriter.setListener(oldListener); });
+#endif
+ result = pattern->matchAndRewrite(op, rewriter);
LLVM_DEBUG(llvm::dbgs()
<< "\"" << bestPattern->getDebugName() << "\" result "
<< succeeded(result) << "\n");
diff --git a/mlir/test/IR/test-pattern-logging-listener.mlir b/mlir/test/IR/test-pattern-logging-listener.mlir
new file mode 100644
index 0000000000000..a1d27741a0723
--- /dev/null
+++ b/mlir/test/IR/test-pattern-logging-listener.mlir
@@ -0,0 +1,17 @@
+// RUN: mlir-opt %s --test-walk-pattern-rewrite-driver \
+// RUN: --allow-unregistered-dialect --debug-only=pattern-logging-listener 2>&1 | FileCheck %s
+
+// Check that when replacing an op with a new op, we get appropriate
+// pattern-logging lines. The regex is because the anonymous namespace is
+// printed
diff erently on
diff erent platforms.
+
+// CHECK: [pattern-logging-listener] {{.anonymous.namespace.}}::ReplaceWithNewOp | notifyOperationInserted | test.new_op
+// CHECK: [pattern-logging-listener] {{.anonymous.namespace.}}::ReplaceWithNewOp | notifyOperationReplaced (with values) | test.replace_with_new_op
+// CHECK: [pattern-logging-listener] {{.anonymous.namespace.}}::ReplaceWithNewOp | notifyOperationModified | arith.addi
+// CHECK: [pattern-logging-listener] {{.anonymous.namespace.}}::ReplaceWithNewOp | notifyOperationModified | arith.addi
+// CHECK: [pattern-logging-listener] {{.anonymous.namespace.}}::ReplaceWithNewOp | notifyOperationErased | test.replace_with_new_op
+func.func @replace_with_new_op() -> i32 {
+ %a = "test.replace_with_new_op"() : () -> (i32)
+ %res = arith.addi %a, %a : i32
+ return %res : i32
+}
diff --git a/mlir/test/lit.cfg.py b/mlir/test/lit.cfg.py
index 9b5cadd62befc..233fef8ec4296 100644
--- a/mlir/test/lit.cfg.py
+++ b/mlir/test/lit.cfg.py
@@ -301,6 +301,17 @@ def find_real_python_interpreter():
ToolSubst("mlir-opt", "mlir-opt --verify-roundtrip", unresolved="fatal"),
]
)
+elif "MLIR_GENERATE_PATTERN_CATALOG" in os.environ:
+ tools.extend(
+ [
+ ToolSubst(
+ "mlir-opt",
+ "mlir-opt --debug-only=pattern-logging-listener --mlir-disable-threading",
+ unresolved="fatal",
+ ),
+ ToolSubst("FileCheck", "FileCheck --dump-input=always", unresolved="fatal"),
+ ]
+ )
else:
tools.extend(["mlir-opt"])
More information about the Mlir-commits
mailing list