[Mlir-commits] [mlir] [MLIR][Remark] Expose RemarkEngine filter queries (PR #222262)
Guray Ozen
llvmlistbot at llvm.org
Wed Sep 9 01:04:22 PDT 2026
https://github.com/grypp created https://github.com/llvm/llvm-project/pull/222262
Expose following filter APIs publicly:
```
| Query | Answers |
|----------------------------------------------|------------------------------------------------------|
| `isAnyRemarkEnabled()` | At least one category filter is active |
| `isAnyRemarkEnabled(category)` | Some kind of remark is enabled for the category |
| `isRemarkEnabled(kind, category)` | Remarks of `kind` are enabled for the category |
| `is{Passed,Missed,Analysis,Failed}OptRemarkEnabled(category)` | Per-kind query |
```
>From 95265221cc1835d3fbfdc1a82e4bc97011f65e77 Mon Sep 17 00:00:00 2001
From: Guray Ozen <gozen at nvidia.com>
Date: Wed, 9 Sep 2026 10:02:40 +0200
Subject: [PATCH] [MLIR][Remark] Expose RemarkEngine filter queries
Expose filter apis publicly
---
mlir/docs/Remarks.md | 27 ++++++++
mlir/include/mlir/IR/Remarks.h | 63 ++++++++++++-------
mlir/lib/IR/Remarks.cpp | 17 +++++
mlir/unittests/IR/RemarkTest.cpp | 104 +++++++++++++++++++++++++++++++
4 files changed, 187 insertions(+), 24 deletions(-)
diff --git a/mlir/docs/Remarks.md b/mlir/docs/Remarks.md
index b44ec2cc3f055..43f5d4da12247 100644
--- a/mlir/docs/Remarks.md
+++ b/mlir/docs/Remarks.md
@@ -221,6 +221,33 @@ You can also implement custom policies by inheriting from the policy interface.
***
+## Querying Enabled Remarks
+
+A remark is only built when its kind and category match the configured
+filters. The `remark::passed`, `remark::missed`, `remark::failed` and
+`remark::analysis` helpers perform this check themselves, so passes do not need
+to do anything. Code that produces remarks from another source, for example a
+bridge that imports remarks from a different compiler, can ask the engine what
+is enabled before doing any work:
+
+```c++
+remark::detail::RemarkEngine *engine = context.getRemarkEngine();
+if (!engine || !engine->isAnyRemarkEnabled())
+ return; // No remark engine, or no category filter is active.
+
+if (engine->isRemarkEnabled(remark::RemarkKind::RemarkPassed, "Vectorizer"))
+ remark::passed(loc, opts) << "vectorized loop";
+```
+
+| Query | Answers |
+|----------------------------------------------|------------------------------------------------------|
+| `isAnyRemarkEnabled()` | At least one category filter is active |
+| `isAnyRemarkEnabled(category)` | Some kind of remark is enabled for the category |
+| `isRemarkEnabled(kind, category)` | Remarks of `kind` are enabled for the category |
+| `is{Passed,Missed,Analysis,Failed}OptRemarkEnabled(category)` | Per-kind query |
+
+***
+
## Enabling Remarks
### Option 1: LLVM Remark Streamer (YAML or Bitstream)
diff --git a/mlir/include/mlir/IR/Remarks.h b/mlir/include/mlir/IR/Remarks.h
index 5cfb888be44a2..81073efa4e026 100644
--- a/mlir/include/mlir/IR/Remarks.h
+++ b/mlir/include/mlir/IR/Remarks.h
@@ -515,30 +515,6 @@ class RemarkEngine {
/// Atomic counter for generating unique remark IDs.
std::atomic<uint64_t> nextRemarkId{1};
- /// Return true if missed optimization remarks are enabled, override
- /// to provide different implementation.
- bool isMissedOptRemarkEnabled(StringRef categoryName) const;
-
- /// Return true if passed optimization remarks are enabled, override
- /// to provide different implementation.
- bool isPassedOptRemarkEnabled(StringRef categoryName) const;
-
- /// Return true if analysis optimization remarks are enabled, override
- /// to provide different implementation.
- bool isAnalysisOptRemarkEnabled(StringRef categoryName) const;
-
- /// Return true if analysis optimization remarks are enabled, override
- /// to provide different implementation.
- bool isFailedOptRemarkEnabled(StringRef categoryName) const;
-
- /// Return true if any type of remarks are enabled for this pass.
- bool isAnyRemarkEnabled(StringRef categoryName) const {
- return isMissedOptRemarkEnabled(categoryName) ||
- isPassedOptRemarkEnabled(categoryName) ||
- isFailedOptRemarkEnabled(categoryName) ||
- isAnalysisOptRemarkEnabled(categoryName);
- }
-
/// Emit a remark using the given maker function, which should return
/// a Remark instance. The remark will be emitted using the main
/// remark streamer.
@@ -581,6 +557,45 @@ class RemarkEngine {
return RemarkId(nextRemarkId.fetch_add(1, std::memory_order_relaxed));
}
+ //===--------------------------------------------------------------------===//
+ // Remark Filtering - query which remarks are enabled
+ //===--------------------------------------------------------------------===//
+
+ /// Return true if missed optimization remarks are enabled for the given
+ /// category.
+ bool isMissedOptRemarkEnabled(StringRef categoryName) const;
+
+ /// Return true if passed optimization remarks are enabled for the given
+ /// category.
+ bool isPassedOptRemarkEnabled(StringRef categoryName) const;
+
+ /// Return true if analysis remarks are enabled for the given category.
+ bool isAnalysisOptRemarkEnabled(StringRef categoryName) const;
+
+ /// Return true if failed optimization remarks are enabled for the given
+ /// category.
+ bool isFailedOptRemarkEnabled(StringRef categoryName) const;
+
+ /// Return true if remarks of the given kind are enabled for the given
+ /// category. Always returns false for `RemarkKind::RemarkUnknown`.
+ bool isRemarkEnabled(RemarkKind kind, StringRef categoryName) const;
+
+ /// Return true if any kind of remark is enabled for the given category.
+ bool isAnyRemarkEnabled(StringRef categoryName) const {
+ return isMissedOptRemarkEnabled(categoryName) ||
+ isPassedOptRemarkEnabled(categoryName) ||
+ isFailedOptRemarkEnabled(categoryName) ||
+ isAnalysisOptRemarkEnabled(categoryName);
+ }
+
+ /// Return true if any kind of remark is enabled for any category, i.e. if at
+ /// least one category filter is active. This is a cheap check that external
+ /// remark producers can use before doing any work to build a remark.
+ bool isAnyRemarkEnabled() const {
+ return missFilter.has_value() || passedFilter.has_value() ||
+ analysisFilter.has_value() || failedFilter.has_value();
+ }
+
//===--------------------------------------------------------------------===//
// Remark Linking - query previously emitted remarks
//===--------------------------------------------------------------------===//
diff --git a/mlir/lib/IR/Remarks.cpp b/mlir/lib/IR/Remarks.cpp
index 273918171746d..85c19dbd89250 100644
--- a/mlir/lib/IR/Remarks.cpp
+++ b/mlir/lib/IR/Remarks.cpp
@@ -205,6 +205,23 @@ bool RemarkEngine::isFailedOptRemarkEnabled(StringRef categoryName) const {
return failedFilter && failedFilter->match(categoryName);
}
+bool RemarkEngine::isRemarkEnabled(RemarkKind kind,
+ StringRef categoryName) const {
+ switch (kind) {
+ case RemarkKind::RemarkUnknown:
+ return false;
+ case RemarkKind::RemarkPassed:
+ return isPassedOptRemarkEnabled(categoryName);
+ case RemarkKind::RemarkMissed:
+ return isMissedOptRemarkEnabled(categoryName);
+ case RemarkKind::RemarkFailure:
+ return isFailedOptRemarkEnabled(categoryName);
+ case RemarkKind::RemarkAnalysis:
+ return isAnalysisOptRemarkEnabled(categoryName);
+ }
+ llvm_unreachable("Unknown remark kind");
+}
+
InFlightRemark RemarkEngine::emitOptimizationRemark(Location loc,
RemarkOpts opts) {
return emitIfEnabled<OptRemarkPass>(loc, opts,
diff --git a/mlir/unittests/IR/RemarkTest.cpp b/mlir/unittests/IR/RemarkTest.cpp
index 81bfcd1446455..c02f1e1c14bf5 100644
--- a/mlir/unittests/IR/RemarkTest.cpp
+++ b/mlir/unittests/IR/RemarkTest.cpp
@@ -518,6 +518,110 @@ TEST(Remark, TestRemarkOwnsStringData) {
<< "Expected message not found in output. Got: " << errOut;
}
+// Test that the engine exposes which remark kinds and categories are enabled,
+// so that external remark producers can query the filters before building
+// remarks.
+TEST(Remark, TestEngineFilterQueries) {
+ using remark::RemarkKind;
+
+ // No filter is set: nothing is enabled.
+ {
+ MLIRContext context;
+ mlir::remark::RemarkCategories cats{/*all=*/std::nullopt,
+ /*passed=*/std::nullopt,
+ /*missed=*/std::nullopt,
+ /*analysis=*/std::nullopt,
+ /*failed=*/std::nullopt};
+ ASSERT_TRUE(succeeded(remark::enableOptimizationRemarks(
+ context, nullptr, std::make_unique<remark::RemarkEmittingPolicyAll>(),
+ cats)));
+ remark::detail::RemarkEngine *engine = context.getRemarkEngine();
+ ASSERT_TRUE(engine);
+ EXPECT_FALSE(engine->isAnyRemarkEnabled());
+ EXPECT_FALSE(engine->isAnyRemarkEnabled("Vectorizer"));
+ EXPECT_FALSE(engine->isPassedOptRemarkEnabled("Vectorizer"));
+ }
+
+ // Empty filter strings are equivalent to unset filters.
+ {
+ MLIRContext context;
+ mlir::remark::RemarkCategories cats{/*all=*/"", /*passed=*/"",
+ /*missed=*/"", /*analysis=*/"",
+ /*failed=*/""};
+ ASSERT_TRUE(succeeded(remark::enableOptimizationRemarks(
+ context, nullptr, std::make_unique<remark::RemarkEmittingPolicyAll>(),
+ cats)));
+ remark::detail::RemarkEngine *engine = context.getRemarkEngine();
+ ASSERT_TRUE(engine);
+ EXPECT_FALSE(engine->isAnyRemarkEnabled());
+ }
+
+ // Per-kind filters are matched against the whole category name.
+ {
+ MLIRContext context;
+ mlir::remark::RemarkCategories cats{/*all=*/std::nullopt,
+ /*passed=*/"Vectorizer",
+ /*missed=*/"Unroll|Inliner",
+ /*analysis=*/std::nullopt,
+ /*failed=*/std::nullopt};
+ ASSERT_TRUE(succeeded(remark::enableOptimizationRemarks(
+ context, nullptr, std::make_unique<remark::RemarkEmittingPolicyAll>(),
+ cats)));
+ remark::detail::RemarkEngine *engine = context.getRemarkEngine();
+ ASSERT_TRUE(engine);
+
+ EXPECT_TRUE(engine->isAnyRemarkEnabled());
+
+ EXPECT_TRUE(engine->isPassedOptRemarkEnabled("Vectorizer"));
+ EXPECT_FALSE(engine->isPassedOptRemarkEnabled("Vectorizer2"));
+ EXPECT_FALSE(engine->isPassedOptRemarkEnabled("Unroll"));
+
+ EXPECT_TRUE(engine->isMissedOptRemarkEnabled("Unroll"));
+ EXPECT_TRUE(engine->isMissedOptRemarkEnabled("Inliner"));
+ EXPECT_FALSE(engine->isMissedOptRemarkEnabled("Vectorizer"));
+
+ EXPECT_FALSE(engine->isAnalysisOptRemarkEnabled("Vectorizer"));
+ EXPECT_FALSE(engine->isFailedOptRemarkEnabled("Vectorizer"));
+
+ EXPECT_TRUE(engine->isAnyRemarkEnabled("Vectorizer"));
+ EXPECT_TRUE(engine->isAnyRemarkEnabled("Unroll"));
+ EXPECT_FALSE(engine->isAnyRemarkEnabled("Register"));
+
+ EXPECT_TRUE(
+ engine->isRemarkEnabled(RemarkKind::RemarkPassed, "Vectorizer"));
+ EXPECT_TRUE(engine->isRemarkEnabled(RemarkKind::RemarkMissed, "Unroll"));
+ EXPECT_FALSE(
+ engine->isRemarkEnabled(RemarkKind::RemarkAnalysis, "Vectorizer"));
+ EXPECT_FALSE(
+ engine->isRemarkEnabled(RemarkKind::RemarkFailure, "Vectorizer"));
+ EXPECT_FALSE(
+ engine->isRemarkEnabled(RemarkKind::RemarkUnknown, "Vectorizer"));
+ }
+
+ // The `all` filter enables every kind for the matching categories.
+ {
+ MLIRContext context;
+ mlir::remark::RemarkCategories cats{/*all=*/"loop-.*",
+ /*passed=*/std::nullopt,
+ /*missed=*/"",
+ /*analysis=*/"",
+ /*failed=*/""};
+ ASSERT_TRUE(succeeded(remark::enableOptimizationRemarks(
+ context, nullptr, std::make_unique<remark::RemarkEmittingPolicyAll>(),
+ cats)));
+ remark::detail::RemarkEngine *engine = context.getRemarkEngine();
+ ASSERT_TRUE(engine);
+
+ EXPECT_TRUE(engine->isAnyRemarkEnabled());
+ // `passed` is unset, so `all` does not enable it.
+ EXPECT_FALSE(engine->isPassedOptRemarkEnabled("loop-unroll"));
+ EXPECT_TRUE(engine->isMissedOptRemarkEnabled("loop-unroll"));
+ EXPECT_TRUE(engine->isAnalysisOptRemarkEnabled("loop-vectorize"));
+ EXPECT_TRUE(engine->isFailedOptRemarkEnabled("loop-unroll"));
+ EXPECT_FALSE(engine->isMissedOptRemarkEnabled("inline"));
+ }
+}
+
// Test that remarks can be linked together using RemarkId.
TEST(Remark, TestRemarkLinking) {
testing::internal::CaptureStderr();
More information about the Mlir-commits
mailing list