MLIR  19.0.0git
PybindAdaptors.h
Go to the documentation of this file.
1 //===- PybindAdaptors.h - Adaptors for interop with MLIR APIs -------------===//
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 // This file contains adaptors for clients of the core MLIR Python APIs to
9 // interop via MLIR CAPI types. The facilities here do not depend on
10 // implementation details of the MLIR Python API and do not introduce C++-level
11 // dependencies with it (requiring only Python and CAPI-level dependencies).
12 //
13 // It is encouraged to be used both in-tree and out-of-tree. For in-tree use
14 // cases, it should be used for dialect implementations (versus relying on
15 // Pybind-based internals of the core libraries).
16 //===----------------------------------------------------------------------===//
17 
18 #ifndef MLIR_BINDINGS_PYTHON_PYBINDADAPTORS_H
19 #define MLIR_BINDINGS_PYTHON_PYBINDADAPTORS_H
20 
21 #include <pybind11/pybind11.h>
22 #include <pybind11/pytypes.h>
23 #include <pybind11/stl.h>
24 
26 #include "mlir-c/Diagnostics.h"
27 #include "mlir-c/IR.h"
28 
29 #include "llvm/ADT/Twine.h"
30 
31 namespace py = pybind11;
32 using namespace py::literals;
33 
34 // Raw CAPI type casters need to be declared before use, so always include them
35 // first.
36 namespace pybind11 {
37 namespace detail {
38 
39 /// Helper to convert a presumed MLIR API object to a capsule, accepting either
40 /// an explicit Capsule (which can happen when two C APIs are communicating
41 /// directly via Python) or indirectly by querying the MLIR_PYTHON_CAPI_PTR_ATTR
42 /// attribute (through which supported MLIR Python API objects export their
43 /// contained API pointer as a capsule). Throws a type error if the object is
44 /// neither. This is intended to be used from type casters, which are invoked
45 /// with a raw handle (unowned). The returned object's lifetime may not extend
46 /// beyond the apiObject handle without explicitly having its refcount increased
47 /// (i.e. on return).
48 static py::object mlirApiObjectToCapsule(py::handle apiObject) {
49  if (PyCapsule_CheckExact(apiObject.ptr()))
50  return py::reinterpret_borrow<py::object>(apiObject);
51  if (!py::hasattr(apiObject, MLIR_PYTHON_CAPI_PTR_ATTR)) {
52  auto repr = py::repr(apiObject).cast<std::string>();
53  throw py::type_error(
54  (llvm::Twine("Expected an MLIR object (got ") + repr + ").").str());
55  }
56  return apiObject.attr(MLIR_PYTHON_CAPI_PTR_ATTR);
57 }
58 
59 // Note: Currently all of the following support cast from py::object to the
60 // Mlir* C-API type, but only a few light-weight, context-bound ones
61 // implicitly cast the other way because the use case has not yet emerged and
62 // ownership is unclear.
63 
64 /// Casts object <-> MlirAffineMap.
65 template <>
66 struct type_caster<MlirAffineMap> {
67  PYBIND11_TYPE_CASTER(MlirAffineMap, _("MlirAffineMap"));
68  bool load(handle src, bool) {
69  py::object capsule = mlirApiObjectToCapsule(src);
70  value = mlirPythonCapsuleToAffineMap(capsule.ptr());
71  if (mlirAffineMapIsNull(value)) {
72  return false;
73  }
74  return !mlirAffineMapIsNull(value);
75  }
76  static handle cast(MlirAffineMap v, return_value_policy, handle) {
77  py::object capsule =
78  py::reinterpret_steal<py::object>(mlirPythonAffineMapToCapsule(v));
79  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
80  .attr("AffineMap")
81  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
82  .release();
83  }
84 };
85 
86 /// Casts object <-> MlirAttribute.
87 template <>
88 struct type_caster<MlirAttribute> {
89  PYBIND11_TYPE_CASTER(MlirAttribute, _("MlirAttribute"));
90  bool load(handle src, bool) {
91  py::object capsule = mlirApiObjectToCapsule(src);
92  value = mlirPythonCapsuleToAttribute(capsule.ptr());
93  return !mlirAttributeIsNull(value);
94  }
95  static handle cast(MlirAttribute v, return_value_policy, handle) {
96  py::object capsule =
97  py::reinterpret_steal<py::object>(mlirPythonAttributeToCapsule(v));
98  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
99  .attr("Attribute")
100  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
102  .release();
103  }
104 };
105 
106 /// Casts object -> MlirBlock.
107 template <>
108 struct type_caster<MlirBlock> {
109  PYBIND11_TYPE_CASTER(MlirBlock, _("MlirBlock"));
110  bool load(handle src, bool) {
111  py::object capsule = mlirApiObjectToCapsule(src);
112  value = mlirPythonCapsuleToBlock(capsule.ptr());
113  return !mlirBlockIsNull(value);
114  }
115 };
116 
117 /// Casts object -> MlirContext.
118 template <>
119 struct type_caster<MlirContext> {
120  PYBIND11_TYPE_CASTER(MlirContext, _("MlirContext"));
121  bool load(handle src, bool) {
122  if (src.is_none()) {
123  // Gets the current thread-bound context.
124  // TODO: This raises an error of "No current context" currently.
125  // Update the implementation to pretty-print the helpful error that the
126  // core implementations print in this case.
127  src = py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
128  .attr("Context")
129  .attr("current");
130  }
131  py::object capsule = mlirApiObjectToCapsule(src);
132  value = mlirPythonCapsuleToContext(capsule.ptr());
133  return !mlirContextIsNull(value);
134  }
135 };
136 
137 /// Casts object <-> MlirDialectRegistry.
138 template <>
139 struct type_caster<MlirDialectRegistry> {
140  PYBIND11_TYPE_CASTER(MlirDialectRegistry, _("MlirDialectRegistry"));
141  bool load(handle src, bool) {
142  py::object capsule = mlirApiObjectToCapsule(src);
143  value = mlirPythonCapsuleToDialectRegistry(capsule.ptr());
144  return !mlirDialectRegistryIsNull(value);
145  }
146  static handle cast(MlirDialectRegistry v, return_value_policy, handle) {
147  py::object capsule = py::reinterpret_steal<py::object>(
149  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
150  .attr("DialectRegistry")
151  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
152  .release();
153  }
154 };
155 
156 /// Casts object <-> MlirLocation.
157 template <>
158 struct type_caster<MlirLocation> {
159  PYBIND11_TYPE_CASTER(MlirLocation, _("MlirLocation"));
160  bool load(handle src, bool) {
161  if (src.is_none()) {
162  // Gets the current thread-bound context.
163  src = py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
164  .attr("Location")
165  .attr("current");
166  }
167  py::object capsule = mlirApiObjectToCapsule(src);
168  value = mlirPythonCapsuleToLocation(capsule.ptr());
169  return !mlirLocationIsNull(value);
170  }
171  static handle cast(MlirLocation v, return_value_policy, handle) {
172  py::object capsule =
173  py::reinterpret_steal<py::object>(mlirPythonLocationToCapsule(v));
174  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
175  .attr("Location")
176  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
177  .release();
178  }
179 };
180 
181 /// Casts object <-> MlirModule.
182 template <>
183 struct type_caster<MlirModule> {
184  PYBIND11_TYPE_CASTER(MlirModule, _("MlirModule"));
185  bool load(handle src, bool) {
186  py::object capsule = mlirApiObjectToCapsule(src);
187  value = mlirPythonCapsuleToModule(capsule.ptr());
188  return !mlirModuleIsNull(value);
189  }
190  static handle cast(MlirModule v, return_value_policy, handle) {
191  py::object capsule =
192  py::reinterpret_steal<py::object>(mlirPythonModuleToCapsule(v));
193  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
194  .attr("Module")
195  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
196  .release();
197  };
198 };
199 
200 /// Casts object <-> MlirOperation.
201 template <>
202 struct type_caster<MlirOperation> {
203  PYBIND11_TYPE_CASTER(MlirOperation, _("MlirOperation"));
204  bool load(handle src, bool) {
205  py::object capsule = mlirApiObjectToCapsule(src);
206  value = mlirPythonCapsuleToOperation(capsule.ptr());
207  return !mlirOperationIsNull(value);
208  }
209  static handle cast(MlirOperation v, return_value_policy, handle) {
210  if (v.ptr == nullptr)
211  return py::none();
212  py::object capsule =
213  py::reinterpret_steal<py::object>(mlirPythonOperationToCapsule(v));
214  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
215  .attr("Operation")
216  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
217  .release();
218  };
219 };
220 
221 /// Casts object <-> MlirValue.
222 template <>
223 struct type_caster<MlirValue> {
224  PYBIND11_TYPE_CASTER(MlirValue, _("MlirValue"));
225  bool load(handle src, bool) {
226  py::object capsule = mlirApiObjectToCapsule(src);
227  value = mlirPythonCapsuleToValue(capsule.ptr());
228  return !mlirValueIsNull(value);
229  }
230  static handle cast(MlirValue v, return_value_policy, handle) {
231  if (v.ptr == nullptr)
232  return py::none();
233  py::object capsule =
234  py::reinterpret_steal<py::object>(mlirPythonValueToCapsule(v));
235  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
236  .attr("Value")
237  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
239  .release();
240  };
241 };
242 
243 /// Casts object -> MlirPassManager.
244 template <>
245 struct type_caster<MlirPassManager> {
246  PYBIND11_TYPE_CASTER(MlirPassManager, _("MlirPassManager"));
247  bool load(handle src, bool) {
248  py::object capsule = mlirApiObjectToCapsule(src);
249  value = mlirPythonCapsuleToPassManager(capsule.ptr());
250  return !mlirPassManagerIsNull(value);
251  }
252 };
253 
254 /// Casts object <-> MlirTypeID.
255 template <>
256 struct type_caster<MlirTypeID> {
257  PYBIND11_TYPE_CASTER(MlirTypeID, _("MlirTypeID"));
258  bool load(handle src, bool) {
259  py::object capsule = mlirApiObjectToCapsule(src);
260  value = mlirPythonCapsuleToTypeID(capsule.ptr());
261  return !mlirTypeIDIsNull(value);
262  }
263  static handle cast(MlirTypeID v, return_value_policy, handle) {
264  if (v.ptr == nullptr)
265  return py::none();
266  py::object capsule =
267  py::reinterpret_steal<py::object>(mlirPythonTypeIDToCapsule(v));
268  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
269  .attr("TypeID")
270  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
271  .release();
272  };
273 };
274 
275 /// Casts object <-> MlirType.
276 template <>
277 struct type_caster<MlirType> {
278  PYBIND11_TYPE_CASTER(MlirType, _("MlirType"));
279  bool load(handle src, bool) {
280  py::object capsule = mlirApiObjectToCapsule(src);
281  value = mlirPythonCapsuleToType(capsule.ptr());
282  return !mlirTypeIsNull(value);
283  }
284  static handle cast(MlirType t, return_value_policy, handle) {
285  py::object capsule =
286  py::reinterpret_steal<py::object>(mlirPythonTypeToCapsule(t));
287  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
288  .attr("Type")
289  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
291  .release();
292  }
293 };
294 
295 } // namespace detail
296 } // namespace pybind11
297 
298 namespace mlir {
299 namespace python {
300 namespace adaptors {
301 
302 /// Provides a facility like py::class_ for defining a new class in a scope,
303 /// but this allows extension of an arbitrary Python class, defining methods
304 /// on it is a similar way. Classes defined in this way are very similar to
305 /// if defined in Python in the usual way but use Pybind11 machinery to do
306 /// it. These are not "real" Pybind11 classes but pure Python classes with no
307 /// relation to a concrete C++ class.
308 ///
309 /// Derived from a discussion upstream:
310 /// https://github.com/pybind/pybind11/issues/1193
311 /// (plus a fair amount of extra curricular poking)
312 /// TODO: If this proves useful, see about including it in pybind11.
314 public:
315  pure_subclass(py::handle scope, const char *derivedClassName,
316  const py::object &superClass) {
317  py::object pyType =
318  py::reinterpret_borrow<py::object>((PyObject *)&PyType_Type);
319  py::object metaclass = pyType(superClass);
320  py::dict attributes;
321 
322  thisClass =
323  metaclass(derivedClassName, py::make_tuple(superClass), attributes);
324  scope.attr(derivedClassName) = thisClass;
325  }
326 
327  template <typename Func, typename... Extra>
328  pure_subclass &def(const char *name, Func &&f, const Extra &...extra) {
329  py::cpp_function cf(
330  std::forward<Func>(f), py::name(name), py::is_method(thisClass),
331  py::sibling(py::getattr(thisClass, name, py::none())), extra...);
332  thisClass.attr(cf.name()) = cf;
333  return *this;
334  }
335 
336  template <typename Func, typename... Extra>
337  pure_subclass &def_property_readonly(const char *name, Func &&f,
338  const Extra &...extra) {
339  py::cpp_function cf(
340  std::forward<Func>(f), py::name(name), py::is_method(thisClass),
341  py::sibling(py::getattr(thisClass, name, py::none())), extra...);
342  auto builtinProperty =
343  py::reinterpret_borrow<py::object>((PyObject *)&PyProperty_Type);
344  thisClass.attr(name) = builtinProperty(cf);
345  return *this;
346  }
347 
348  template <typename Func, typename... Extra>
349  pure_subclass &def_staticmethod(const char *name, Func &&f,
350  const Extra &...extra) {
351  static_assert(!std::is_member_function_pointer<Func>::value,
352  "def_staticmethod(...) called with a non-static member "
353  "function pointer");
354  py::cpp_function cf(
355  std::forward<Func>(f), py::name(name), py::scope(thisClass),
356  py::sibling(py::getattr(thisClass, name, py::none())), extra...);
357  thisClass.attr(cf.name()) = py::staticmethod(cf);
358  return *this;
359  }
360 
361  template <typename Func, typename... Extra>
362  pure_subclass &def_classmethod(const char *name, Func &&f,
363  const Extra &...extra) {
364  static_assert(!std::is_member_function_pointer<Func>::value,
365  "def_classmethod(...) called with a non-static member "
366  "function pointer");
367  py::cpp_function cf(
368  std::forward<Func>(f), py::name(name), py::scope(thisClass),
369  py::sibling(py::getattr(thisClass, name, py::none())), extra...);
370  thisClass.attr(cf.name()) =
371  py::reinterpret_borrow<py::object>(PyClassMethod_New(cf.ptr()));
372  return *this;
373  }
374 
375  py::object get_class() const { return thisClass; }
376 
377 protected:
378  py::object superClass;
379  py::object thisClass;
380 };
381 
382 /// Creates a custom subclass of mlir.ir.Attribute, implementing a casting
383 /// constructor and type checking methods.
385 public:
386  using IsAFunctionTy = bool (*)(MlirAttribute);
387 
388  /// Subclasses by looking up the super-class dynamically.
389  mlir_attribute_subclass(py::handle scope, const char *attrClassName,
390  IsAFunctionTy isaFunction)
392  scope, attrClassName, isaFunction,
393  py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
394  .attr("Attribute")) {}
395 
396  /// Subclasses with a provided mlir.ir.Attribute super-class. This must
397  /// be used if the subclass is being defined in the same extension module
398  /// as the mlir.ir class (otherwise, it will trigger a recursive
399  /// initialization).
400  mlir_attribute_subclass(py::handle scope, const char *typeClassName,
401  IsAFunctionTy isaFunction, const py::object &superCls)
402  : pure_subclass(scope, typeClassName, superCls) {
403  // Casting constructor. Note that it hard, if not impossible, to properly
404  // call chain to parent `__init__` in pybind11 due to its special handling
405  // for init functions that don't have a fully constructed self-reference,
406  // which makes it impossible to forward it to `__init__` of a superclass.
407  // Instead, provide a custom `__new__` and call that of a superclass, which
408  // eventually calls `__init__` of the superclass. Since attribute subclasses
409  // have no additional members, we can just return the instance thus created
410  // without amending it.
411  std::string captureTypeName(
412  typeClassName); // As string in case if typeClassName is not static.
413  py::cpp_function newCf(
414  [superCls, isaFunction, captureTypeName](py::object cls,
415  py::object otherAttribute) {
416  MlirAttribute rawAttribute = py::cast<MlirAttribute>(otherAttribute);
417  if (!isaFunction(rawAttribute)) {
418  auto origRepr = py::repr(otherAttribute).cast<std::string>();
419  throw std::invalid_argument(
420  (llvm::Twine("Cannot cast attribute to ") + captureTypeName +
421  " (from " + origRepr + ")")
422  .str());
423  }
424  py::object self = superCls.attr("__new__")(cls, otherAttribute);
425  return self;
426  },
427  py::name("__new__"), py::arg("cls"), py::arg("cast_from_attr"));
428  thisClass.attr("__new__") = newCf;
429 
430  // 'isinstance' method.
431  def_staticmethod(
432  "isinstance",
433  [isaFunction](MlirAttribute other) { return isaFunction(other); },
434  py::arg("other_attribute"));
435  }
436 };
437 
438 /// Creates a custom subclass of mlir.ir.Type, implementing a casting
439 /// constructor and type checking methods.
441 public:
442  using IsAFunctionTy = bool (*)(MlirType);
443  using GetTypeIDFunctionTy = MlirTypeID (*)();
444 
445  /// Subclasses by looking up the super-class dynamically.
446  mlir_type_subclass(py::handle scope, const char *typeClassName,
447  IsAFunctionTy isaFunction,
448  GetTypeIDFunctionTy getTypeIDFunction = nullptr)
450  scope, typeClassName, isaFunction,
451  py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")).attr("Type"),
452  getTypeIDFunction) {}
453 
454  /// Subclasses with a provided mlir.ir.Type super-class. This must
455  /// be used if the subclass is being defined in the same extension module
456  /// as the mlir.ir class (otherwise, it will trigger a recursive
457  /// initialization).
458  mlir_type_subclass(py::handle scope, const char *typeClassName,
459  IsAFunctionTy isaFunction, const py::object &superCls,
460  GetTypeIDFunctionTy getTypeIDFunction = nullptr)
461  : pure_subclass(scope, typeClassName, superCls) {
462  // Casting constructor. Note that it hard, if not impossible, to properly
463  // call chain to parent `__init__` in pybind11 due to its special handling
464  // for init functions that don't have a fully constructed self-reference,
465  // which makes it impossible to forward it to `__init__` of a superclass.
466  // Instead, provide a custom `__new__` and call that of a superclass, which
467  // eventually calls `__init__` of the superclass. Since attribute subclasses
468  // have no additional members, we can just return the instance thus created
469  // without amending it.
470  std::string captureTypeName(
471  typeClassName); // As string in case if typeClassName is not static.
472  py::cpp_function newCf(
473  [superCls, isaFunction, captureTypeName](py::object cls,
474  py::object otherType) {
475  MlirType rawType = py::cast<MlirType>(otherType);
476  if (!isaFunction(rawType)) {
477  auto origRepr = py::repr(otherType).cast<std::string>();
478  throw std::invalid_argument((llvm::Twine("Cannot cast type to ") +
479  captureTypeName + " (from " +
480  origRepr + ")")
481  .str());
482  }
483  py::object self = superCls.attr("__new__")(cls, otherType);
484  return self;
485  },
486  py::name("__new__"), py::arg("cls"), py::arg("cast_from_type"));
487  thisClass.attr("__new__") = newCf;
488 
489  // 'isinstance' method.
490  def_staticmethod(
491  "isinstance",
492  [isaFunction](MlirType other) { return isaFunction(other); },
493  py::arg("other_type"));
494  def("__repr__", [superCls, captureTypeName](py::object self) {
495  return py::repr(superCls(self))
496  .attr("replace")(superCls.attr("__name__"), captureTypeName);
497  });
498  if (getTypeIDFunction) {
499  // 'get_static_typeid' method.
500  // This is modeled as a static method instead of a static property because
501  // `def_property_readonly_static` is not available in `pure_subclass` and
502  // we do not want to introduce the complexity that pybind uses to
503  // implement it.
504  def_staticmethod("get_static_typeid",
505  [getTypeIDFunction]() { return getTypeIDFunction(); });
506  py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
508  getTypeIDFunction())(pybind11::cpp_function(
509  [thisClass = thisClass](const py::object &mlirType) {
510  return thisClass(mlirType);
511  }));
512  }
513  }
514 };
515 
516 /// Creates a custom subclass of mlir.ir.Value, implementing a casting
517 /// constructor and type checking methods.
519 public:
520  using IsAFunctionTy = bool (*)(MlirValue);
521 
522  /// Subclasses by looking up the super-class dynamically.
523  mlir_value_subclass(py::handle scope, const char *valueClassName,
524  IsAFunctionTy isaFunction)
526  scope, valueClassName, isaFunction,
527  py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")).attr("Value")) {
528  }
529 
530  /// Subclasses with a provided mlir.ir.Value super-class. This must
531  /// be used if the subclass is being defined in the same extension module
532  /// as the mlir.ir class (otherwise, it will trigger a recursive
533  /// initialization).
534  mlir_value_subclass(py::handle scope, const char *valueClassName,
535  IsAFunctionTy isaFunction, const py::object &superCls)
536  : pure_subclass(scope, valueClassName, superCls) {
537  // Casting constructor. Note that it hard, if not impossible, to properly
538  // call chain to parent `__init__` in pybind11 due to its special handling
539  // for init functions that don't have a fully constructed self-reference,
540  // which makes it impossible to forward it to `__init__` of a superclass.
541  // Instead, provide a custom `__new__` and call that of a superclass, which
542  // eventually calls `__init__` of the superclass. Since attribute subclasses
543  // have no additional members, we can just return the instance thus created
544  // without amending it.
545  std::string captureValueName(
546  valueClassName); // As string in case if valueClassName is not static.
547  py::cpp_function newCf(
548  [superCls, isaFunction, captureValueName](py::object cls,
549  py::object otherValue) {
550  MlirValue rawValue = py::cast<MlirValue>(otherValue);
551  if (!isaFunction(rawValue)) {
552  auto origRepr = py::repr(otherValue).cast<std::string>();
553  throw std::invalid_argument((llvm::Twine("Cannot cast value to ") +
554  captureValueName + " (from " +
555  origRepr + ")")
556  .str());
557  }
558  py::object self = superCls.attr("__new__")(cls, otherValue);
559  return self;
560  },
561  py::name("__new__"), py::arg("cls"), py::arg("cast_from_value"));
562  thisClass.attr("__new__") = newCf;
563 
564  // 'isinstance' method.
565  def_staticmethod(
566  "isinstance",
567  [isaFunction](MlirValue other) { return isaFunction(other); },
568  py::arg("other_value"));
569  }
570 };
571 
572 } // namespace adaptors
573 
574 /// RAII scope intercepting all diagnostics into a string. The message must be
575 /// checked before this goes out of scope.
577 public:
578  explicit CollectDiagnosticsToStringScope(MlirContext ctx) : context(ctx) {
579  handlerID = mlirContextAttachDiagnosticHandler(ctx, &handler, &errorMessage,
580  /*deleteUserData=*/nullptr);
581  }
583  assert(errorMessage.empty() && "unchecked error message");
584  mlirContextDetachDiagnosticHandler(context, handlerID);
585  }
586 
587  [[nodiscard]] std::string takeMessage() { return std::move(errorMessage); }
588 
589 private:
590  static MlirLogicalResult handler(MlirDiagnostic diag, void *data) {
591  auto printer = +[](MlirStringRef message, void *data) {
592  *static_cast<std::string *>(data) +=
593  llvm::StringRef(message.data, message.length);
594  };
595  MlirLocation loc = mlirDiagnosticGetLocation(diag);
596  *static_cast<std::string *>(data) += "at ";
597  mlirLocationPrint(loc, printer, data);
598  *static_cast<std::string *>(data) += ": ";
599  mlirDiagnosticPrint(diag, printer, data);
600  return mlirLogicalResultSuccess();
601  }
602 
603  MlirContext context;
604  MlirDiagnosticHandlerID handlerID;
605  std::string errorMessage = "";
606 };
607 
608 } // namespace python
609 } // namespace mlir
610 
611 #endif // MLIR_BINDINGS_PYTHON_PYBINDADAPTORS_H
static PyObject * mlirPythonModuleToCapsule(MlirModule module)
Creates a capsule object encapsulating the raw C-API MlirModule.
Definition: Interop.h:272
#define MLIR_PYTHON_MAYBE_DOWNCAST_ATTR
Attribute on MLIR Python objects that expose a function for downcasting the corresponding Python obje...
Definition: Interop.h:117
static MlirBlock mlirPythonCapsuleToBlock(PyObject *capsule)
Extracts an MlirBlock from a capsule as produced from mlirPythonBlockToCapsule.
Definition: Interop.h:205
static PyObject * mlirPythonTypeIDToCapsule(MlirTypeID typeID)
Creates a capsule object encapsulating the raw C-API MlirTypeID.
Definition: Interop.h:327
static MlirOperation mlirPythonCapsuleToOperation(PyObject *capsule)
Extracts an MlirOperations from a capsule as produced from mlirPythonOperationToCapsule.
Definition: Interop.h:317
#define MLIR_PYTHON_CAPI_PTR_ATTR
Attribute on MLIR Python objects that expose their C-API pointer.
Definition: Interop.h:96
static MlirAttribute mlirPythonCapsuleToAttribute(PyObject *capsule)
Extracts an MlirAttribute from a capsule as produced from mlirPythonAttributeToCapsule.
Definition: Interop.h:188
static PyObject * mlirPythonAttributeToCapsule(MlirAttribute attribute)
Creates a capsule object encapsulating the raw C-API MlirAttribute.
Definition: Interop.h:179
static PyObject * mlirPythonLocationToCapsule(MlirLocation loc)
Creates a capsule object encapsulating the raw C-API MlirLocation.
Definition: Interop.h:254
static MlirAffineMap mlirPythonCapsuleToAffineMap(PyObject *capsule)
Extracts an MlirAffineMap from a capsule as produced from mlirPythonAffineMapToCapsule.
Definition: Interop.h:374
#define MLIR_PYTHON_CAPI_FACTORY_ATTR
Attribute on MLIR Python objects that exposes a factory function for constructing the corresponding P...
Definition: Interop.h:109
static MlirModule mlirPythonCapsuleToModule(PyObject *capsule)
Extracts an MlirModule from a capsule as produced from mlirPythonModuleToCapsule.
Definition: Interop.h:281
static MlirContext mlirPythonCapsuleToContext(PyObject *capsule)
Extracts a MlirContext from a capsule as produced from mlirPythonContextToCapsule.
Definition: Interop.h:223
static MlirTypeID mlirPythonCapsuleToTypeID(PyObject *capsule)
Extracts an MlirTypeID from a capsule as produced from mlirPythonTypeIDToCapsule.
Definition: Interop.h:336
static PyObject * mlirPythonDialectRegistryToCapsule(MlirDialectRegistry registry)
Creates a capsule object encapsulating the raw C-API MlirDialectRegistry.
Definition: Interop.h:234
static PyObject * mlirPythonTypeToCapsule(MlirType type)
Creates a capsule object encapsulating the raw C-API MlirType.
Definition: Interop.h:346
static MlirDialectRegistry mlirPythonCapsuleToDialectRegistry(PyObject *capsule)
Extracts an MlirDialectRegistry from a capsule as produced from mlirPythonDialectRegistryToCapsule.
Definition: Interop.h:244
#define MAKE_MLIR_PYTHON_QUALNAME(local)
Definition: Interop.h:56
static MlirType mlirPythonCapsuleToType(PyObject *capsule)
Extracts an MlirType from a capsule as produced from mlirPythonTypeToCapsule.
Definition: Interop.h:355
static MlirValue mlirPythonCapsuleToValue(PyObject *capsule)
Extracts an MlirValue from a capsule as produced from mlirPythonValueToCapsule.
Definition: Interop.h:433
static PyObject * mlirPythonAffineMapToCapsule(MlirAffineMap affineMap)
Creates a capsule object encapsulating the raw C-API MlirAffineMap.
Definition: Interop.h:365
static MlirPassManager mlirPythonCapsuleToPassManager(PyObject *capsule)
Extracts an MlirPassManager from a capsule as produced from mlirPythonPassManagerToCapsule.
Definition: Interop.h:299
static PyObject * mlirPythonOperationToCapsule(MlirOperation operation)
Creates a capsule object encapsulating the raw C-API MlirOperation.
Definition: Interop.h:309
static MlirLocation mlirPythonCapsuleToLocation(PyObject *capsule)
Extracts an MlirLocation from a capsule as produced from mlirPythonLocationToCapsule.
Definition: Interop.h:263
static PyObject * mlirPythonValueToCapsule(MlirValue value)
Creates a capsule object encapsulating the raw C-API MlirValue.
Definition: Interop.h:424
#define MLIR_PYTHON_CAPI_TYPE_CASTER_REGISTER_ATTR
Attribute on main C extension module (_mlir) that corresponds to the type caster registration binding...
Definition: Interop.h:129
static std::string diag(const llvm::Value &value)
RAII scope intercepting all diagnostics into a string.
Creates a custom subclass of mlir.ir.Attribute, implementing a casting constructor and type checking ...
mlir_attribute_subclass(py::handle scope, const char *typeClassName, IsAFunctionTy isaFunction, const py::object &superCls)
Subclasses with a provided mlir.ir.Attribute super-class.
mlir_attribute_subclass(py::handle scope, const char *attrClassName, IsAFunctionTy isaFunction)
Subclasses by looking up the super-class dynamically.
Creates a custom subclass of mlir.ir.Type, implementing a casting constructor and type checking metho...
mlir_type_subclass(py::handle scope, const char *typeClassName, IsAFunctionTy isaFunction, const py::object &superCls, GetTypeIDFunctionTy getTypeIDFunction=nullptr)
Subclasses with a provided mlir.ir.Type super-class.
mlir_type_subclass(py::handle scope, const char *typeClassName, IsAFunctionTy isaFunction, GetTypeIDFunctionTy getTypeIDFunction=nullptr)
Subclasses by looking up the super-class dynamically.
Creates a custom subclass of mlir.ir.Value, implementing a casting constructor and type checking meth...
mlir_value_subclass(py::handle scope, const char *valueClassName, IsAFunctionTy isaFunction, const py::object &superCls)
Subclasses with a provided mlir.ir.Value super-class.
mlir_value_subclass(py::handle scope, const char *valueClassName, IsAFunctionTy isaFunction)
Subclasses by looking up the super-class dynamically.
Provides a facility like py::class_ for defining a new class in a scope, but this allows extension of...
pure_subclass & def_classmethod(const char *name, Func &&f, const Extra &...extra)
pure_subclass & def(const char *name, Func &&f, const Extra &...extra)
pure_subclass(py::handle scope, const char *derivedClassName, const py::object &superClass)
pure_subclass & def_property_readonly(const char *name, Func &&f, const Extra &...extra)
pure_subclass & def_staticmethod(const char *name, Func &&f, const Extra &...extra)
MLIR_CAPI_EXPORTED void mlirDiagnosticPrint(MlirDiagnostic diagnostic, MlirStringCallback callback, void *userData)
Prints a diagnostic using the provided callback.
Definition: Diagnostics.cpp:18
MLIR_CAPI_EXPORTED MlirDiagnosticHandlerID mlirContextAttachDiagnosticHandler(MlirContext context, MlirDiagnosticHandler handler, void *userData, void(*deleteUserData)(void *))
Attaches the diagnostic handler to the context.
Definition: Diagnostics.cpp:56
MLIR_CAPI_EXPORTED void mlirContextDetachDiagnosticHandler(MlirContext context, MlirDiagnosticHandlerID id)
Detaches an attached diagnostic handler from the context given its identifier.
Definition: Diagnostics.cpp:72
uint64_t MlirDiagnosticHandlerID
Opaque identifier of a diagnostic handler, useful to detach a handler.
Definition: Diagnostics.h:41
MLIR_CAPI_EXPORTED MlirLocation mlirDiagnosticGetLocation(MlirDiagnostic diagnostic)
Returns the location at which the diagnostic is reported.
Definition: Diagnostics.cpp:24
static bool mlirPassManagerIsNull(MlirPassManager passManager)
Checks if a PassManager is null.
Definition: Pass.h:65
static bool mlirAffineMapIsNull(MlirAffineMap affineMap)
Checks whether an affine map is null.
Definition: AffineMap.h:47
static bool mlirAttributeIsNull(MlirAttribute attr)
Checks whether an attribute is null.
Definition: IR.h:1011
static bool mlirModuleIsNull(MlirModule module)
Checks whether a module is null.
Definition: IR.h:314
static bool mlirValueIsNull(MlirValue value)
Returns whether the value is null.
Definition: IR.h:875
static bool mlirTypeIsNull(MlirType type)
Checks whether a type is null.
Definition: IR.h:976
static bool mlirContextIsNull(MlirContext context)
Checks whether a context is null.
Definition: IR.h:104
static bool mlirBlockIsNull(MlirBlock block)
Checks whether a block is null.
Definition: IR.h:797
static bool mlirLocationIsNull(MlirLocation location)
Checks if the location is null.
Definition: IR.h:282
MLIR_CAPI_EXPORTED void mlirLocationPrint(MlirLocation location, MlirStringCallback callback, void *userData)
Prints a location by sending chunks of the string representation and forwarding userData tocallback`.
Definition: IR.cpp:291
static bool mlirDialectRegistryIsNull(MlirDialectRegistry registry)
Checks if the dialect registry is null.
Definition: IR.h:235
static bool mlirOperationIsNull(MlirOperation op)
Checks whether the underlying operation is null.
Definition: IR.h:507
static MlirLogicalResult mlirLogicalResultSuccess(void)
Creates a logical result representing a success.
Definition: Support.h:132
static bool mlirTypeIDIsNull(MlirTypeID typeID)
Checks whether a type id is null.
Definition: Support.h:163
Include the generated interface declarations.
static py::object mlirApiObjectToCapsule(py::handle apiObject)
Helper to convert a presumed MLIR API object to a capsule, accepting either an explicit Capsule (whic...
An opaque reference to a diagnostic, always owned by the diagnostics engine (context).
Definition: Diagnostics.h:26
A logical result value, essentially a boolean with named states.
Definition: Support.h:116
A pointer to a sized fragment of a string, not necessarily null-terminated.
Definition: Support.h:73
const char * data
Pointer to the first symbol.
Definition: Support.h:74
size_t length
Length of the fragment.
Definition: Support.h:75
PYBIND11_TYPE_CASTER(MlirAffineMap, _("MlirAffineMap"))
static handle cast(MlirAffineMap v, return_value_policy, handle)
PYBIND11_TYPE_CASTER(MlirAttribute, _("MlirAttribute"))
static handle cast(MlirAttribute v, return_value_policy, handle)
PYBIND11_TYPE_CASTER(MlirBlock, _("MlirBlock"))
PYBIND11_TYPE_CASTER(MlirContext, _("MlirContext"))
PYBIND11_TYPE_CASTER(MlirDialectRegistry, _("MlirDialectRegistry"))
static handle cast(MlirDialectRegistry v, return_value_policy, handle)
PYBIND11_TYPE_CASTER(MlirLocation, _("MlirLocation"))
static handle cast(MlirLocation v, return_value_policy, handle)
PYBIND11_TYPE_CASTER(MlirModule, _("MlirModule"))
static handle cast(MlirModule v, return_value_policy, handle)
PYBIND11_TYPE_CASTER(MlirOperation, _("MlirOperation"))
static handle cast(MlirOperation v, return_value_policy, handle)
PYBIND11_TYPE_CASTER(MlirPassManager, _("MlirPassManager"))
PYBIND11_TYPE_CASTER(MlirTypeID, _("MlirTypeID"))
static handle cast(MlirTypeID v, return_value_policy, handle)
static handle cast(MlirType t, return_value_policy, handle)
PYBIND11_TYPE_CASTER(MlirType, _("MlirType"))
static handle cast(MlirValue v, return_value_policy, handle)
PYBIND11_TYPE_CASTER(MlirValue, _("MlirValue"))