MLIR 22.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
34void Remark::insert(llvm::StringRef s) { args.emplace_back(s); }
35void Remark::insert(Arg a) { args.push_back(std::move(a)); }
36
37// Simple helper to print key=val list (sorted).
38static void printArgs(llvm::raw_ostream &os, llvm::ArrayRef<Remark::Arg> args) {
39 if (args.empty())
40 return;
41
42 llvm::SmallVector<Remark::Arg, 8> sorted(args.begin(), args.end());
43 llvm::sort(sorted, [](const Remark::Arg &a, const Remark::Arg &b) {
44 return a.key < b.key;
45 });
46
47 for (size_t i = 0; i < sorted.size(); ++i) {
48 const auto &a = sorted[i];
49 os << a.key << "=";
50
51 llvm::StringRef val(a.val);
52 bool needsQuote = val.contains(' ') || val.contains(',') ||
53 val.contains('{') || val.contains('}');
54 if (needsQuote)
55 os << '"' << val << '"';
56 else
57 os << val;
58
59 if (i + 1 < sorted.size())
60 os << ", ";
61 }
62}
63
64/// Print the remark to the given output stream.
65/// Example output:
66// clang-format off
67/// [Missed] Category: Loop | Pass:Unroller | Function=main | Reason="tripCount=4 < threshold=256"
68/// [Failure] LoopOptimizer | Reason="failed due to unsupported pattern"
69// clang-format on
70void Remark::print(llvm::raw_ostream &os, bool printLocation) const {
71 // Header: [Type] pass:remarkName
72 StringRef type = getRemarkTypeString();
74 StringRef name = remarkName;
75
76 os << '[' << type << "] ";
77 os << name << " | ";
78 if (!categoryName.empty())
79 os << "Category:" << categoryName << " | ";
80 if (!functionName.empty())
81 os << "Function=" << getFunction() << " | ";
82
83 if (printLocation) {
84 if (auto flc = mlir::dyn_cast<mlir::FileLineColLoc>(getLocation())) {
85 os << " @" << flc.getFilename() << ":" << flc.getLine() << ":"
86 << flc.getColumn();
87 }
88 }
89
90 printArgs(os, getArgs());
91}
92
93std::string Remark::getMsg() const {
94 std::string s;
95 llvm::raw_string_ostream os(s);
96 print(os);
97 os.flush();
98 return s;
99}
100
101llvm::StringRef Remark::getRemarkTypeString() const {
102 switch (remarkKind) {
104 return "Unknown";
106 return "Passed";
108 return "Missed";
110 return "Failure";
112 return "Analysis";
113 }
114 llvm_unreachable("Unknown remark kind");
115}
116
117llvm::remarks::Type Remark::getRemarkType() const {
118 switch (remarkKind) {
120 return llvm::remarks::Type::Unknown;
122 return llvm::remarks::Type::Passed;
124 return llvm::remarks::Type::Missed;
126 return llvm::remarks::Type::Failure;
128 return llvm::remarks::Type::Analysis;
129 }
130 llvm_unreachable("Unknown remark kind");
131}
132
133llvm::remarks::Remark Remark::generateRemark() const {
134 auto locLambda = [&]() -> llvm::remarks::RemarkLocation {
135 if (auto flc = dyn_cast<FileLineColLoc>(getLocation()))
136 return {flc.getFilename(), flc.getLine(), flc.getColumn()};
137 return {"<unknown file>", 0, 0};
138 };
139
140 llvm::remarks::Remark r; // The result.
141 r.RemarkType = getRemarkType();
142 r.RemarkName = getRemarkName();
143 // MLIR does not use passes; instead, it has categories and sub-categories.
144 r.PassName = getCombinedCategoryName();
145 r.FunctionName = getFunction();
146 r.Loc = locLambda();
147 for (const Remark::Arg &arg : getArgs()) {
148 r.Args.emplace_back();
149 r.Args.back().Key = arg.key;
150 r.Args.back().Val = arg.val;
151 }
152 return r;
153}
154
155//===----------------------------------------------------------------------===//
156// InFlightRemark
157//===----------------------------------------------------------------------===//
158
160 if (remark && owner)
161 owner->report(std::move(*remark));
162 owner = nullptr;
163}
164
165//===----------------------------------------------------------------------===//
166// Remark Engine
167//===----------------------------------------------------------------------===//
168
169template <typename RemarkT, typename... Args>
170InFlightRemark RemarkEngine::makeRemark(Args &&...args) {
171 static_assert(std::is_base_of_v<Remark, RemarkT>,
172 "RemarkT must derive from Remark");
173 return InFlightRemark(*this,
174 std::make_unique<RemarkT>(std::forward<Args>(args)...));
175}
176
177template <typename RemarkT>
179RemarkEngine::emitIfEnabled(Location loc, RemarkOpts opts,
180 bool (RemarkEngine::*isEnabled)(StringRef) const) {
181 return (this->*isEnabled)(opts.categoryName) ? makeRemark<RemarkT>(loc, opts)
182 : InFlightRemark{};
183}
184
185bool RemarkEngine::isMissedOptRemarkEnabled(StringRef categoryName) const {
186 return missFilter && missFilter->match(categoryName);
187}
188
189bool RemarkEngine::isPassedOptRemarkEnabled(StringRef categoryName) const {
190 return passedFilter && passedFilter->match(categoryName);
191}
192
193bool RemarkEngine::isAnalysisOptRemarkEnabled(StringRef categoryName) const {
194 return analysisFilter && analysisFilter->match(categoryName);
195}
196
197bool RemarkEngine::isFailedOptRemarkEnabled(StringRef categoryName) const {
198 return failedFilter && failedFilter->match(categoryName);
199}
200
202 RemarkOpts opts) {
203 return emitIfEnabled<OptRemarkPass>(loc, opts,
204 &RemarkEngine::isPassedOptRemarkEnabled);
205}
206
208 RemarkOpts opts) {
209 return emitIfEnabled<OptRemarkMissed>(
210 loc, opts, &RemarkEngine::isMissedOptRemarkEnabled);
211}
212
214 RemarkOpts opts) {
215 return emitIfEnabled<OptRemarkFailure>(
216 loc, opts, &RemarkEngine::isFailedOptRemarkEnabled);
217}
218
220 RemarkOpts opts) {
221 return emitIfEnabled<OptRemarkAnalysis>(
222 loc, opts, &RemarkEngine::isAnalysisOptRemarkEnabled);
223}
224
225//===----------------------------------------------------------------------===//
226// RemarkEngine
227//===----------------------------------------------------------------------===//
228
229void RemarkEngine::reportImpl(const Remark &remark) {
230 // Stream the remark
231 if (remarkStreamer) {
232 remarkStreamer->streamOptimizationRemark(remark);
233 }
234
235 // Print using MLIR's diagnostic
236 if (printAsEmitRemarks)
237 emitRemark(remark.getLocation(), remark.getMsg());
238}
239
241 if (remarkEmittingPolicy)
242 remarkEmittingPolicy->reportRemark(remark);
243}
244
246 if (remarkEmittingPolicy)
247 remarkEmittingPolicy->finalize();
248
249 if (remarkStreamer)
250 remarkStreamer->finalize();
251}
252
253llvm::LogicalResult RemarkEngine::initialize(
254 std::unique_ptr<MLIRRemarkStreamerBase> streamer,
255 std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy,
256 std::string *errMsg) {
257
258 remarkStreamer = std::move(streamer);
259
260 auto reportFunc =
261 std::bind(&RemarkEngine::reportImpl, this, std::placeholders::_1);
262 remarkEmittingPolicy->initialize(ReportFn(std::move(reportFunc)));
263
264 this->remarkEmittingPolicy = std::move(remarkEmittingPolicy);
265 return success();
266}
267
268/// Returns true if filter is already anchored like ^...$
269static bool isAnchored(llvm::StringRef s) {
270 s = s.trim();
271 return s.starts_with("^") && s.ends_with("$"); // note: startswith/endswith
272}
273
274/// Anchor the entire pattern so it matches the whole string.
275static std::string anchorWhole(llvm::StringRef filter) {
276 if (isAnchored(filter))
277 return filter.str();
278 return (llvm::Twine("^(") + filter + ")$").str();
279}
280
281/// Build a combined filter from cats.all and a category-specific pattern.
282/// If neither is present, return std::nullopt. Otherwise "(all|specific)"
283/// and anchor once. Also validate before returning.
284static std::optional<llvm::Regex>
286 const std::optional<std::string> &specific) {
288 if (cats.all && !cats.all->empty())
289 parts.emplace_back(*cats.all);
290 if (specific && !specific->empty())
291 parts.emplace_back(*specific);
292
293 if (parts.empty())
294 return std::nullopt;
295
296 std::string joined = llvm::join(parts, "|");
297 std::string anchored = anchorWhole(joined);
298
299 llvm::Regex rx(anchored);
300 std::string err;
301 if (!rx.isValid(err))
302 return std::nullopt;
303
304 return std::make_optional<llvm::Regex>(std::move(rx));
305}
306
307RemarkEngine::RemarkEngine(bool printAsEmitRemarks,
308 const RemarkCategories &cats)
309 : printAsEmitRemarks(printAsEmitRemarks) {
310 if (cats.passed)
311 passedFilter = buildFilter(cats, cats.passed);
312 if (cats.missed)
313 missFilter = buildFilter(cats, cats.missed);
314 if (cats.analysis)
315 analysisFilter = buildFilter(cats, cats.analysis);
316 if (cats.failed)
317 failedFilter = buildFilter(cats, cats.failed);
318}
319
321 MLIRContext &ctx, std::unique_ptr<detail::MLIRRemarkStreamerBase> streamer,
322 std::unique_ptr<detail::RemarkEmittingPolicyBase> remarkEmittingPolicy,
323 const RemarkCategories &cats, bool printAsEmitRemarks) {
324 auto engine =
325 std::make_unique<detail::RemarkEngine>(printAsEmitRemarks, cats);
326
327 std::string errMsg;
328 if (failed(engine->initialize(std::move(streamer),
329 std::move(remarkEmittingPolicy), &errMsg))) {
330 llvm::report_fatal_error(
331 llvm::Twine("Failed to initialize remark engine. Error: ") + errMsg);
332 }
333 ctx.setRemarkEngine(std::move(engine));
334
335 return success();
336}
337
338//===----------------------------------------------------------------------===//
339// Remark emitting policies
340//===----------------------------------------------------------------------===//
341
342namespace mlir::remark {
345} // namespace mlir::remark
return success()
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
if(!isCopyOut)
static bool isAnchored(llvm::StringRef s)
Returns true if filter is already anchored like ^...$.
Definition Remarks.cpp:269
static void printArgs(llvm::raw_ostream &os, llvm::ArrayRef< Remark::Arg > args)
Definition Remarks.cpp:38
static std::string anchorWhole(llvm::StringRef filter)
Anchor the entire pattern so it matches the whole string.
Definition Remarks.cpp:275
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:285
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
InFlightRemark is a RAII class that holds a reference to a Remark instance and allows to build the re...
Definition Remarks.h:280
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:213
void report(const Remark &&remark)
Report a remark.
Definition Remarks.cpp:240
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:201
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:253
RemarkEngine()=delete
Default constructor is deleted, use the other constructor.
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:207
~RemarkEngine()
Destructor that will close the output file and reset the main remark streamer.
Definition Remarks.cpp:245
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:219
void print(llvm::raw_ostream &os, bool printLocation=false) const
Print the remark to the given output stream.
Definition Remarks.cpp:70
ArrayRef< Arg > getArgs() const
Definition Remarks.h:164
StringRef categoryName
Sub category passname e.g., "Unroll" or "UnrollAndJam".
Definition Remarks.h:179
SmallVector< Arg, 4 > args
Args collected via the streaming interface.
Definition Remarks.h:191
StringRef getFunction() const
Definition Remarks.h:138
llvm::remarks::Type getRemarkType() const
Definition Remarks.cpp:117
StringRef getRemarkTypeString() const
Definition Remarks.cpp:101
Location getLocation() const
Definition Remarks.h:134
StringRef remarkName
Remark identifier.
Definition Remarks.h:188
llvm::StringRef getCombinedCategoryName() const
Definition Remarks.h:146
RemarkKind remarkKind
Keeps the MLIR diagnostic kind, which is used to determine the diagnostic kind in the LLVM remark str...
Definition Remarks.h:173
StringRef getRemarkName() const
Definition Remarks.h:156
void insert(llvm::StringRef s)
Definition Remarks.cpp:34
StringRef functionName
Name of the convering function like interface.
Definition Remarks.h:175
llvm::remarks::Remark generateRemark() const
Diagnostic -> Remark.
Definition Remarks.cpp:133
std::string getMsg() const
Definition Remarks.cpp:93
llvm::unique_function< void(const Remark &)> ReportFn
Definition Remarks.h:340
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:561
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.
@ RemarkPassed
An optimization was applied.
Definition Remarks.h:40
@ RemarkAnalysis
Informational context (e.g., analysis numbers) without a pass/fail outcome.
Definition Remarks.h:51
@ RemarkMissed
A profitable optimization opportunity was found but not applied.
Definition Remarks.h:43
@ RemarkFailure
The compiler attempted the optimization but failed (e.g., legality checks, or better opportunites).
Definition Remarks.h:47
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:30
std::optional< std::string > missed
Definition Remarks.h:31
std::optional< std::string > all
Definition Remarks.h:31
std::optional< std::string > passed
Definition Remarks.h:31
std::optional< std::string > analysis
Definition Remarks.h:31
std::optional< std::string > failed
Definition Remarks.h:31
Options to create a Remark.
Definition Remarks.h:57