Skip to content

Commit dd3a42b

Browse files
committed
[MLIR] Implement remark emitting policies in MLIR
This update introduces two new remark emitting policies: 1. `RemarkEmittingPolicyAll`, which emits all remarks, 2. `RemarkEmittingPolicyFinal`, which only emits final remarks after processing. The `RemarkEngine` is modified to support these policies, allowing for more flexible remark handling based on user configuration. PR also adds flag to `mlir-opt` ``` --remark-policy=<value> - Specify the policy for remark output. =all - Print all remarks =final - Print final remarks ```
1 parent e4d94f4 commit dd3a42b

File tree

10 files changed

+332
-40
lines changed

10 files changed

+332
-40
lines changed

mlir/include/mlir/IR/Remarks.h

Lines changed: 132 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "llvm/Remarks/Remark.h"
1919
#include "llvm/Support/FormatVariadic.h"
2020
#include "llvm/Support/Regex.h"
21-
#include <optional>
2221

2322
#include "mlir/IR/Diagnostics.h"
2423
#include "mlir/IR/MLIRContext.h"
@@ -144,7 +143,7 @@ class Remark {
144143

145144
llvm::StringRef getCategoryName() const { return categoryName; }
146145

147-
llvm::StringRef getFullCategoryName() const {
146+
llvm::StringRef getCombinedCategoryName() const {
148147
if (categoryName.empty() && subCategoryName.empty())
149148
return {};
150149
if (subCategoryName.empty())
@@ -318,7 +317,7 @@ class InFlightRemark {
318317
};
319318

320319
//===----------------------------------------------------------------------===//
321-
// MLIR Remark Streamer
320+
// Pluggable Remark Utilities
322321
//===----------------------------------------------------------------------===//
323322

324323
/// Base class for MLIR remark streamers that is used to stream
@@ -338,6 +337,26 @@ class MLIRRemarkStreamerBase {
338337
virtual void finalize() {} // optional
339338
};
340339

340+
using ReportFn = llvm::unique_function<void(const Remark &)>;
341+
342+
/// Base class for MLIR remark emitting policies that is used to emit
343+
/// optimization remarks to the underlying remark streamer. The derived classes
344+
/// should implement the `reportRemark` method to provide the actual emitting
345+
/// implementation.
346+
class RemarkEmittingPolicyBase {
347+
protected:
348+
ReportFn reportImpl;
349+
350+
public:
351+
RemarkEmittingPolicyBase() = default;
352+
virtual ~RemarkEmittingPolicyBase() = default;
353+
354+
void initialize(ReportFn fn) { reportImpl = std::move(fn); }
355+
356+
virtual void reportRemark(const Remark &remark) = 0;
357+
virtual void finalize() = 0;
358+
};
359+
341360
//===----------------------------------------------------------------------===//
342361
// Remark Engine (MLIR Context will own this class)
343362
//===----------------------------------------------------------------------===//
@@ -355,6 +374,8 @@ class RemarkEngine {
355374
std::optional<llvm::Regex> failedFilter;
356375
/// The MLIR remark streamer that will be used to emit the remarks.
357376
std::unique_ptr<MLIRRemarkStreamerBase> remarkStreamer;
377+
/// The MLIR remark policy that will be used to emit the remarks.
378+
std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy;
358379
/// When is enabled, engine also prints remarks as mlir::emitRemarks.
359380
bool printAsEmitRemarks = false;
360381

@@ -392,6 +413,8 @@ class RemarkEngine {
392413
InFlightRemark emitIfEnabled(Location loc, RemarkOpts opts,
393414
bool (RemarkEngine::*isEnabled)(StringRef)
394415
const);
416+
/// Report a remark.
417+
void reportImpl(const Remark &remark);
395418

396419
public:
397420
/// Default constructor is deleted, use the other constructor.
@@ -406,9 +429,15 @@ class RemarkEngine {
406429
/// main remark streamer.
407430
~RemarkEngine();
408431

432+
/// Shutdown the remark engine. This will finalize the remark engine and
433+
/// close the output file.
434+
void shutdown();
435+
409436
/// Setup the remark engine with the given output path and format.
410-
LogicalResult initialize(std::unique_ptr<MLIRRemarkStreamerBase> streamer,
411-
std::string *errMsg);
437+
LogicalResult
438+
initialize(std::unique_ptr<MLIRRemarkStreamerBase> streamer,
439+
std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy,
440+
std::string *errMsg);
412441

413442
/// Report a remark.
414443
void report(const Remark &&remark);
@@ -446,6 +475,46 @@ inline InFlightRemark withEngine(Fn fn, Location loc, Args &&...args) {
446475

447476
namespace mlir::remark {
448477

478+
//===----------------------------------------------------------------------===//
479+
// Remark Emitting Policies
480+
//===----------------------------------------------------------------------===//
481+
482+
/// Policy that emits all remarks.
483+
class RemarkEmittingPolicyAll : public detail::RemarkEmittingPolicyBase {
484+
public:
485+
RemarkEmittingPolicyAll();
486+
487+
void reportRemark(const detail::Remark &remark) override {
488+
assert(reportImpl && "reportImpl is not set");
489+
reportImpl(remark);
490+
}
491+
void finalize() override {}
492+
};
493+
494+
/// Policy that emits final remarks.
495+
class RemarkEmittingPolicyFinal : public detail::RemarkEmittingPolicyBase {
496+
private:
497+
/// user can intercept them for custom processing via a registered callback,
498+
/// otherwise they will be reported on engine destruction.
499+
llvm::DenseSet<detail::Remark> postponedRemarks;
500+
501+
public:
502+
RemarkEmittingPolicyFinal();
503+
504+
void reportRemark(const detail::Remark &remark) override {
505+
postponedRemarks.erase(remark);
506+
postponedRemarks.insert(remark);
507+
}
508+
509+
void finalize() override {
510+
assert(reportImpl && "reportImpl is not set");
511+
for (auto &remark : postponedRemarks) {
512+
if (reportImpl)
513+
reportImpl(remark);
514+
}
515+
}
516+
};
517+
449518
/// Create a Reason with llvm::formatv formatting.
450519
template <class... Ts>
451520
inline detail::LazyTextBuild reason(const char *fmt, Ts &&...ts) {
@@ -505,16 +574,72 @@ inline detail::InFlightRemark analysis(Location loc, RemarkOpts opts) {
505574

506575
/// Setup remarks for the context. This function will enable the remark engine
507576
/// and set the streamer to be used for optimization remarks. The remark
508-
/// categories are used to filter the remarks that will be emitted by the remark
509-
/// engine. If a category is not specified, it will not be emitted. If
577+
/// categories are used to filter the remarks that will be emitted by the
578+
/// remark engine. If a category is not specified, it will not be emitted. If
510579
/// `printAsEmitRemarks` is true, the remarks will be printed as
511580
/// mlir::emitRemarks. 'streamer' must inherit from MLIRRemarkStreamerBase and
512581
/// will be used to stream the remarks.
513582
LogicalResult enableOptimizationRemarks(
514583
MLIRContext &ctx,
515584
std::unique_ptr<remark::detail::MLIRRemarkStreamerBase> streamer,
585+
std::unique_ptr<remark::detail::RemarkEmittingPolicyBase>
586+
remarkEmittingPolicy,
516587
const remark::RemarkCategories &cats, bool printAsEmitRemarks = false);
517588

518589
} // namespace mlir::remark
519590

591+
// DenseMapInfo specialization for Remark
592+
namespace llvm {
593+
template <>
594+
struct DenseMapInfo<mlir::remark::detail::Remark> {
595+
static constexpr StringRef kEmptyKey = "<EMPTY_KEY>";
596+
static constexpr StringRef kTombstoneKey = "<TOMBSTONE_KEY>";
597+
598+
/// Helper to provide a static dummy context for sentinel keys.
599+
static mlir::MLIRContext *getStaticDummyContext() {
600+
static mlir::MLIRContext dummyContext;
601+
return &dummyContext;
602+
}
603+
604+
/// Create an empty remark
605+
static inline mlir::remark::detail::Remark getEmptyKey() {
606+
return mlir::remark::detail::Remark(
607+
mlir::remark::RemarkKind::RemarkUnknown, mlir::DiagnosticSeverity::Note,
608+
mlir::UnknownLoc::get(getStaticDummyContext()),
609+
mlir::remark::RemarkOpts::name(kEmptyKey));
610+
}
611+
612+
/// Create a dead remark
613+
static inline mlir::remark::detail::Remark getTombstoneKey() {
614+
return mlir::remark::detail::Remark(
615+
mlir::remark::RemarkKind::RemarkUnknown, mlir::DiagnosticSeverity::Note,
616+
mlir::UnknownLoc::get(getStaticDummyContext()),
617+
mlir::remark::RemarkOpts::name(kTombstoneKey));
618+
}
619+
620+
/// Compute the hash value of the remark
621+
static unsigned getHashValue(const mlir::remark::detail::Remark &remark) {
622+
return llvm::hash_combine(
623+
remark.getLocation().getAsOpaquePointer(),
624+
llvm::hash_value(remark.getRemarkName()),
625+
llvm::hash_value(remark.getCombinedCategoryName()));
626+
}
627+
628+
static bool isEqual(const mlir::remark::detail::Remark &lhs,
629+
const mlir::remark::detail::Remark &rhs) {
630+
// Check for empty/tombstone keys first
631+
if (lhs.getRemarkName() == kEmptyKey ||
632+
lhs.getRemarkName() == kTombstoneKey ||
633+
rhs.getRemarkName() == kEmptyKey ||
634+
rhs.getRemarkName() == kTombstoneKey) {
635+
return lhs.getRemarkName() == rhs.getRemarkName();
636+
}
637+
638+
// For regular remarks, compare key identifying fields
639+
return lhs.getLocation() == rhs.getLocation() &&
640+
lhs.getRemarkName() == rhs.getRemarkName() &&
641+
lhs.getCombinedCategoryName() == rhs.getCombinedCategoryName();
642+
}
643+
};
644+
} // namespace llvm
520645
#endif // MLIR_IR_REMARKS_H

mlir/include/mlir/Remark/RemarkStreamer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ namespace mlir::remark {
4545
/// mlir::emitRemarks.
4646
LogicalResult enableOptimizationRemarksWithLLVMStreamer(
4747
MLIRContext &ctx, StringRef filePath, llvm::remarks::Format fmt,
48+
std::unique_ptr<detail::RemarkEmittingPolicyBase> remarkEmittingPolicy,
4849
const RemarkCategories &cat, bool printAsEmitRemarks = false);
4950

5051
} // namespace mlir::remark

mlir/include/mlir/Tools/mlir-opt/MlirOptMain.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ enum class RemarkFormat {
4444
REMARK_FORMAT_BITSTREAM,
4545
};
4646

47+
enum class RemarkPolicy {
48+
REMARK_POLICY_ALL,
49+
REMARK_POLICY_FINAL,
50+
};
51+
4752
/// Configuration options for the mlir-opt tool.
4853
/// This is intended to help building tools like mlir-opt by collecting the
4954
/// supported options.
@@ -242,6 +247,8 @@ class MlirOptMainConfig {
242247

243248
/// Set the reproducer output filename
244249
RemarkFormat getRemarkFormat() const { return remarkFormatFlag; }
250+
/// Set the remark policy to use.
251+
RemarkPolicy getRemarkPolicy() const { return remarkPolicyFlag; }
245252
/// Set the remark format to use.
246253
std::string getRemarksAllFilter() const { return remarksAllFilterFlag; }
247254
/// Set the remark output file.
@@ -265,6 +272,8 @@ class MlirOptMainConfig {
265272

266273
/// Remark format
267274
RemarkFormat remarkFormatFlag = RemarkFormat::REMARK_FORMAT_STDOUT;
275+
/// Remark policy
276+
RemarkPolicy remarkPolicyFlag = RemarkPolicy::REMARK_POLICY_ALL;
268277
/// Remark file to output to
269278
std::string remarksOutputFileFlag = "";
270279
/// Remark filters

mlir/lib/IR/MLIRContext.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,11 @@ namespace mlir {
120120
/// This class is completely private to this file, so everything is public.
121121
class MLIRContextImpl {
122122
public:
123+
//===--------------------------------------------------------------------===//
124+
// Remark
125+
//===--------------------------------------------------------------------===//
126+
std::unique_ptr<remark::detail::RemarkEngine> remarkEngine;
127+
123128
//===--------------------------------------------------------------------===//
124129
// Debugging
125130
//===--------------------------------------------------------------------===//
@@ -134,11 +139,6 @@ class MLIRContextImpl {
134139
//===--------------------------------------------------------------------===//
135140
DiagnosticEngine diagEngine;
136141

137-
//===--------------------------------------------------------------------===//
138-
// Remark
139-
//===--------------------------------------------------------------------===//
140-
std::unique_ptr<remark::detail::RemarkEngine> remarkEngine;
141-
142142
//===--------------------------------------------------------------------===//
143143
// Options
144144
//===--------------------------------------------------------------------===//
@@ -357,7 +357,10 @@ MLIRContext::MLIRContext(const DialectRegistry &registry, Threading setting)
357357
impl->affineUniquer.registerParametricStorageType<IntegerSetStorage>();
358358
}
359359

360-
MLIRContext::~MLIRContext() = default;
360+
MLIRContext::~MLIRContext() {
361+
// finalize remark engine before destroying anything else.
362+
impl->remarkEngine.reset();
363+
}
361364

362365
/// Copy the specified array of elements into memory managed by the provided
363366
/// bump pointer allocator. This assumes the elements are all PODs.

0 commit comments

Comments
 (0)