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