2424#include " mlir/IR/MLIRContext.h"
2525#include " mlir/IR/Value.h"
2626
27+ #include < functional>
28+
2729namespace mlir ::remark {
2830
2931// / Define an the set of categories to accept. By default none are, the provided
@@ -144,7 +146,7 @@ class Remark {
144146
145147 llvm::StringRef getCategoryName () const { return categoryName; }
146148
147- llvm::StringRef getFullCategoryName () const {
149+ llvm::StringRef getCombinedCategoryName () const {
148150 if (categoryName.empty () && subCategoryName.empty ())
149151 return {};
150152 if (subCategoryName.empty ())
@@ -318,7 +320,7 @@ class InFlightRemark {
318320};
319321
320322// ===----------------------------------------------------------------------===//
321- // MLIR Remark Streamer
323+ // Pluggable Remark Utilities
322324// ===----------------------------------------------------------------------===//
323325
324326// / Base class for MLIR remark streamers that is used to stream
@@ -338,6 +340,26 @@ class MLIRRemarkStreamerBase {
338340 virtual void finalize () {} // optional
339341};
340342
343+ using ReportFn = llvm::unique_function<void (const Remark &)>;
344+
345+ // / Base class for MLIR remark emitting policies that is used to emit
346+ // / optimization remarks to the underlying remark streamer. The derived classes
347+ // / should implement the `reportRemark` method to provide the actual emitting
348+ // / implementation.
349+ class RemarkEmittingPolicyBase {
350+ protected:
351+ ReportFn reportImpl;
352+
353+ public:
354+ RemarkEmittingPolicyBase () = default ;
355+ virtual ~RemarkEmittingPolicyBase () = default ;
356+
357+ void initialize (ReportFn fn) { reportImpl = std::move (fn); }
358+
359+ virtual void reportRemark (const Remark &remark) = 0;
360+ virtual void finalize () = 0;
361+ };
362+
341363// ===----------------------------------------------------------------------===//
342364// Remark Engine (MLIR Context will own this class)
343365// ===----------------------------------------------------------------------===//
@@ -355,6 +377,8 @@ class RemarkEngine {
355377 std::optional<llvm::Regex> failedFilter;
356378 // / The MLIR remark streamer that will be used to emit the remarks.
357379 std::unique_ptr<MLIRRemarkStreamerBase> remarkStreamer;
380+ // / The MLIR remark policy that will be used to emit the remarks.
381+ std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy;
358382 // / When is enabled, engine also prints remarks as mlir::emitRemarks.
359383 bool printAsEmitRemarks = false ;
360384
@@ -392,6 +416,8 @@ class RemarkEngine {
392416 InFlightRemark emitIfEnabled (Location loc, RemarkOpts opts,
393417 bool (RemarkEngine::*isEnabled)(StringRef)
394418 const );
419+ // / Report a remark.
420+ void reportImpl (const Remark &remark);
395421
396422public:
397423 // / Default constructor is deleted, use the other constructor.
@@ -407,8 +433,10 @@ class RemarkEngine {
407433 ~RemarkEngine ();
408434
409435 // / Setup the remark engine with the given output path and format.
410- LogicalResult initialize (std::unique_ptr<MLIRRemarkStreamerBase> streamer,
411- std::string *errMsg);
436+ LogicalResult
437+ initialize (std::unique_ptr<MLIRRemarkStreamerBase> streamer,
438+ std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy,
439+ std::string *errMsg);
412440
413441 // / Report a remark.
414442 void report (const Remark &&remark);
@@ -446,6 +474,54 @@ inline InFlightRemark withEngine(Fn fn, Location loc, Args &&...args) {
446474
447475namespace mlir ::remark {
448476
477+ // ===----------------------------------------------------------------------===//
478+ // Remark Emitting Policies
479+ // ===----------------------------------------------------------------------===//
480+
481+ // / Policy that emits all remarks.
482+ class RemarkEmittingPolicyAll : public detail ::RemarkEmittingPolicyBase {
483+ public:
484+ RemarkEmittingPolicyAll ();
485+
486+ void reportRemark (const detail::Remark &remark) override {
487+ reportImpl (remark);
488+ }
489+ void finalize () override {}
490+ };
491+
492+ // / Policy that emits final remarks.
493+ class RemarkEmittingPolicyFinal : public detail ::RemarkEmittingPolicyBase {
494+ private:
495+ // / user can intercept them for custom processing via a registered callback,
496+ // / otherwise they will be reported on engine destruction.
497+ llvm::DenseSet<detail::Remark> postponedRemarks;
498+ // / Optional user callback for intercepting postponed remarks.
499+ std::function<void (const detail::Remark &)> postponedRemarkCallback;
500+
501+ public:
502+ RemarkEmittingPolicyFinal ();
503+
504+ // / Register a callback to intercept postponed remarks before they are
505+ // / reported. The callback will be invoked for each postponed remark in
506+ // / finalize().
507+ void
508+ setPostponedRemarkCallback (std::function<void (const detail::Remark &)> cb) {
509+ postponedRemarkCallback = std::move (cb);
510+ }
511+
512+ void reportRemark (const detail::Remark &remark) override {
513+ postponedRemarks.erase (remark);
514+ postponedRemarks.insert (remark);
515+ }
516+ void finalize () override {
517+ for (auto &remark : postponedRemarks) {
518+ if (postponedRemarkCallback)
519+ postponedRemarkCallback (remark);
520+ reportImpl (remark);
521+ }
522+ }
523+ };
524+
449525// / Create a Reason with llvm::formatv formatting.
450526template <class ... Ts>
451527inline detail::LazyTextBuild reason (const char *fmt, Ts &&...ts) {
@@ -505,16 +581,72 @@ inline detail::InFlightRemark analysis(Location loc, RemarkOpts opts) {
505581
506582// / Setup remarks for the context. This function will enable the remark engine
507583// / 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
584+ // / categories are used to filter the remarks that will be emitted by the
585+ // / remark engine. If a category is not specified, it will not be emitted. If
510586// / `printAsEmitRemarks` is true, the remarks will be printed as
511587// / mlir::emitRemarks. 'streamer' must inherit from MLIRRemarkStreamerBase and
512588// / will be used to stream the remarks.
513589LogicalResult enableOptimizationRemarks (
514590 MLIRContext &ctx,
515591 std::unique_ptr<remark::detail::MLIRRemarkStreamerBase> streamer,
592+ std::unique_ptr<remark::detail::RemarkEmittingPolicyBase>
593+ remarkEmittingPolicy,
516594 const remark::RemarkCategories &cats, bool printAsEmitRemarks = false );
517595
518596} // namespace mlir::remark
519597
598+ // DenseMapInfo specialization for Remark
599+ namespace llvm {
600+ template <>
601+ struct DenseMapInfo <mlir::remark::detail::Remark> {
602+ static constexpr StringRef kEmptyKey = " <EMPTY_KEY>" ;
603+ static constexpr StringRef kTombstoneKey = " <TOMBSTONE_KEY>" ;
604+
605+ // / Helper to provide a static dummy context for sentinel keys.
606+ static mlir::MLIRContext *getStaticDummyContext () {
607+ static mlir::MLIRContext dummyContext;
608+ return &dummyContext;
609+ }
610+
611+ // / Create an empty remark
612+ static inline mlir::remark::detail::Remark getEmptyKey () {
613+ return mlir::remark::detail::Remark (
614+ mlir::remark::RemarkKind::RemarkUnknown, mlir::DiagnosticSeverity::Note,
615+ mlir::UnknownLoc::get (getStaticDummyContext ()),
616+ mlir::remark::RemarkOpts::name (kEmptyKey ));
617+ }
618+
619+ // / Create a dead remark
620+ static inline mlir::remark::detail::Remark getTombstoneKey () {
621+ return mlir::remark::detail::Remark (
622+ mlir::remark::RemarkKind::RemarkUnknown, mlir::DiagnosticSeverity::Note,
623+ mlir::UnknownLoc::get (getStaticDummyContext ()),
624+ mlir::remark::RemarkOpts::name (kTombstoneKey ));
625+ }
626+
627+ // / Compute the hash value of the remark
628+ static unsigned getHashValue (const mlir::remark::detail::Remark &remark) {
629+ return llvm::hash_combine (
630+ remark.getLocation ().getAsOpaquePointer (),
631+ llvm::hash_value (remark.getRemarkName ()),
632+ llvm::hash_value (remark.getCombinedCategoryName ()));
633+ }
634+
635+ static bool isEqual (const mlir::remark::detail::Remark &lhs,
636+ const mlir::remark::detail::Remark &rhs) {
637+ // Check for empty/tombstone keys first
638+ if (lhs.getRemarkName () == kEmptyKey ||
639+ lhs.getRemarkName () == kTombstoneKey ||
640+ rhs.getRemarkName () == kEmptyKey ||
641+ rhs.getRemarkName () == kTombstoneKey ) {
642+ return lhs.getRemarkName () == rhs.getRemarkName ();
643+ }
644+
645+ // For regular remarks, compare key identifying fields
646+ return lhs.getLocation () == rhs.getLocation () &&
647+ lhs.getRemarkName () == rhs.getRemarkName () &&
648+ lhs.getCombinedCategoryName () == rhs.getCombinedCategoryName ();
649+ }
650+ };
651+ } // namespace llvm
520652#endif // MLIR_IR_REMARKS_H
0 commit comments