MLIR 24.0.0git
IRRemarks.cpp
Go to the documentation of this file.
1//===- IRRemarks.cpp - Remark engine bindings -----------------------------===//
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-c/Remarks.h"
11
12#include <cstdio>
13#include <optional>
14#include <string>
15
16namespace nb = nanobind;
17using namespace nb::literals;
18
19namespace mlir {
20namespace python {
22namespace {
23/// User data of the remark callback installed by `Context.enable_remarks`.
24struct PyRemarkCallbackData {
25 MlirContext context;
26 nb::object callback;
27};
28} // namespace
29
30static nb::str remarkStr(MlirStringRef ref) {
31 return nb::str(ref.data, ref.length);
32}
33
34/// Forwards a reported remark to the Python callable in `userData`; the
35/// PyRemark is invalidated once the callable returns, like a PyDiagnostic.
36static void pyRemarkCallback(MlirRemark remark, void *userData) {
37 auto *data = static_cast<PyRemarkCallbackData *>(userData);
38 // Since this can be called from arbitrary C++ contexts, always get the gil.
39 nb::gil_scoped_acquire gil;
40 // A remark postponed until the context's destruction cannot be delivered:
41 // the Python wrapper of the context is already gone.
42 if (!PyMlirContext::isLiveContext(data->context))
43 return;
44 PyRemark *pyRemark = new PyRemark(remark);
45 nb::object pyRemarkObject = nb::cast(pyRemark, nb::rv_policy::take_ownership);
46 try {
47 data->callback(pyRemarkObject);
48 } catch (std::exception &e) {
49 fprintf(stderr, "MLIR Python remark callback raised exception: %s\n",
50 e.what());
51 }
52 pyRemark->invalidate();
53}
54
55static void pyRemarkCallbackDelete(void *userData) {
56 nb::gil_scoped_acquire gil;
57 delete static_cast<PyRemarkCallbackData *>(userData);
58}
59
60bool PyMlirContext::isLiveContext(MlirContext context) {
61 nb::ft_lock_guard lock(live_contexts_mutex);
62 return getLiveContexts().count(context.ptr) != 0;
63}
64
66 PyRemarkPolicy policy, const std::optional<std::string> &outputFile,
67 PyRemarkFormat format, const std::string &allFilter,
68 const std::string &passedFilter, const std::string &missedFilter,
69 const std::string &analysisFilter, const std::string &failedFilter,
70 nb::object callback, std::optional<bool> printAsEmitRemarks) {
71 bool hasCallback = !callback.is_none();
72 if (outputFile && hasCallback)
73 throw nb::value_error(
74 "a remark callback cannot be combined with an output file");
76 throw nb::value_error("remarks are already enabled on this context; call "
77 "finalize_remarks() first");
78 }
79
80 MlirRemarkCategories categories{
81 toMlirStringRef(allFilter), toMlirStringRef(passedFilter),
82 toMlirStringRef(missedFilter), toMlirStringRef(analysisFilter),
83 toMlirStringRef(failedFilter)};
84 auto remarkPolicy = static_cast<MlirRemarkPolicy>(policy);
85 // Without a sink of its own, the engine prints as MLIR remark diagnostics.
86 bool printAsEmit =
87 printAsEmitRemarks.value_or(!outputFile.has_value() && !hasCallback);
88
90 if (outputFile) {
92 get(), categories, remarkPolicy,
93 static_cast<MlirRemarkFileFormat>(format), toMlirStringRef(*outputFile),
94 printAsEmit);
96 throw nb::value_error(
97 ("failed to enable remarks: cannot write '" + *outputFile + "'")
98 .c_str());
99 } else if (hasCallback) {
100 auto *data = new PyRemarkCallbackData{get(), std::move(callback)};
102 get(), categories, remarkPolicy, pyRemarkCallback, data,
103 pyRemarkCallbackDelete, printAsEmit);
104 } else {
106 remarkPolicy, printAsEmit);
107 }
109 throw nb::value_error("failed to enable remarks");
110}
111
115
119
120void PyRemark::checkValid() const {
121 if (!valid)
122 throw std::invalid_argument("Remark is invalid (used outside of callback)");
123}
124
126 checkValid();
127 return static_cast<PyRemarkKind>(mlirRemarkGetKind(remark));
128}
129
130nb::str PyRemark::getRemarkName() const {
131 checkValid();
132 return remarkStr(mlirRemarkGetRemarkName(remark));
133}
134
136 checkValid();
137 return remarkStr(mlirRemarkGetCategoryName(remark));
138}
139
141 checkValid();
143}
144
146 checkValid();
147 return remarkStr(mlirRemarkGetFunctionName(remark));
148}
149
150nb::typed<nb::object, PyLocation> PyRemark::getLocation() const {
151 checkValid();
152 MlirLocation loc = mlirRemarkGetLocation(remark);
153 MlirContext context = mlirLocationGetContext(loc);
154 return PyLocation(PyMlirContext::forContext(context), loc).maybeDownCast();
155}
156
157uint64_t PyRemark::getId() const {
158 checkValid();
159 return mlirRemarkGetId(remark);
160}
161
162nb::list PyRemark::getArgs() const {
163 checkValid();
164 nb::list args;
165 intptr_t numArgs = mlirRemarkGetNumArgs(remark);
166 for (intptr_t i = 0; i < numArgs; ++i) {
167 args.append(nb::make_tuple(remarkStr(mlirRemarkGetArgKey(remark, i)),
168 remarkStr(mlirRemarkGetArgValue(remark, i))));
169 }
170 return args;
171}
172
173nb::str PyRemark::getMessage() const {
174 checkValid();
175 std::string message;
176 auto callback = +[](MlirStringRef ref, void *userData) {
177 static_cast<std::string *>(userData)->append(ref.data, ref.length);
178 };
179 mlirRemarkPrint(remark, callback, &message);
180 return nb::str(message.c_str(), message.size());
181}
182
183void populateIRRemarks(nb::module_ &m) {
184 nb::enum_<PyRemarkKind>(m, "RemarkKind")
185 .value("UNKNOWN", PyRemarkKind::Unknown)
186 .value("PASSED", PyRemarkKind::Passed)
187 .value("MISSED", PyRemarkKind::Missed)
188 .value("FAILURE", PyRemarkKind::Failure)
189 .value("ANALYSIS", PyRemarkKind::Analysis);
190
191 nb::enum_<PyRemarkPolicy>(m, "RemarkPolicy")
192 .value("ALL", PyRemarkPolicy::All)
193 .value("FINAL", PyRemarkPolicy::Final);
194
195 nb::enum_<PyRemarkFormat>(m, "RemarkFormat")
196 .value("YAML", PyRemarkFormat::YAML)
197 .value("BITSTREAM", PyRemarkFormat::Bitstream);
198
199 nb::class_<PyRemark>(m, "Remark")
200 .def_prop_ro("kind", &PyRemark::getKind,
201 "Returns the kind of the remark.")
202 .def_prop_ro("remark_name", &PyRemark::getRemarkName,
203 "Returns the name identifying the remark.")
204 .def_prop_ro("category_name", &PyRemark::getCategoryName,
205 "Returns the category of the remark (what the filters "
206 "match).")
207 .def_prop_ro("full_category_name", &PyRemark::getFullCategoryName,
208 "Returns the combined `category:subcategory` name.")
209 .def_prop_ro("function_name", &PyRemark::getFunctionName,
210 "Returns the name of the function the remark refers to.")
211 .def_prop_ro("location", &PyRemark::getLocation,
212 "Returns the location associated with the remark.")
213 .def_prop_ro("remark_id", &PyRemark::getId,
214 "Returns the id of the remark within its engine (0 when "
215 "unset).")
216 .def_prop_ro("args", &PyRemark::getArgs,
217 "Returns the key/value arguments as a list of tuples.")
218 .def_prop_ro("message", &PyRemark::getMessage,
219 "Returns the textual form of the remark, `[Kind] name | "
220 "Category:... | key=value, ...`.")
221 .def(
222 "__str__",
223 [](PyRemark &self) -> nb::str {
224 if (!self.isValid())
225 return nb::str("<Invalid Remark>");
226 return self.getMessage();
227 },
228 "Returns the remark message as a string.");
229}
230} // namespace MLIR_BINDINGS_PYTHON_DOMAIN
231} // namespace python
232} // namespace mlir
nanobind::typed< nanobind::object, PyLocation > maybeDownCast()
Returns the most-derived Location subclass registered for this TypeID, or self.
Definition IRCore.cpp:1888
static PyMlirContextRef forContext(MlirContext context)
Returns a context reference for the singleton PyMlirContext wrapper for the given context.
Definition IRCore.cpp:461
static bool isLiveContext(MlirContext context)
Whether context still has a live Python wrapper (false while it is being destroyed).
Definition IRRemarks.cpp:60
bool getRemarksEnabled()
Whether a remark engine is enabled on the context.
void enableRemarks(PyRemarkPolicy policy, const std::optional< std::string > &outputFile, PyRemarkFormat format, const std::string &allFilter, const std::string &passedFilter, const std::string &missedFilter, const std::string &analysisFilter, const std::string &failedFilter, nanobind::object callback, std::optional< bool > printAsEmitRemarks)
Enables the optimization remark engine of the context, streaming to outputFile, to callback,...
Definition IRRemarks.cpp:65
MlirContext get()
Accesses the underlying MlirContext.
Definition IRCore.h:245
void finalizeRemarks()
Finalizes and removes the remark engine; no-op when none is enabled.
Wrapper around an MlirRemark as delivered to a remark callback.
Definition IRCore.h:457
nanobind::typed< nanobind::object, PyLocation > getLocation() const
nanobind::str getMessage() const
The textual form of the remark, without its location.
nanobind::list getArgs() const
The key/value arguments as a list of (key, value) tuples.
MLIR_CAPI_EXPORTED MlirContext mlirLocationGetContext(MlirLocation location)
Gets the context that a location was created with.
Definition IR.cpp:436
MLIR_CAPI_EXPORTED MlirStringRef mlirRemarkGetCategoryName(MlirRemark remark)
Returns the category of the remark (the subject of the filters).
Definition Remarks.cpp:169
MLIR_CAPI_EXPORTED MlirStringRef mlirRemarkGetFullCategoryName(MlirRemark remark)
Returns the combined category:subcategory name of the remark.
Definition Remarks.cpp:173
MlirRemarkFileFormat
The serialization format of a remark output file.
Definition Remarks.h:62
MLIR_CAPI_EXPORTED MlirStringRef mlirRemarkGetRemarkName(MlirRemark remark)
Returns the name identifying the remark.
Definition Remarks.cpp:165
MLIR_CAPI_EXPORTED MlirRemarkKind mlirRemarkGetKind(MlirRemark remark)
Returns the kind of the remark.
Definition Remarks.cpp:161
MLIR_CAPI_EXPORTED void mlirRemarkPrint(MlirRemark remark, MlirStringCallback callback, void *userData)
Prints the remark in its textual form, [Kind] name | Category:... | / Function=......
Definition Remarks.cpp:207
MLIR_CAPI_EXPORTED MlirLogicalResult mlirContextEnableOptimizationRemarksToFile(MlirContext context, MlirRemarkCategories categories, MlirRemarkPolicy policy, MlirRemarkFileFormat format, MlirStringRef path, bool printAsEmitRemarks)
Enables the remark engine on the context, streaming the reported remarks to the file at path in forma...
Definition Remarks.cpp:116
MLIR_CAPI_EXPORTED intptr_t mlirRemarkGetNumArgs(MlirRemark remark)
Returns the number of key/value arguments attached to the remark.
Definition Remarks.cpp:189
MlirRemarkPolicy
The emitting policy of the remark engine.
Definition Remarks.h:52
MLIR_CAPI_EXPORTED MlirLocation mlirRemarkGetLocation(MlirRemark remark)
Returns the location of the remark.
Definition Remarks.cpp:181
MLIR_CAPI_EXPORTED MlirStringRef mlirRemarkGetArgValue(MlirRemark remark, intptr_t pos)
Returns the value of the pos-th argument of the remark.
Definition Remarks.cpp:200
MLIR_CAPI_EXPORTED bool mlirContextHasRemarkEngine(MlirContext context)
Returns whether the context has a remark engine enabled.
Definition Remarks.cpp:153
MLIR_CAPI_EXPORTED MlirLogicalResult mlirContextEnableOptimizationRemarksWithCallback(MlirContext context, MlirRemarkCategories categories, MlirRemarkPolicy policy, MlirRemarkCallback callback, void *userData, void(*deleteUserData)(void *), bool printAsEmitRemarks)
Enables the remark engine on the context, delivering every reported remark to callback.
Definition Remarks.cpp:128
MLIR_CAPI_EXPORTED void mlirContextFinalizeOptimizationRemarks(MlirContext context)
Finalizes and removes the remark engine of the context: postponed remarks are reported,...
Definition Remarks.cpp:147
MLIR_CAPI_EXPORTED uint64_t mlirRemarkGetId(MlirRemark remark)
Returns the unique id of the remark within its engine (0 when unset).
Definition Remarks.cpp:185
MLIR_CAPI_EXPORTED MlirStringRef mlirRemarkGetFunctionName(MlirRemark remark)
Returns the name of the function the remark refers to.
Definition Remarks.cpp:177
MLIR_CAPI_EXPORTED MlirLogicalResult mlirContextEnableOptimizationRemarks(MlirContext context, MlirRemarkCategories categories, MlirRemarkPolicy policy, bool printAsEmitRemarks)
Enables the remark engine on the context without a streamer; when printAsEmitRemarks is set,...
Definition Remarks.cpp:105
MLIR_CAPI_EXPORTED MlirStringRef mlirRemarkGetArgKey(MlirRemark remark, intptr_t pos)
Returns the key of the pos-th argument of the remark.
Definition Remarks.cpp:193
static bool mlirLogicalResultIsFailure(MlirLogicalResult res)
Checks if the given logical result represents a failure.
Definition Support.h:132
MLIR_PYTHON_API_EXPORTED void populateIRRemarks(nanobind::module_ &m)
static nb::str remarkStr(MlirStringRef ref)
Definition IRRemarks.cpp:30
MlirStringRef toMlirStringRef(const std::string &s)
Definition IRCore.h:1554
PyRemarkKind
The kinds, emitting policies and file formats of the remark engine (mlir-c/Remarks....
Definition IRCore.h:212
static void pyRemarkCallback(MlirRemark remark, void *userData)
Forwards a reported remark to the Python callable in userData; the PyRemark is invalidated once the c...
Definition IRRemarks.cpp:36
static void pyRemarkCallbackDelete(void *userData)
Definition IRRemarks.cpp:55
Include the generated interface declarations.
A logical result value, essentially a boolean with named states.
Definition Support.h:121
Regular expressions (llvm::Regex syntax, anchored by the engine) selecting the remark categories to r...
Definition Remarks.h:72
An opaque reference to a remark.
Definition Remarks.h:32
A pointer to a sized fragment of a string, not necessarily null-terminated.
Definition Support.h:78
const char * data
Pointer to the first symbol.
Definition Support.h:79
size_t length
Length of the fragment.
Definition Support.h:80