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
396419public:
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
447476namespace 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.
450519template <class ... Ts>
451520inline 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.
513582LogicalResult 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
0 commit comments