Skip to content

Commit 66bf252

Browse files
authored
[MLIR] Implement remark emitting policies in MLIR (llvm#161202)
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 ``` Relanding llvm#160526 This PR requires RemarkEngine to be finalize manually. So here is usage: ``` MLIRContext ctx; ctx.setRemarkEngine(...) ... ctx.getRemarkEngine().shutdown() <-- PR adds this, it is required when the emission policy is final ```
1 parent e156d1e commit 66bf252

File tree

10 files changed

+327
-40
lines changed

10 files changed

+327
-40
lines changed

mlir/include/mlir/IR/Remarks.h

Lines changed: 133 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.
@@ -407,8 +430,15 @@ class RemarkEngine {
407430
~RemarkEngine();
408431

409432
/// Setup the remark engine with the given output path and format.
410-
LogicalResult initialize(std::unique_ptr<MLIRRemarkStreamerBase> streamer,
411-
std::string *errMsg);
433+
LogicalResult
434+
initialize(std::unique_ptr<MLIRRemarkStreamerBase> streamer,
435+
std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy,
436+
std::string *errMsg);
437+
438+
/// Get the remark emitting policy.
439+
RemarkEmittingPolicyBase *getRemarkEmittingPolicy() const {
440+
return remarkEmittingPolicy.get();
441+
}
412442

413443
/// Report a remark.
414444
void report(const Remark &&remark);
@@ -446,6 +476,46 @@ inline InFlightRemark withEngine(Fn fn, Location loc, Args &&...args) {
446476

447477
namespace mlir::remark {
448478

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

506576
/// Setup remarks for the context. This function will enable the remark engine
507577
/// 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
578+
/// categories are used to filter the remarks that will be emitted by the
579+
/// remark engine. If a category is not specified, it will not be emitted. If
510580
/// `printAsEmitRemarks` is true, the remarks will be printed as
511581
/// mlir::emitRemarks. 'streamer' must inherit from MLIRRemarkStreamerBase and
512582
/// will be used to stream the remarks.
513583
LogicalResult enableOptimizationRemarks(
514584
MLIRContext &ctx,
515585
std::unique_ptr<remark::detail::MLIRRemarkStreamerBase> streamer,
586+
std::unique_ptr<remark::detail::RemarkEmittingPolicyBase>
587+
remarkEmittingPolicy,
516588
const remark::RemarkCategories &cats, bool printAsEmitRemarks = false);
517589

518590
} // namespace mlir::remark
519591

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