MLIR 24.0.0git
Remarks.cpp
Go to the documentation of this file.
1//===- Remarks.cpp - MLIR Remarks -----------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "mlir/IR/Remarks.h"
10
12#include "mlir/IR/Diagnostics.h"
13#include "mlir/IR/Value.h"
14
15#include "llvm/ADT/StringExtras.h"
16#include "llvm/ADT/StringRef.h"
17
18using namespace mlir::remark::detail;
19using namespace mlir::remark;
20//------------------------------------------------------------------------------
21// Remark
22//------------------------------------------------------------------------------
23
24Remark::Arg::Arg(llvm::StringRef k, Value v) : key(k) {
25 llvm::raw_string_ostream os(val);
26 os << v;
27}
28
29Remark::Arg::Arg(llvm::StringRef k, Type t) : key(k) {
30 llvm::raw_string_ostream os(val);
31 os << t;
32}
33
34Remark::Arg::Arg(llvm::StringRef k, Attribute a) : key(k), attr(a) {
35 llvm::raw_string_ostream os(val);
36 os << a;
37}
38
39void Remark::insert(llvm::StringRef s) { args.emplace_back(s); }
40void Remark::insert(Arg a) { args.push_back(std::move(a)); }
41
42// Simple helper to print key=val list (sorted).
43static void printArgs(llvm::raw_ostream &os, llvm::ArrayRef<Remark::Arg> args) {
44 if (args.empty())
45 return;
46
47 llvm::SmallVector<Remark::Arg, 8> sorted(args.begin(), args.end());
48 llvm::sort(sorted, [](const Remark::Arg &a, const Remark::Arg &b) {
49 return a.key < b.key;
50 });
51
52 for (size_t i = 0; i < sorted.size(); ++i) {
53 const auto &a = sorted[i];
54 os << a.key << "=";
55
56 llvm::StringRef val(a.val);
57 bool needsQuote = val.contains(' ') || val.contains(',') ||
58 val.contains('{') || val.contains('}');
59 if (needsQuote)
60 os << '"' << val << '"';
61 else
62 os << val;
63
64 if (i + 1 < sorted.size())
65 os << ", ";
66 }
67}
68
69/// Print the remark to the given output stream.
70/// Example output:
71// clang-format off
72/// [Missed] Category: Loop | Pass:Unroller | Function=main | Reason="tripCount=4 < threshold=256"
73/// [Failure] LoopOptimizer | Reason="failed due to unsupported pattern"
74// clang-format on
75void Remark::print(llvm::raw_ostream &os, bool printLocation) const {
76 // Header: [Type] pass:remarkName
77 StringRef type = getRemarkTypeString();
79 StringRef name = remarkName;
80
81 os << '[' << type << "] ";
82 os << name << " | ";
83 if (!categoryName.empty())
84 os << "Category:" << categoryName << " | ";
85 if (!functionName.empty())
86 os << "Function=" << getFunction() << " | ";
87
88 if (printLocation) {
89 if (auto flc = mlir::dyn_cast<mlir::FileLineColLoc>(getLocation())) {
90 os << " @" << flc.getFilename() << ":" << flc.getLine() << ":"
91 << flc.getColumn();
92 }
93 }
94
95 printArgs(os, getArgs());
96}
97
98std::string Remark::getMsg() const {
99 std::string s;
100 llvm::raw_string_ostream os(s);
101 print(os);
102 os.flush();
103 return s;
104}
105
106llvm::StringRef Remark::getRemarkTypeString() const {
107 switch (remarkKind) {
109 return "Unknown";
111 return "Passed";
113 return "Missed";
115 return "Failure";
117 return "Analysis";
118 }
119 llvm_unreachable("Unknown remark kind");
120}
121
122llvm::remarks::Type Remark::getRemarkType() const {
123 switch (remarkKind) {
125 return llvm::remarks::Type::Unknown;
127 return llvm::remarks::Type::Passed;
129 return llvm::remarks::Type::Missed;
131 return llvm::remarks::Type::Failure;
133 return llvm::remarks::Type::Analysis;
134 }
135 llvm_unreachable("Unknown remark kind");
136}
137
138llvm::remarks::Remark Remark::generateRemark() const {
139 auto locLambda = [&]() -> llvm::remarks::RemarkLocation {
140 if (auto flc = dyn_cast<FileLineColLoc>(getLocation()))
141 return {flc.getFilename(), flc.getLine(), flc.getColumn()};
142 return {"<unknown file>", 0, 0};
143 };
144
145 llvm::remarks::Remark r; // The result.
146 r.RemarkType = getRemarkType();
147 r.RemarkName = getRemarkName();
148 // MLIR does not use passes; instead, it has categories and sub-categories.
149 r.PassName = getCombinedCategoryName();
150 r.FunctionName = getFunction();
151 r.Loc = locLambda();
152 // Add all args (includes RemarkId and RelatedTo if they were added).
153 for (const Remark::Arg &arg : getArgs()) {
154 r.Args.emplace_back();
155 r.Args.back().Key = arg.key;
156 r.Args.back().Val = arg.val;
157 }
158 return r;
159}
160
161//===----------------------------------------------------------------------===//
162// InFlightRemark
163//===----------------------------------------------------------------------===//
164
166 if (remark && owner)
167 owner->report(std::move(*remark));
168 owner = nullptr;
169}
170
171//===----------------------------------------------------------------------===//
172// Remark Engine
173//===----------------------------------------------------------------------===//
174
175template <typename RemarkT>
176InFlightRemark RemarkEngine::makeRemark(Location loc, RemarkOpts opts) {
177 static_assert(std::is_base_of_v<Remark, RemarkT>,
178 "RemarkT must derive from Remark");
179 auto remark = std::make_unique<RemarkT>(loc, opts);
180 remark->setId(generateRemarkId());
181 return InFlightRemark(*this, std::move(remark));
182}
183
184template <typename RemarkT>
186RemarkEngine::emitIfEnabled(Location loc, RemarkOpts opts,
187 bool (RemarkEngine::*isEnabled)(StringRef) const) {
188 return (this->*isEnabled)(opts.categoryName) ? makeRemark<RemarkT>(loc, opts)
189 : InFlightRemark{};
190}
191
193 return missFilter && missFilter->match(categoryName);
194}
195
197 return passedFilter && passedFilter->match(categoryName);
198}
199
201 return analysisFilter && analysisFilter->match(categoryName);
202}
203
205 return failedFilter && failedFilter->match(categoryName);
206}
207
209 StringRef categoryName) const {
210 switch (kind) {
212 return false;
221 }
222 llvm_unreachable("Unknown remark kind");
223}
224
226 RemarkOpts opts) {
227 return emitIfEnabled<OptRemarkPass>(loc, opts,
229}
230
232 RemarkOpts opts) {
233 return emitIfEnabled<OptRemarkMissed>(
235}
236
238 RemarkOpts opts) {
239 return emitIfEnabled<OptRemarkFailure>(
241}
242
244 RemarkOpts opts) {
245 return emitIfEnabled<OptRemarkAnalysis>(
247}
248
249//===----------------------------------------------------------------------===//
250// RemarkEngine
251//===----------------------------------------------------------------------===//
252
253void RemarkEngine::reportImpl(const Remark &remark) {
254 // Stream the remark
255 if (remarkStreamer) {
256 remarkStreamer->streamOptimizationRemark(remark);
257 }
258
259 // Print using MLIR's diagnostic
260 if (printAsEmitRemarks)
261 emitRemark(remark.getLocation(), remark.getMsg());
262}
263
265 if (remarkEmittingPolicy)
266 remarkEmittingPolicy->reportRemark(remark);
267}
268
270 if (remarkEmittingPolicy)
271 remarkEmittingPolicy->finalize();
272
273 if (remarkStreamer)
274 remarkStreamer->finalize();
275}
276
277llvm::LogicalResult RemarkEngine::initialize(
278 std::unique_ptr<MLIRRemarkStreamerBase> streamer,
279 std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy,
280 std::string *errMsg) {
281 remarkStreamer = std::move(streamer);
282
283 auto reportFunc = llvm::bind_front<&RemarkEngine::reportImpl>(this);
284 remarkEmittingPolicy->initialize(ReportFn(std::move(reportFunc)));
285
286 this->remarkEmittingPolicy = std::move(remarkEmittingPolicy);
287 return success();
288}
289
290/// Returns true if filter is already anchored like ^...$
291static bool isAnchored(llvm::StringRef s) {
292 s = s.trim();
293 return s.starts_with("^") && s.ends_with("$"); // note: startswith/endswith
294}
295
296/// Anchor the entire pattern so it matches the whole string.
297static std::string anchorWhole(llvm::StringRef filter) {
298 if (isAnchored(filter))
299 return filter.str();
300 return (llvm::Twine("^(") + filter + ")$").str();
301}
302
303/// Build a combined filter from cats.all and a category-specific pattern.
304/// If neither is present, return std::nullopt. Otherwise "(all|specific)"
305/// and anchor once. Also validate before returning.
306static std::optional<llvm::Regex>
308 const std::optional<std::string> &specific) {
310 if (cats.all && !cats.all->empty())
311 parts.emplace_back(*cats.all);
312 if (specific && !specific->empty())
313 parts.emplace_back(*specific);
314
315 if (parts.empty())
316 return std::nullopt;
317
318 std::string joined = llvm::join(parts, "|");
319 std::string anchored = anchorWhole(joined);
320
321 llvm::Regex rx(anchored);
322 std::string err;
323 if (!rx.isValid(err))
324 return std::nullopt;
325
326 return std::make_optional<llvm::Regex>(std::move(rx));
327}
328
329RemarkEngine::RemarkEngine(bool printAsEmitRemarks,
330 const RemarkCategories &cats)
331 : printAsEmitRemarks(printAsEmitRemarks) {
332 if (cats.passed)
333 passedFilter = buildFilter(cats, cats.passed);
334 if (cats.missed)
335 missFilter = buildFilter(cats, cats.missed);
336 if (cats.analysis)
337 analysisFilter = buildFilter(cats, cats.analysis);
338 if (cats.failed)
339 failedFilter = buildFilter(cats, cats.failed);
340}
341
343 MLIRContext &ctx, std::unique_ptr<detail::MLIRRemarkStreamerBase> streamer,
344 std::unique_ptr<detail::RemarkEmittingPolicyBase> remarkEmittingPolicy,
345 const RemarkCategories &cats, bool printAsEmitRemarks) {
346 auto engine =
347 std::make_unique<detail::RemarkEngine>(printAsEmitRemarks, cats);
348
349 std::string errMsg;
350 if (failed(engine->initialize(std::move(streamer),
351 std::move(remarkEmittingPolicy), &errMsg))) {
352 llvm::report_fatal_error(
353 llvm::Twine("Failed to initialize remark engine. Error: ") + errMsg);
354 }
355 ctx.setRemarkEngine(std::move(engine));
356
357 return success();
358}
359
360//===----------------------------------------------------------------------===//
361// Remark emitting policies
362//===----------------------------------------------------------------------===//
363
364namespace mlir::remark {
367
369 assert(reportImpl && "reportImpl is not set");
370
371 // Build ID -> Remark* lookup for resolving related remark references.
373 llvm::DenseSet<uint64_t> childIds; // IDs referenced as children
374
375 for (const auto &remark : postponedRemarks) {
376 if (remark.getId())
377 idMap[remark.getId().getValue()] = &remark;
378 for (auto relId : remark.getRelatedRemarkIds())
379 childIds.insert(relId.getValue());
380 }
381
382 // Emit remarks with related remarks grouped after their parents.
383 // Parent remarks are emitted first, followed by their related (child)
384 // remarks. Child-only remarks are skipped at the top level to avoid
385 // duplication.
386 for (const auto &remark : postponedRemarks) {
387 if (remark.getId() && childIds.count(remark.getId().getValue()))
388 continue; // will be printed grouped under its parent
389
391
392 // Emit related remarks immediately after the parent.
393 for (auto relId : remark.getRelatedRemarkIds()) {
394 if (const auto *related = idMap.lookup(relId.getValue()))
395 reportImpl(*related);
396 }
397 }
398}
399
400} // namespace mlir::remark
return success()
if(failed(verifyVectorMemoryOp(getOperation(), memrefType, getVectorType()))) return failure()
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
static bool isAnchored(llvm::StringRef s)
Returns true if filter is already anchored like ^...$.
Definition Remarks.cpp:291
static void printArgs(llvm::raw_ostream &os, llvm::ArrayRef< Remark::Arg > args)
Definition Remarks.cpp:43
static std::string anchorWhole(llvm::StringRef filter)
Anchor the entire pattern so it matches the whole string.
Definition Remarks.cpp:297
static std::optional< llvm::Regex > buildFilter(const mlir::remark::RemarkCategories &cats, const std::optional< std::string > &specific)
Build a combined filter from cats.all and a category-specific pattern.
Definition Remarks.cpp:307
Attributes are known-constant values of operations.
Definition Attributes.h:25
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
void setRemarkEngine(std::unique_ptr< remark::detail::RemarkEngine > engine)
Set the remark engine for this context.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
void finalize() override
Emits all stored remarks.
Definition Remarks.cpp:368
A wrapper for linking remarks by query - searches the engine's registry at stream time and links to a...
Definition Remarks.h:402
InFlightRemark emitOptimizationRemarkFailure(Location loc, RemarkOpts opts)
Report a failed optimization remark, this will create an InFlightRemark that can be used to build the...
Definition Remarks.cpp:237
bool isPassedOptRemarkEnabled(StringRef categoryName) const
Return true if passed optimization remarks are enabled for the given category.
Definition Remarks.cpp:196
void report(const Remark &&remark)
Report a remark.
Definition Remarks.cpp:264
bool isMissedOptRemarkEnabled(StringRef categoryName) const
Return true if missed optimization remarks are enabled for the given category.
Definition Remarks.cpp:192
InFlightRemark emitOptimizationRemark(Location loc, RemarkOpts opts)
Report a successful remark, this will create an InFlightRemark that can be used to build the remark u...
Definition Remarks.cpp:225
LogicalResult initialize(std::unique_ptr< MLIRRemarkStreamerBase > streamer, std::unique_ptr< RemarkEmittingPolicyBase > remarkEmittingPolicy, std::string *errMsg)
Setup the remark engine with the given output path and format.
Definition Remarks.cpp:277
RemarkEngine()=delete
Default constructor is deleted, use the other constructor.
bool isAnalysisOptRemarkEnabled(StringRef categoryName) const
Return true if analysis remarks are enabled for the given category.
Definition Remarks.cpp:200
bool isRemarkEnabled(RemarkKind kind, StringRef categoryName) const
Return true if remarks of the given kind are enabled for the given category.
Definition Remarks.cpp:208
InFlightRemark emitOptimizationRemarkMiss(Location loc, RemarkOpts opts)
Report a missed optimization remark that can be used to build the remark using the << operator.
Definition Remarks.cpp:231
~RemarkEngine()
Destructor that will close the output file and reset the main remark streamer.
Definition Remarks.cpp:269
bool isFailedOptRemarkEnabled(StringRef categoryName) const
Return true if failed optimization remarks are enabled for the given category.
Definition Remarks.cpp:204
InFlightRemark emitOptimizationRemarkAnalysis(Location loc, RemarkOpts opts)
Report an analysis remark, this will create an InFlightRemark that can be used to build the remark us...
Definition Remarks.cpp:243
std::string functionName
Name of the covering function like interface.
Definition Remarks.h:285
void print(llvm::raw_ostream &os, bool printLocation=false) const
Print the remark to the given output stream.
Definition Remarks.cpp:75
ArrayRef< Arg > getArgs() const
Definition Remarks.h:241
SmallVector< Arg, 4 > args
Args collected via the streaming interface.
Definition Remarks.h:304
StringRef getFunction() const
Definition Remarks.h:215
llvm::remarks::Type getRemarkType() const
Definition Remarks.cpp:122
StringRef getRemarkTypeString() const
Definition Remarks.cpp:106
std::string remarkName
Remark identifier.
Definition Remarks.h:301
Location getLocation() const
Definition Remarks.h:211
llvm::StringRef getCombinedCategoryName() const
Definition Remarks.h:223
RemarkKind remarkKind
Keeps the MLIR diagnostic kind, which is used to determine the diagnostic kind in the LLVM remark str...
Definition Remarks.h:282
StringRef getRemarkName() const
Definition Remarks.h:233
void insert(llvm::StringRef s)
Definition Remarks.cpp:39
llvm::remarks::Remark generateRemark() const
Diagnostic -> Remark.
Definition Remarks.cpp:138
std::string categoryName
Category name e.g., "Unroll" or "UnrollAndJam".
Definition Remarks.h:290
std::string getMsg() const
Definition Remarks.cpp:98
llvm::unique_function< void(const Remark &)> ReportFn
Definition Remarks.h:465
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:732
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)
Setup remarks for the context.
RemarkKind
Categories describe the outcome of an transformation, not the mechanics of emitting/serializing remar...
Definition Remarks.h:70
@ RemarkPassed
An optimization was applied.
Definition Remarks.h:74
@ RemarkAnalysis
Informational context (e.g., analysis numbers) without a pass/fail outcome.
Definition Remarks.h:85
@ RemarkMissed
A profitable optimization opportunity was found but not applied.
Definition Remarks.h:77
@ RemarkFailure
The compiler attempted the optimization but failed (e.g., legality checks, or better opportunites).
Definition Remarks.h:81
InFlightDiagnostic emitRemark(Location loc)
Utility method to emit a remark message using this location.
Define an the set of categories to accept.
Definition Remarks.h:64
std::optional< std::string > missed
Definition Remarks.h:65
std::optional< std::string > all
Definition Remarks.h:65
std::optional< std::string > passed
Definition Remarks.h:65
std::optional< std::string > analysis
Definition Remarks.h:65
std::optional< std::string > failed
Definition Remarks.h:65
Options to create a Remark.
Definition Remarks.h:95
std::optional< Attribute > attr
Optional attribute storage for Attribute-based args.
Definition Remarks.h:174