Files
gps/tools/local/circt/include/mlir/IR/Remarks.h
T
2026-07-12 11:01:51 +03:00

786 lines
27 KiB
C++

//===- Remarks.h - MLIR Optimization Remark ----------------------*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines utilities for emitting optimization remarks.
//
//===----------------------------------------------------------------------===//
#ifndef MLIR_IR_REMARKS_H
#define MLIR_IR_REMARKS_H
#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/Remarks/Remark.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Regex.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/IR/Value.h"
#include <atomic>
namespace mlir::remark {
//===----------------------------------------------------------------------===//
// RemarkId - Unique identifier for linking related remarks
//===----------------------------------------------------------------------===//
/// A unique identifier for a remark, used to link related remarks together.
/// An invalid/empty ID has value 0.
class RemarkId {
public:
RemarkId() : id(0) {}
explicit RemarkId(uint64_t id) : id(id) {}
/// Check if this is a valid (non-zero) ID.
explicit operator bool() const { return id != 0; }
/// Get the raw ID value.
uint64_t getValue() const { return id; }
bool operator==(const RemarkId &other) const { return id == other.id; }
bool operator!=(const RemarkId &other) const { return id != other.id; }
/// Print the ID.
void print(llvm::raw_ostream &os) const { os << "remark-" << id; }
private:
uint64_t id;
};
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, RemarkId id) {
id.print(os);
return os;
}
/// Define an the set of categories to accept. By default none are, the provided
/// regex matches against the category names for each kind of remark.
struct RemarkCategories {
std::optional<std::string> all, passed, missed, analysis, failed;
};
/// Categories describe the outcome of an transformation, not the mechanics of
/// emitting/serializing remarks.
enum class RemarkKind {
RemarkUnknown = 0,
/// An optimization was applied.
RemarkPassed,
/// A profitable optimization opportunity was found but not applied.
RemarkMissed,
/// The compiler attempted the optimization but failed (e.g., legality
/// checks, or better opportunites).
RemarkFailure,
/// Informational context (e.g., analysis numbers) without a pass/fail
/// outcome.
RemarkAnalysis,
};
using namespace llvm;
namespace detail {
class InFlightRemark; // forward declaration
} // namespace detail
/// Options to create a Remark
struct RemarkOpts {
StringRef remarkName; // Identifiable name
StringRef categoryName; // Category name (subject to regex filtering)
StringRef subCategoryName; // Subcategory name
StringRef functionName; // Function name if available
/// Link to a related remark by explicit ID.
RemarkId relatedId;
// Construct RemarkOpts from a remark name.
static RemarkOpts name(StringRef n) {
RemarkOpts o;
o.remarkName = n;
return o;
}
/// Return a copy with the category set.
RemarkOpts category(StringRef v) const {
auto copy = *this;
copy.categoryName = v;
return copy;
}
/// Return a copy with the subcategory set.
RemarkOpts subCategory(StringRef v) const {
auto copy = *this;
copy.subCategoryName = v;
return copy;
}
/// Return a copy with the function name set.
RemarkOpts function(StringRef v) const {
auto copy = *this;
copy.functionName = v;
return copy;
}
/// Link this remark to a previously emitted remark by explicit ID.
RemarkOpts relatedTo(RemarkId id) const {
auto copy = *this;
copy.relatedId = id;
return copy;
}
/// Link this remark to a related remark that is still in flight.
/// Extracts the ID from the InFlightRemark.
inline RemarkOpts relatedTo(const detail::InFlightRemark &r) const;
};
} // namespace mlir::remark
namespace mlir::remark::detail {
//===----------------------------------------------------------------------===//
// Remark Base Class
//===----------------------------------------------------------------------===//
class Remark {
public:
Remark(RemarkKind remarkKind, DiagnosticSeverity severity, Location loc,
RemarkOpts opts)
: remarkKind(remarkKind), functionName(opts.functionName.str()), loc(loc),
categoryName(opts.categoryName.str()),
subCategoryName(opts.subCategoryName.str()),
remarkName(opts.remarkName.str()) {
if (!categoryName.empty() && !subCategoryName.empty()) {
(llvm::Twine(categoryName) + ":" + subCategoryName)
.toVector(fullCategoryName);
}
// Explicit ID linking from opts.
if (opts.relatedId)
addRelatedRemark(opts.relatedId);
}
// Remark argument that is a key-value pair that can be printed as machine
// parsable args. For Attribute arguments, the original attribute is also
// stored to allow custom streamers to handle them specially.
struct Arg {
std::string key;
std::string val;
/// Optional attribute storage for Attribute-based args. Allows streamers
/// to access the original attribute for custom handling.
std::optional<Attribute> attr;
Arg(llvm::StringRef m) : key("Remark"), val(m) {}
Arg(llvm::StringRef k, llvm::StringRef v) : key(k), val(v) {}
Arg(llvm::StringRef k, std::string v) : key(k), val(std::move(v)) {}
Arg(llvm::StringRef k, const char *v) : Arg(k, llvm::StringRef(v)) {}
Arg(llvm::StringRef k, Value v);
Arg(llvm::StringRef k, Type t);
Arg(llvm::StringRef k, Attribute a);
Arg(llvm::StringRef k, bool b) : key(k), val(b ? "true" : "false") {}
/// Check if this arg has an associated attribute.
bool hasAttribute() const { return attr.has_value(); }
/// Get the attribute if present.
Attribute getAttribute() const { return attr.value_or(Attribute()); }
// One constructor for all arithmetic types except bool.
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T> &&
!std::is_same_v<T, bool>>>
Arg(llvm::StringRef k, T v) : key(k) {
if constexpr (std::is_floating_point_v<T>) {
llvm::raw_string_ostream os(val);
os << v;
} else if constexpr (std::is_signed_v<T>) {
val = llvm::itostr(static_cast<long long>(v));
} else {
val = llvm::utostr(static_cast<unsigned long long>(v));
}
}
};
void insert(llvm::StringRef s);
void insert(Arg a);
void print(llvm::raw_ostream &os, bool printLocation = false) const;
Location getLocation() const { return loc; }
/// Diagnostic -> Remark
llvm::remarks::Remark generateRemark() const;
StringRef getFunction() const {
if (!functionName.empty())
return functionName;
return "<unknown function>";
}
llvm::StringRef getCategoryName() const { return categoryName; }
llvm::StringRef getCombinedCategoryName() const {
if (categoryName.empty() && subCategoryName.empty())
return {};
if (subCategoryName.empty())
return categoryName;
if (categoryName.empty())
return subCategoryName;
return fullCategoryName;
}
StringRef getRemarkName() const {
if (remarkName.empty())
return "<unknown remark name>";
return remarkName;
}
std::string getMsg() const;
ArrayRef<Arg> getArgs() const { return args; }
llvm::remarks::Type getRemarkType() const;
//===--------------------------------------------------------------------===//
// Remark Linking Support
//===--------------------------------------------------------------------===//
/// Get this remark's unique ID (0 if not assigned).
RemarkId getId() const { return id; }
/// Set this remark's unique ID. Also adds it as an Arg for serialization.
void setId(RemarkId newId) {
id = newId;
if (id)
args.emplace_back("RemarkId", llvm::utostr(id.getValue()));
}
/// Get the list of related remark IDs.
ArrayRef<RemarkId> getRelatedRemarkIds() const { return relatedRemarks; }
/// Add a reference to a related remark. Also adds it as an Arg for
/// serialization.
void addRelatedRemark(RemarkId relatedId) {
if (relatedId) {
relatedRemarks.push_back(relatedId);
args.emplace_back("RelatedTo", llvm::utostr(relatedId.getValue()));
}
}
/// Check if this remark has any related remarks.
bool hasRelatedRemarks() const { return !relatedRemarks.empty(); }
/// Get the remark kind.
RemarkKind getRemarkKind() const { return remarkKind; }
StringRef getRemarkTypeString() const;
protected:
/// Keeps the MLIR diagnostic kind, which is used to determine the
/// diagnostic kind in the LLVM remark streamer.
RemarkKind remarkKind;
/// Name of the covering function like interface.
/// Stored as std::string to ensure the Remark owns its data.
std::string functionName;
Location loc;
/// Category name e.g., "Unroll" or "UnrollAndJam".
/// Stored as std::string to ensure the Remark owns its data.
std::string categoryName;
/// Sub category name e.g., "Loop Optimizer".
/// Stored as std::string to ensure the Remark owns its data.
std::string subCategoryName;
/// Combined name for category and sub-category
SmallString<64> fullCategoryName;
/// Remark identifier.
/// Stored as std::string to ensure the Remark owns its data.
std::string remarkName;
/// Args collected via the streaming interface.
SmallVector<Arg, 4> args;
/// Unique ID for this remark (assigned by RemarkEngine).
RemarkId id;
/// IDs of related remarks (e.g., parent analysis that enabled this opt).
SmallVector<RemarkId> relatedRemarks;
private:
/// Convert the MLIR diagnostic severity to LLVM diagnostic severity.
static llvm::DiagnosticSeverity
makeLLVMSeverity(DiagnosticSeverity severity) {
switch (severity) {
case DiagnosticSeverity::Note:
return llvm::DiagnosticSeverity::DS_Note;
case DiagnosticSeverity::Warning:
return llvm::DiagnosticSeverity::DS_Warning;
case DiagnosticSeverity::Error:
return llvm::DiagnosticSeverity::DS_Error;
case DiagnosticSeverity::Remark:
return llvm::DiagnosticSeverity::DS_Remark;
}
llvm_unreachable("Unknown diagnostic severity");
}
/// Convert the MLIR remark kind to LLVM diagnostic kind.
static llvm::DiagnosticKind makeLLVMKind(RemarkKind remarkKind) {
switch (remarkKind) {
case RemarkKind::RemarkUnknown:
return llvm::DiagnosticKind::DK_Generic;
case RemarkKind::RemarkPassed:
return llvm::DiagnosticKind::DK_OptimizationRemark;
case RemarkKind::RemarkMissed:
return llvm::DiagnosticKind::DK_OptimizationRemarkMissed;
case RemarkKind::RemarkFailure:
return llvm::DiagnosticKind::DK_OptimizationFailure;
case RemarkKind::RemarkAnalysis:
return llvm::DiagnosticKind::DK_OptimizationRemarkAnalysis;
}
llvm_unreachable("Unknown diagnostic kind");
}
};
inline Remark &operator<<(Remark &r, StringRef s) {
r.insert(s);
return r;
}
inline Remark &&operator<<(Remark &&r, StringRef s) {
r.insert(s);
return std::move(r);
}
inline Remark &operator<<(Remark &r, const Remark::Arg &kv) {
r.insert(kv);
return r;
}
//===----------------------------------------------------------------------===//
// Shorthand aliases for different kinds of remarks.
//===----------------------------------------------------------------------===//
template <RemarkKind K, DiagnosticSeverity S>
class OptRemarkBase final : public Remark {
public:
explicit OptRemarkBase(Location loc, RemarkOpts opts)
: Remark(K, S, loc, opts) {}
};
using OptRemarkAnalysis =
OptRemarkBase<RemarkKind::RemarkAnalysis, DiagnosticSeverity::Remark>;
using OptRemarkPass =
OptRemarkBase<RemarkKind::RemarkPassed, DiagnosticSeverity::Remark>;
using OptRemarkMissed =
OptRemarkBase<RemarkKind::RemarkMissed, DiagnosticSeverity::Remark>;
using OptRemarkFailure =
OptRemarkBase<RemarkKind::RemarkFailure, DiagnosticSeverity::Remark>;
class RemarkEngine;
//===----------------------------------------------------------------------===//
// InFlightRemark
//===----------------------------------------------------------------------===//
/// Lazy text building for zero cost string formatting.
struct LazyTextBuild {
llvm::StringRef key;
std::function<std::string()> thunk;
};
/// A wrapper for linking remarks by query - searches the engine's registry
/// at stream time and links to all matching remarks.
/// InFlightRemark is a RAII class that holds a reference to a Remark
/// instance and allows to build the remark using the << operator. The remark
/// is emitted when the InFlightRemark instance is destroyed, which happens
/// when the scope ends or when the InFlightRemark instance is moved.
/// Similar to InFlightDiagnostic, but for remarks.
class InFlightRemark {
public:
explicit InFlightRemark(std::unique_ptr<Remark> diag)
: remark(std::move(diag)) {}
InFlightRemark(RemarkEngine &eng, std::unique_ptr<Remark> diag)
: owner(&eng), remark(std::move(diag)) {}
InFlightRemark() = default; // empty ctor
InFlightRemark &operator<<(const LazyTextBuild &l) {
if (remark)
*remark << Remark::Arg(l.key, l.thunk());
return *this;
}
// Generic path, but *not* for Lazy
template <typename T, typename = std::enable_if_t<
!std::is_same_v<std::decay_t<T>, LazyTextBuild>>>
InFlightRemark &operator<<(T &&arg) {
if (remark)
*remark << std::forward<T>(arg);
return *this;
}
explicit operator bool() const { return remark != nullptr; }
/// Get this remark's unique ID (for linking from other remarks).
RemarkId getId() const { return remark ? remark->getId() : RemarkId(); }
~InFlightRemark();
InFlightRemark(const InFlightRemark &) = delete;
InFlightRemark &operator=(const InFlightRemark &) = delete;
InFlightRemark(InFlightRemark &&) = default;
InFlightRemark &operator=(InFlightRemark &&) = default;
private:
RemarkEngine *owner{nullptr};
std::unique_ptr<Remark> remark;
};
//===----------------------------------------------------------------------===//
// Pluggable Remark Utilities
//===----------------------------------------------------------------------===//
/// Base class for MLIR remark streamers that is used to stream
/// optimization remarks to the underlying remark streamer. The derived classes
/// should implement the `streamOptimizationRemark` method to provide the
/// actual streaming implementation.
class MLIRRemarkStreamerBase {
public:
virtual ~MLIRRemarkStreamerBase() = default;
/// Stream an optimization remark to the underlying remark streamer. It is
/// called by the RemarkEngine to stream the optimization remarks.
///
/// It must be overridden by the derived classes to provide
/// the actual streaming implementation.
virtual void streamOptimizationRemark(const Remark &remark) = 0;
virtual void finalize() {} // optional
};
using ReportFn = llvm::unique_function<void(const Remark &)>;
/// Base class for MLIR remark emitting policies that is used to emit
/// optimization remarks to the underlying remark streamer. The derived classes
/// should implement the `reportRemark` method to provide the actual emitting
/// implementation.
class RemarkEmittingPolicyBase {
protected:
ReportFn reportImpl;
public:
RemarkEmittingPolicyBase() = default;
virtual ~RemarkEmittingPolicyBase() = default;
void initialize(ReportFn fn) { reportImpl = std::move(fn); }
virtual void reportRemark(const Remark &remark) = 0;
virtual void finalize() = 0;
/// Find previously reported remarks matching the given criteria.
/// Default returns empty -- only policies that store remarks (like
/// PolicyFinal) override this to enable query-based linking.
virtual SmallVector<RemarkId>
findRemarks(const RemarkOpts &opts,
std::optional<RemarkKind> kind = std::nullopt) const {
return {};
}
};
//===----------------------------------------------------------------------===//
// Remark Engine (MLIR Context will own this class)
//===----------------------------------------------------------------------===//
class RemarkEngine {
private:
/// Regex that filters missed optimization remarks: only matching one are
/// reported.
std::optional<llvm::Regex> missFilter;
/// The category for passed optimization remarks.
std::optional<llvm::Regex> passedFilter;
/// The category for analysis remarks.
std::optional<llvm::Regex> analysisFilter;
/// The category for failed optimization remarks.
std::optional<llvm::Regex> failedFilter;
/// The MLIR remark streamer that will be used to emit the remarks.
std::unique_ptr<MLIRRemarkStreamerBase> remarkStreamer;
/// The MLIR remark policy that will be used to emit the remarks.
std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy;
/// When is enabled, engine also prints remarks as mlir::emitRemarks.
bool printAsEmitRemarks = false;
/// Atomic counter for generating unique remark IDs.
std::atomic<uint64_t> nextRemarkId{1};
/// Return true if missed optimization remarks are enabled, override
/// to provide different implementation.
bool isMissedOptRemarkEnabled(StringRef categoryName) const;
/// Return true if passed optimization remarks are enabled, override
/// to provide different implementation.
bool isPassedOptRemarkEnabled(StringRef categoryName) const;
/// Return true if analysis optimization remarks are enabled, override
/// to provide different implementation.
bool isAnalysisOptRemarkEnabled(StringRef categoryName) const;
/// Return true if analysis optimization remarks are enabled, override
/// to provide different implementation.
bool isFailedOptRemarkEnabled(StringRef categoryName) const;
/// Return true if any type of remarks are enabled for this pass.
bool isAnyRemarkEnabled(StringRef categoryName) const {
return isMissedOptRemarkEnabled(categoryName) ||
isPassedOptRemarkEnabled(categoryName) ||
isFailedOptRemarkEnabled(categoryName) ||
isAnalysisOptRemarkEnabled(categoryName);
}
/// Emit a remark using the given maker function, which should return
/// a Remark instance. The remark will be emitted using the main
/// remark streamer.
template <typename RemarkT>
InFlightRemark makeRemark(Location loc, RemarkOpts opts);
template <typename RemarkT>
InFlightRemark emitIfEnabled(Location loc, RemarkOpts opts,
bool (RemarkEngine::*isEnabled)(StringRef)
const);
/// Report a remark.
void reportImpl(const Remark &remark);
public:
/// Default constructor is deleted, use the other constructor.
RemarkEngine() = delete;
/// Constructs Remark engine with optional category names. If a category
/// name is not provided, it is not enabled. The category names are used to
/// filter the remarks that are emitted.
RemarkEngine(bool printAsEmitRemarks, const RemarkCategories &cats);
/// Destructor that will close the output file and reset the
/// main remark streamer.
~RemarkEngine();
/// Setup the remark engine with the given output path and format.
LogicalResult
initialize(std::unique_ptr<MLIRRemarkStreamerBase> streamer,
std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy,
std::string *errMsg);
/// Get the remark emitting policy.
RemarkEmittingPolicyBase *getRemarkEmittingPolicy() const {
return remarkEmittingPolicy.get();
}
/// Generate a unique ID for a new remark.
RemarkId generateRemarkId() {
return RemarkId(nextRemarkId.fetch_add(1, std::memory_order_relaxed));
}
//===--------------------------------------------------------------------===//
// Remark Linking - query previously emitted remarks
//===--------------------------------------------------------------------===//
/// Find all remarks matching the given criteria. Delegates to the
/// emitting policy. Only works with policies that store remarks
/// (e.g. RemarkEmittingPolicyFinal); returns empty for PolicyAll.
SmallVector<RemarkId>
findRemarks(const RemarkOpts &opts,
std::optional<RemarkKind> kind = std::nullopt) const;
/// Report a remark.
void report(const Remark &&remark);
/// Report a successful remark, this will create an InFlightRemark
/// that can be used to build the remark using the << operator.
InFlightRemark emitOptimizationRemark(Location loc, RemarkOpts opts);
/// Report a missed optimization remark
/// that can be used to build the remark using the << operator.
InFlightRemark emitOptimizationRemarkMiss(Location loc, RemarkOpts opts);
/// Report a failed optimization remark, this will create an InFlightRemark
/// that can be used to build the remark using the << operator.
InFlightRemark emitOptimizationRemarkFailure(Location loc, RemarkOpts opts);
/// Report an analysis remark, this will create an InFlightRemark
/// that can be used to build the remark using the << operator.
InFlightRemark emitOptimizationRemarkAnalysis(Location loc, RemarkOpts opts);
};
template <typename Fn, typename... Args>
inline InFlightRemark withEngine(Fn fn, Location loc, Args &&...args) {
MLIRContext *ctx = loc->getContext();
RemarkEngine *enginePtr = ctx->getRemarkEngine();
if (LLVM_UNLIKELY(enginePtr))
return (enginePtr->*fn)(loc, std::forward<Args>(args)...);
return {};
}
} // namespace mlir::remark::detail
// Deferred definition: needs InFlightRemark to be complete.
inline mlir::remark::RemarkOpts
mlir::remark::RemarkOpts::relatedTo(const detail::InFlightRemark &r) const {
return relatedTo(r.getId());
}
namespace mlir::remark {
//===----------------------------------------------------------------------===//
// Remark Emitting Policies
//===----------------------------------------------------------------------===//
/// Policy that emits all remarks.
class RemarkEmittingPolicyAll : public detail::RemarkEmittingPolicyBase {
public:
RemarkEmittingPolicyAll();
void reportRemark(const detail::Remark &remark) override {
assert(reportImpl && "reportImpl is not set");
reportImpl(remark);
}
void finalize() override {}
};
/// Policy that emits final remarks. Stores all remarks until finalize(),
/// which enables query-based linking via findRemarks().
class RemarkEmittingPolicyFinal : public detail::RemarkEmittingPolicyBase {
private:
/// user can intercept them for custom processing via a registered callback,
/// otherwise they will be reported on engine destruction.
llvm::DenseSet<detail::Remark> postponedRemarks;
public:
RemarkEmittingPolicyFinal();
void reportRemark(const detail::Remark &remark) override {
postponedRemarks.erase(remark);
postponedRemarks.insert(remark);
}
/// Emits all stored remarks. Related remarks are printed as nested notes
/// under the remark that references them.
void finalize() override;
};
/// Create a Reason with llvm::formatv formatting.
template <class... Ts>
inline detail::LazyTextBuild reason(const char *fmt, Ts &&...ts) {
return {"Reason", [=] { return llvm::formatv(fmt, ts...).str(); }};
}
/// Create a Suggestion with llvm::formatv formatting.
template <class... Ts>
inline detail::LazyTextBuild suggest(const char *fmt, Ts &&...ts) {
return {"Suggestion", [=] { return llvm::formatv(fmt, ts...).str(); }};
}
/// Create a Remark with llvm::formatv formatting.
template <class... Ts>
inline detail::LazyTextBuild add(const char *fmt, Ts &&...ts) {
return {"Remark", [=] { return llvm::formatv(fmt, ts...).str(); }};
}
template <class V>
inline detail::LazyTextBuild metric(StringRef key, V &&v) {
using DV = std::decay_t<V>;
return {key, [key, vv = DV(std::forward<V>(v))]() mutable {
// Reuse Arg's formatting logic and return just the value string.
return detail::Remark::Arg(key, std::move(vv)).val;
}};
}
//===----------------------------------------------------------------------===//
// Emitters
//===----------------------------------------------------------------------===//
/// Report an optimization remark that was passed.
inline detail::InFlightRemark passed(Location loc, RemarkOpts opts) {
return withEngine(&detail::RemarkEngine::emitOptimizationRemark, loc, opts);
}
/// Report an optimization remark that was missed.
inline detail::InFlightRemark missed(Location loc, RemarkOpts opts) {
return withEngine(&detail::RemarkEngine::emitOptimizationRemarkMiss, loc,
opts);
}
/// Report an optimization remark that failed.
inline detail::InFlightRemark failed(Location loc, RemarkOpts opts) {
return withEngine(&detail::RemarkEngine::emitOptimizationRemarkFailure, loc,
opts);
}
/// Report an optimization analysis remark.
inline detail::InFlightRemark analysis(Location loc, RemarkOpts opts) {
return withEngine(&detail::RemarkEngine::emitOptimizationRemarkAnalysis, loc,
opts);
}
//===----------------------------------------------------------------------===//
// Setup
//===----------------------------------------------------------------------===//
/// Setup remarks for the context. This function will enable the remark engine
/// and set the streamer to be used for optimization remarks. The remark
/// categories are used to filter the remarks that will be emitted by the
/// remark engine. If a category is not specified, it will not be emitted. If
/// `printAsEmitRemarks` is true, the remarks will be printed as
/// mlir::emitRemarks. 'streamer' must inherit from MLIRRemarkStreamerBase and
/// will be used to stream the remarks.
LogicalResult enableOptimizationRemarks(
MLIRContext &ctx,
std::unique_ptr<remark::detail::MLIRRemarkStreamerBase> streamer,
std::unique_ptr<remark::detail::RemarkEmittingPolicyBase>
remarkEmittingPolicy,
const remark::RemarkCategories &cats, bool printAsEmitRemarks = false);
} // namespace mlir::remark
// DenseMapInfo specialization for Remark
namespace llvm {
template <>
struct DenseMapInfo<mlir::remark::detail::Remark> {
static constexpr StringRef kEmptyKey = "<EMPTY_KEY>";
/// Helper to provide a static dummy context for sentinel keys.
static mlir::MLIRContext *getStaticDummyContext() {
static mlir::MLIRContext dummyContext;
return &dummyContext;
}
/// Create an empty remark
/// Compute the hash value of the remark
static unsigned getHashValue(const mlir::remark::detail::Remark &remark) {
return llvm::hash_combine(
remark.getLocation().getAsOpaquePointer(),
llvm::hash_value(remark.getRemarkName()),
llvm::hash_value(remark.getCombinedCategoryName()),
static_cast<unsigned>(remark.getRemarkKind()));
}
static bool isEqual(const mlir::remark::detail::Remark &lhs,
const mlir::remark::detail::Remark &rhs) {
// Check for empty keys first.
if (lhs.getRemarkName() == kEmptyKey || rhs.getRemarkName() == kEmptyKey) {
return lhs.getRemarkName() == rhs.getRemarkName();
}
// For regular remarks, compare key identifying fields
return lhs.getLocation() == rhs.getLocation() &&
lhs.getRemarkName() == rhs.getRemarkName() &&
lhs.getCombinedCategoryName() == rhs.getCombinedCategoryName() &&
lhs.getRemarkKind() == rhs.getRemarkKind();
}
};
} // namespace llvm
#endif // MLIR_IR_REMARKS_H