24
24
#include " mlir/IR/MLIRContext.h"
25
25
#include " mlir/IR/Value.h"
26
26
27
+ #include < functional>
28
+
27
29
namespace mlir ::remark {
28
30
29
31
// / Define an the set of categories to accept. By default none are, the provided
@@ -144,7 +146,7 @@ class Remark {
144
146
145
147
llvm::StringRef getCategoryName () const { return categoryName; }
146
148
147
- llvm::StringRef getFullCategoryName () const {
149
+ llvm::StringRef getCombinedCategoryName () const {
148
150
if (categoryName.empty () && subCategoryName.empty ())
149
151
return {};
150
152
if (subCategoryName.empty ())
@@ -318,7 +320,7 @@ class InFlightRemark {
318
320
};
319
321
320
322
// ===----------------------------------------------------------------------===//
321
- // MLIR Remark Streamer
323
+ // Pluggable Remark Utilities
322
324
// ===----------------------------------------------------------------------===//
323
325
324
326
// / Base class for MLIR remark streamers that is used to stream
@@ -338,6 +340,26 @@ class MLIRRemarkStreamerBase {
338
340
virtual void finalize () {} // optional
339
341
};
340
342
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
+
341
363
// ===----------------------------------------------------------------------===//
342
364
// Remark Engine (MLIR Context will own this class)
343
365
// ===----------------------------------------------------------------------===//
@@ -355,6 +377,8 @@ class RemarkEngine {
355
377
std::optional<llvm::Regex> failedFilter;
356
378
// / The MLIR remark streamer that will be used to emit the remarks.
357
379
std::unique_ptr<MLIRRemarkStreamerBase> remarkStreamer;
380
+ // / The MLIR remark policy that will be used to emit the remarks.
381
+ std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy;
358
382
// / When is enabled, engine also prints remarks as mlir::emitRemarks.
359
383
bool printAsEmitRemarks = false ;
360
384
@@ -392,6 +416,8 @@ class RemarkEngine {
392
416
InFlightRemark emitIfEnabled (Location loc, RemarkOpts opts,
393
417
bool (RemarkEngine::*isEnabled)(StringRef)
394
418
const );
419
+ // / Report a remark.
420
+ void reportImpl (const Remark &remark);
395
421
396
422
public:
397
423
// / Default constructor is deleted, use the other constructor.
@@ -407,8 +433,10 @@ class RemarkEngine {
407
433
~RemarkEngine ();
408
434
409
435
// / 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);
412
440
413
441
// / Report a remark.
414
442
void report (const Remark &&remark);
@@ -446,6 +474,54 @@ inline InFlightRemark withEngine(Fn fn, Location loc, Args &&...args) {
446
474
447
475
namespace mlir ::remark {
448
476
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
+
449
525
// / Create a Reason with llvm::formatv formatting.
450
526
template <class ... Ts>
451
527
inline detail::LazyTextBuild reason (const char *fmt, Ts &&...ts) {
@@ -505,16 +581,72 @@ inline detail::InFlightRemark analysis(Location loc, RemarkOpts opts) {
505
581
506
582
// / Setup remarks for the context. This function will enable the remark engine
507
583
// / 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
510
586
// / `printAsEmitRemarks` is true, the remarks will be printed as
511
587
// / mlir::emitRemarks. 'streamer' must inherit from MLIRRemarkStreamerBase and
512
588
// / will be used to stream the remarks.
513
589
LogicalResult enableOptimizationRemarks (
514
590
MLIRContext &ctx,
515
591
std::unique_ptr<remark::detail::MLIRRemarkStreamerBase> streamer,
592
+ std::unique_ptr<remark::detail::RemarkEmittingPolicyBase>
593
+ remarkEmittingPolicy,
516
594
const remark::RemarkCategories &cats, bool printAsEmitRemarks = false );
517
595
518
596
} // namespace mlir::remark
519
597
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
520
652
#endif // MLIR_IR_REMARKS_H
0 commit comments