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
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 for (const Remark::Arg &arg : getArgs()) {
153 r.Args.emplace_back();
154 r.Args.back().Key = arg.key;
155 r.Args.back().Val = arg.val;
156 }
157 return r;
158}
159
160//===----------------------------------------------------------------------===//
161// InFlightRemark
162//===----------------------------------------------------------------------===//
163
165 if (remark && owner)
166 owner->report(std::move(*remark));
167 owner = nullptr;
168}
169
170//===----------------------------------------------------------------------===//
171// Remark Engine
172//===----------------------------------------------------------------------===//
173
174template <typename RemarkT, typename... Args>
175InFlightRemark RemarkEngine::makeRemark(Args &&...args) {
176 static_assert(std::is_base_of_v<Remark, RemarkT>,
177 "RemarkT must derive from Remark");
178 return InFlightRemark(*this,
179 std::make_unique<RemarkT>(std::forward<Args>(args)...));
180}
181
182template <typename RemarkT>
184RemarkEngine::emitIfEnabled(Location loc, RemarkOpts opts,
185 bool (RemarkEngine::*isEnabled)(StringRef) const) {
186 return (this->*isEnabled)(opts.categoryName) ? makeRemark<RemarkT>(loc, opts)
187 : InFlightRemark{};
188}
189
190bool RemarkEngine::isMissedOptRemarkEnabled(StringRef categoryName) const {
191 return missFilter && missFilter->match(categoryName);
192}
193
194bool RemarkEngine::isPassedOptRemarkEnabled(StringRef categoryName) const {
195 return passedFilter && passedFilter->match(categoryName);
196}
197
198bool RemarkEngine::isAnalysisOptRemarkEnabled(StringRef categoryName) const {
199 return analysisFilter && analysisFilter->match(categoryName);
200}
201
202bool RemarkEngine::isFailedOptRemarkEnabled(StringRef categoryName) const {
203 return failedFilter && failedFilter->match(categoryName);
204}
205
207 RemarkOpts opts) {
208 return emitIfEnabled<OptRemarkPass>(loc, opts,
209 &RemarkEngine::isPassedOptRemarkEnabled);
210}
211
213 RemarkOpts opts) {
214 return emitIfEnabled<OptRemarkMissed>(
215 loc, opts, &RemarkEngine::isMissedOptRemarkEnabled);
216}
217
219 RemarkOpts opts) {
220 return emitIfEnabled<OptRemarkFailure>(
221 loc, opts, &RemarkEngine::isFailedOptRemarkEnabled);
222}
223
225 RemarkOpts opts) {
226 return emitIfEnabled<OptRemarkAnalysis>(
227 loc, opts, &RemarkEngine::isAnalysisOptRemarkEnabled);
228}
229
230//===----------------------------------------------------------------------===//
231// RemarkEngine
232//===----------------------------------------------------------------------===//
233
234void RemarkEngine::reportImpl(const Remark &remark) {
235 // Stream the remark
236 if (remarkStreamer) {
237 remarkStreamer->streamOptimizationRemark(remark);
238 }
239
240 // Print using MLIR's diagnostic
241 if (printAsEmitRemarks)
242 emitRemark(remark.getLocation(), remark.getMsg());
243}
244
246 if (remarkEmittingPolicy)
247 remarkEmittingPolicy->reportRemark(remark);
248}
249
251 if (remarkEmittingPolicy)
252 remarkEmittingPolicy->finalize();
253
254 if (remarkStreamer)
255 remarkStreamer->finalize();
256}
257
258llvm::LogicalResult RemarkEngine::initialize(
259 std::unique_ptr<MLIRRemarkStreamerBase> streamer,
260 std::unique_ptr<RemarkEmittingPolicyBase> remarkEmittingPolicy,
261 std::string *errMsg) {
262
263 remarkStreamer = std::move(streamer);
264
265 auto reportFunc =
266 std::bind(&RemarkEngine::reportImpl, this, std::placeholders::_1);
267 remarkEmittingPolicy->initialize(ReportFn(std::move(reportFunc)));
268
269 this->remarkEmittingPolicy = std::move(remarkEmittingPolicy);
270 return success();
271}
272
273/// Returns true if filter is already anchored like ^...$
274static bool isAnchored(llvm::StringRef s) {
275 s = s.trim();
276 return s.starts_with("^") && s.ends_with("$"); // note: startswith/endswith
277}
278
279/// Anchor the entire pattern so it matches the whole string.
280static std::string anchorWhole(llvm::StringRef filter) {
281 if (isAnchored(filter))
282 return filter.str();
283 return (llvm::Twine("^(") + filter + ")$").str();
284}
285
286/// Build a combined filter from cats.all and a category-specific pattern.
287/// If neither is present, return std::nullopt. Otherwise "(all|specific)"
288/// and anchor once. Also validate before returning.
289static std::optional<llvm::Regex>
291 const std::optional<std::string> &specific) {
293 if (cats.all && !cats.all->empty())
294 parts.emplace_back(*cats.all);
295 if (specific && !specific->empty())
296 parts.emplace_back(*specific);
297
298 if (parts.empty())
299 return std::nullopt;
300
301 std::string joined = llvm::join(parts, "|");
302 std::string anchored = anchorWhole(joined);
303
304 llvm::Regex rx(anchored);
305 std::string err;
306 if (!rx.isValid(err))
307 return std::nullopt;
308
309 return std::make_optional<llvm::Regex>(std::move(rx));
310}
311
312RemarkEngine::RemarkEngine(bool printAsEmitRemarks,
313 const RemarkCategories &cats)
314 : printAsEmitRemarks(printAsEmitRemarks) {
315 if (cats.passed)
316 passedFilter = buildFilter(cats, cats.passed);
317 if (cats.missed)
318 missFilter = buildFilter(cats, cats.missed);
319 if (cats.analysis)
320 analysisFilter = buildFilter(cats, cats.analysis);
321 if (cats.failed)
322 failedFilter = buildFilter(cats, cats.failed);
323}
324
326 MLIRContext &ctx, std::unique_ptr<detail::MLIRRemarkStreamerBase> streamer,
327 std::unique_ptr<detail::RemarkEmittingPolicyBase> remarkEmittingPolicy,
328 const RemarkCategories &cats, bool printAsEmitRemarks) {
329 auto engine =
330 std::make_unique<detail::RemarkEngine>(printAsEmitRemarks, cats);
331
332 std::string errMsg;
333 if (failed(engine->initialize(std::move(streamer),
334 std::move(remarkEmittingPolicy), &errMsg))) {
335 llvm::report_fatal_error(
336 llvm::Twine("Failed to initialize remark engine. Error: ") + errMsg);
337 }
338 ctx.setRemarkEngine(std::move(engine));
339
340 return success();
341}
342
343//===----------------------------------------------------------------------===//
344// Remark emitting policies
345//===----------------------------------------------------------------------===//
346
347namespace mlir::remark {
350} // 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:274
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:280
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:290
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
InFlightRemark is a RAII class that holds a reference to a Remark instance and allows to build the re...
Definition Remarks.h:292
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:218
void report(const Remark &&remark)
Report a remark.
Definition Remarks.cpp:245
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:206
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:258
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:212
~RemarkEngine()
Destructor that will close the output file and reset the main remark streamer.
Definition Remarks.cpp:250
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:224
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:176
StringRef categoryName
Sub category passname e.g., "Unroll" or "UnrollAndJam".
Definition Remarks.h:191
SmallVector< Arg, 4 > args
Args collected via the streaming interface.
Definition Remarks.h:203
StringRef getFunction() const
Definition Remarks.h:150
llvm::remarks::Type getRemarkType() const
Definition Remarks.cpp:122
StringRef getRemarkTypeString() const
Definition Remarks.cpp:106
Location getLocation() const
Definition Remarks.h:146
StringRef remarkName
Remark identifier.
Definition Remarks.h:200
llvm::StringRef getCombinedCategoryName() const
Definition Remarks.h:158
RemarkKind remarkKind
Keeps the MLIR diagnostic kind, which is used to determine the diagnostic kind in the LLVM remark str...
Definition Remarks.h:185
StringRef getRemarkName() const
Definition Remarks.h:168
void insert(llvm::StringRef s)
Definition Remarks.cpp:39
StringRef functionName
Name of the convering function like interface.
Definition Remarks.h:187
llvm::remarks::Remark generateRemark() const
Diagnostic -> Remark.
Definition Remarks.cpp:138
std::string getMsg() const
Definition Remarks.cpp:98
llvm::unique_function< void(const Remark &)> ReportFn
Definition Remarks.h:352
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:573
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
std::optional< Attribute > attr
Optional attribute storage for Attribute-based args.
Definition Remarks.h:109