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 <-> MlirFrozenRewritePatternSet.
202 template <>
203 struct type_caster<MlirFrozenRewritePatternSet> {
204  PYBIND11_TYPE_CASTER(MlirFrozenRewritePatternSet,
205  _("MlirFrozenRewritePatternSet"));
206  bool load(handle src, bool) {
207  py::object capsule = mlirApiObjectToCapsule(src);
208  value = mlirPythonCapsuleToFrozenRewritePatternSet(capsule.ptr());
209  return value.ptr != nullptr;
210  }
211  static handle cast(MlirFrozenRewritePatternSet v, return_value_policy,
212  handle) {
213  py::object capsule = py::reinterpret_steal<py::object>(
215  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("rewrite"))
216  .attr("FrozenRewritePatternSet")
217  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
218  .release();
219  };
220 };
221 
222 /// Casts object <-> MlirOperation.
223 template <>
224 struct type_caster<MlirOperation> {
225  PYBIND11_TYPE_CASTER(MlirOperation, _("MlirOperation"));
226  bool load(handle src, bool) {
227  py::object capsule = mlirApiObjectToCapsule(src);
228  value = mlirPythonCapsuleToOperation(capsule.ptr());
229  return !mlirOperationIsNull(value);
230  }
231  static handle cast(MlirOperation v, return_value_policy, handle) {
232  if (v.ptr == nullptr)
233  return py::none();
234  py::object capsule =
235  py::reinterpret_steal<py::object>(mlirPythonOperationToCapsule(v));
236  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
237  .attr("Operation")
238  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
239  .release();
240  };
241 };
242 
243 /// Casts object <-> MlirValue.
244 template <>
245 struct type_caster<MlirValue> {
246  PYBIND11_TYPE_CASTER(MlirValue, _("MlirValue"));
247  bool load(handle src, bool) {
248  py::object capsule = mlirApiObjectToCapsule(src);
249  value = mlirPythonCapsuleToValue(capsule.ptr());
250  return !mlirValueIsNull(value);
251  }
252  static handle cast(MlirValue v, return_value_policy, handle) {
253  if (v.ptr == nullptr)
254  return py::none();
255  py::object capsule =
256  py::reinterpret_steal<py::object>(mlirPythonValueToCapsule(v));
257  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
258  .attr("Value")
259  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
261  .release();
262  };
263 };
264 
265 /// Casts object -> MlirPassManager.
266 template <>
267 struct type_caster<MlirPassManager> {
268  PYBIND11_TYPE_CASTER(MlirPassManager, _("MlirPassManager"));
269  bool load(handle src, bool) {
270  py::object capsule = mlirApiObjectToCapsule(src);
271  value = mlirPythonCapsuleToPassManager(capsule.ptr());
272  return !mlirPassManagerIsNull(value);
273  }
274 };
275 
276 /// Casts object <-> MlirTypeID.
277 template <>
278 struct type_caster<MlirTypeID> {
279  PYBIND11_TYPE_CASTER(MlirTypeID, _("MlirTypeID"));
280  bool load(handle src, bool) {
281  py::object capsule = mlirApiObjectToCapsule(src);
282  value = mlirPythonCapsuleToTypeID(capsule.ptr());
283  return !mlirTypeIDIsNull(value);
284  }
285  static handle cast(MlirTypeID v, return_value_policy, handle) {
286  if (v.ptr == nullptr)
287  return py::none();
288  py::object capsule =
289  py::reinterpret_steal<py::object>(mlirPythonTypeIDToCapsule(v));
290  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
291  .attr("TypeID")
292  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
293  .release();
294  };
295 };
296 
297 /// Casts object <-> MlirType.
298 template <>
299 struct type_caster<MlirType> {
300  PYBIND11_TYPE_CASTER(MlirType, _("MlirType"));
301  bool load(handle src, bool) {
302  py::object capsule = mlirApiObjectToCapsule(src);
303  value = mlirPythonCapsuleToType(capsule.ptr());
304  return !mlirTypeIsNull(value);
305  }
306  static handle cast(MlirType t, return_value_policy, handle) {
307  py::object capsule =
308  py::reinterpret_steal<py::object>(mlirPythonTypeToCapsule(t));
309  return py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
310  .attr("Type")
311  .attr(MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
313  .release();
314  }
315 };
316 
317 } // namespace detail
318 } // namespace pybind11
319 
320 namespace mlir {
321 namespace python {
322 namespace adaptors {
323 
324 /// Provides a facility like py::class_ for defining a new class in a scope,
325 /// but this allows extension of an arbitrary Python class, defining methods
326 /// on it is a similar way. Classes defined in this way are very similar to
327 /// if defined in Python in the usual way but use Pybind11 machinery to do
328 /// it. These are not "real" Pybind11 classes but pure Python classes with no
329 /// relation to a concrete C++ class.
330 ///
331 /// Derived from a discussion upstream:
332 /// https://github.com/pybind/pybind11/issues/1193
333 /// (plus a fair amount of extra curricular poking)
334 /// TODO: If this proves useful, see about including it in pybind11.
336 public:
337  pure_subclass(py::handle scope, const char *derivedClassName,
338  const py::object &superClass) {
339  py::object pyType =
340  py::reinterpret_borrow<py::object>((PyObject *)&PyType_Type);
341  py::object metaclass = pyType(superClass);
342  py::dict attributes;
343 
344  thisClass =
345  metaclass(derivedClassName, py::make_tuple(superClass), attributes);
346  scope.attr(derivedClassName) = thisClass;
347  }
348 
349  template <typename Func, typename... Extra>
350  pure_subclass &def(const char *name, Func &&f, const Extra &...extra) {
351  py::cpp_function cf(
352  std::forward<Func>(f), py::name(name), py::is_method(thisClass),
353  py::sibling(py::getattr(thisClass, name, py::none())), extra...);
354  thisClass.attr(cf.name()) = cf;
355  return *this;
356  }
357 
358  template <typename Func, typename... Extra>
359  pure_subclass &def_property_readonly(const char *name, Func &&f,
360  const Extra &...extra) {
361  py::cpp_function cf(
362  std::forward<Func>(f), py::name(name), py::is_method(thisClass),
363  py::sibling(py::getattr(thisClass, name, py::none())), extra...);
364  auto builtinProperty =
365  py::reinterpret_borrow<py::object>((PyObject *)&PyProperty_Type);
366  thisClass.attr(name) = builtinProperty(cf);
367  return *this;
368  }
369 
370  template <typename Func, typename... Extra>
371  pure_subclass &def_staticmethod(const char *name, Func &&f,
372  const Extra &...extra) {
373  static_assert(!std::is_member_function_pointer<Func>::value,
374  "def_staticmethod(...) called with a non-static member "
375  "function pointer");
376  py::cpp_function cf(
377  std::forward<Func>(f), py::name(name), py::scope(thisClass),
378  py::sibling(py::getattr(thisClass, name, py::none())), extra...);
379  thisClass.attr(cf.name()) = py::staticmethod(cf);
380  return *this;
381  }
382 
383  template <typename Func, typename... Extra>
384  pure_subclass &def_classmethod(const char *name, Func &&f,
385  const Extra &...extra) {
386  static_assert(!std::is_member_function_pointer<Func>::value,
387  "def_classmethod(...) called with a non-static member "
388  "function pointer");
389  py::cpp_function cf(
390  std::forward<Func>(f), py::name(name), py::scope(thisClass),
391  py::sibling(py::getattr(thisClass, name, py::none())), extra...);
392  thisClass.attr(cf.name()) =
393  py::reinterpret_borrow<py::object>(PyClassMethod_New(cf.ptr()));
394  return *this;
395  }
396 
397  py::object get_class() const { return thisClass; }
398 
399 protected:
400  py::object superClass;
401  py::object thisClass;
402 };
403 
404 /// Creates a custom subclass of mlir.ir.Attribute, implementing a casting
405 /// constructor and type checking methods.
407 public:
408  using IsAFunctionTy = bool (*)(MlirAttribute);
409  using GetTypeIDFunctionTy = MlirTypeID (*)();
410 
411  /// Subclasses by looking up the super-class dynamically.
412  mlir_attribute_subclass(py::handle scope, const char *attrClassName,
413  IsAFunctionTy isaFunction,
414  GetTypeIDFunctionTy getTypeIDFunction = nullptr)
416  scope, attrClassName, isaFunction,
417  py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
418  .attr("Attribute"),
419  getTypeIDFunction) {}
420 
421  /// Subclasses with a provided mlir.ir.Attribute super-class. This must
422  /// be used if the subclass is being defined in the same extension module
423  /// as the mlir.ir class (otherwise, it will trigger a recursive
424  /// initialization).
425  mlir_attribute_subclass(py::handle scope, const char *typeClassName,
426  IsAFunctionTy isaFunction, const py::object &superCls,
427  GetTypeIDFunctionTy getTypeIDFunction = nullptr)
428  : pure_subclass(scope, typeClassName, superCls) {
429  // Casting constructor. Note that it hard, if not impossible, to properly
430  // call chain to parent `__init__` in pybind11 due to its special handling
431  // for init functions that don't have a fully constructed self-reference,
432  // which makes it impossible to forward it to `__init__` of a superclass.
433  // Instead, provide a custom `__new__` and call that of a superclass, which
434  // eventually calls `__init__` of the superclass. Since attribute subclasses
435  // have no additional members, we can just return the instance thus created
436  // without amending it.
437  std::string captureTypeName(
438  typeClassName); // As string in case if typeClassName is not static.
439  py::cpp_function newCf(
440  [superCls, isaFunction, captureTypeName](py::object cls,
441  py::object otherAttribute) {
442  MlirAttribute rawAttribute = py::cast<MlirAttribute>(otherAttribute);
443  if (!isaFunction(rawAttribute)) {
444  auto origRepr = py::repr(otherAttribute).cast<std::string>();
445  throw std::invalid_argument(
446  (llvm::Twine("Cannot cast attribute to ") + captureTypeName +
447  " (from " + origRepr + ")")
448  .str());
449  }
450  py::object self = superCls.attr("__new__")(cls, otherAttribute);
451  return self;
452  },
453  py::name("__new__"), py::arg("cls"), py::arg("cast_from_attr"));
454  thisClass.attr("__new__") = newCf;
455 
456  // 'isinstance' method.
457  def_staticmethod(
458  "isinstance",
459  [isaFunction](MlirAttribute other) { return isaFunction(other); },
460  py::arg("other_attribute"));
461  def("__repr__", [superCls, captureTypeName](py::object self) {
462  return py::repr(superCls(self))
463  .attr("replace")(superCls.attr("__name__"), captureTypeName);
464  });
465  if (getTypeIDFunction) {
466  def_staticmethod("get_static_typeid",
467  [getTypeIDFunction]() { return getTypeIDFunction(); });
468  py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
470  getTypeIDFunction())(pybind11::cpp_function(
471  [thisClass = thisClass](const py::object &mlirAttribute) {
472  return thisClass(mlirAttribute);
473  }));
474  }
475  }
476 };
477 
478 /// Creates a custom subclass of mlir.ir.Type, implementing a casting
479 /// constructor and type checking methods.
481 public:
482  using IsAFunctionTy = bool (*)(MlirType);
483  using GetTypeIDFunctionTy = MlirTypeID (*)();
484 
485  /// Subclasses by looking up the super-class dynamically.
486  mlir_type_subclass(py::handle scope, const char *typeClassName,
487  IsAFunctionTy isaFunction,
488  GetTypeIDFunctionTy getTypeIDFunction = nullptr)
490  scope, typeClassName, isaFunction,
491  py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")).attr("Type"),
492  getTypeIDFunction) {}
493 
494  /// Subclasses with a provided mlir.ir.Type super-class. This must
495  /// be used if the subclass is being defined in the same extension module
496  /// as the mlir.ir class (otherwise, it will trigger a recursive
497  /// initialization).
498  mlir_type_subclass(py::handle scope, const char *typeClassName,
499  IsAFunctionTy isaFunction, const py::object &superCls,
500  GetTypeIDFunctionTy getTypeIDFunction = nullptr)
501  : pure_subclass(scope, typeClassName, superCls) {
502  // Casting constructor. Note that it hard, if not impossible, to properly
503  // call chain to parent `__init__` in pybind11 due to its special handling
504  // for init functions that don't have a fully constructed self-reference,
505  // which makes it impossible to forward it to `__init__` of a superclass.
506  // Instead, provide a custom `__new__` and call that of a superclass, which
507  // eventually calls `__init__` of the superclass. Since attribute subclasses
508  // have no additional members, we can just return the instance thus created
509  // without amending it.
510  std::string captureTypeName(
511  typeClassName); // As string in case if typeClassName is not static.
512  py::cpp_function newCf(
513  [superCls, isaFunction, captureTypeName](py::object cls,
514  py::object otherType) {
515  MlirType rawType = py::cast<MlirType>(otherType);
516  if (!isaFunction(rawType)) {
517  auto origRepr = py::repr(otherType).cast<std::string>();
518  throw std::invalid_argument((llvm::Twine("Cannot cast type to ") +
519  captureTypeName + " (from " +
520  origRepr + ")")
521  .str());
522  }
523  py::object self = superCls.attr("__new__")(cls, otherType);
524  return self;
525  },
526  py::name("__new__"), py::arg("cls"), py::arg("cast_from_type"));
527  thisClass.attr("__new__") = newCf;
528 
529  // 'isinstance' method.
530  def_staticmethod(
531  "isinstance",
532  [isaFunction](MlirType other) { return isaFunction(other); },
533  py::arg("other_type"));
534  def("__repr__", [superCls, captureTypeName](py::object self) {
535  return py::repr(superCls(self))
536  .attr("replace")(superCls.attr("__name__"), captureTypeName);
537  });
538  if (getTypeIDFunction) {
539  // 'get_static_typeid' method.
540  // This is modeled as a static method instead of a static property because
541  // `def_property_readonly_static` is not available in `pure_subclass` and
542  // we do not want to introduce the complexity that pybind uses to
543  // implement it.
544  def_staticmethod("get_static_typeid",
545  [getTypeIDFunction]() { return getTypeIDFunction(); });
546  py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir"))
548  getTypeIDFunction())(pybind11::cpp_function(
549  [thisClass = thisClass](const py::object &mlirType) {
550  return thisClass(mlirType);
551  }));
552  }
553  }
554 };
555 
556 /// Creates a custom subclass of mlir.ir.Value, implementing a casting
557 /// constructor and type checking methods.
559 public:
560  using IsAFunctionTy = bool (*)(MlirValue);
561 
562  /// Subclasses by looking up the super-class dynamically.
563  mlir_value_subclass(py::handle scope, const char *valueClassName,
564  IsAFunctionTy isaFunction)
566  scope, valueClassName, isaFunction,
567  py::module::import(MAKE_MLIR_PYTHON_QUALNAME("ir")).attr("Value")) {
568  }
569 
570  /// Subclasses with a provided mlir.ir.Value super-class. This must
571  /// be used if the subclass is being defined in the same extension module
572  /// as the mlir.ir class (otherwise, it will trigger a recursive
573  /// initialization).
574  mlir_value_subclass(py::handle scope, const char *valueClassName,
575  IsAFunctionTy isaFunction, const py::object &superCls)
576  : pure_subclass(scope, valueClassName, superCls) {
577  // Casting constructor. Note that it hard, if not impossible, to properly
578  // call chain to parent `__init__` in pybind11 due to its special handling
579  // for init functions that don't have a fully constructed self-reference,
580  // which makes it impossible to forward it to `__init__` of a superclass.
581  // Instead, provide a custom `__new__` and call that of a superclass, which
582  // eventually calls `__init__` of the superclass. Since attribute subclasses
583  // have no additional members, we can just return the instance thus created
584  // without amending it.
585  std::string captureValueName(
586  valueClassName); // As string in case if valueClassName is not static.
587  py::cpp_function newCf(
588  [superCls, isaFunction, captureValueName](py::object cls,
589  py::object otherValue) {
590  MlirValue rawValue = py::cast<MlirValue>(otherValue);
591  if (!isaFunction(rawValue)) {
592  auto origRepr = py::repr(otherValue).cast<std::string>();
593  throw std::invalid_argument((llvm::Twine("Cannot cast value to ") +
594  captureValueName + " (from " +
595  origRepr + ")")
596  .str());
597  }
598  py::object self = superCls.attr("__new__")(cls, otherValue);
599  return self;
600  },
601  py::name("__new__"), py::arg("cls"), py::arg("cast_from_value"));
602  thisClass.attr("__new__") = newCf;
603 
604  // 'isinstance' method.
605  def_staticmethod(
606  "isinstance",
607  [isaFunction](MlirValue other) { return isaFunction(other); },
608  py::arg("other_value"));
609  }
610 };
611 
612 } // namespace adaptors
613 
614 /// RAII scope intercepting all diagnostics into a string. The message must be
615 /// checked before this goes out of scope.
617 public:
618  explicit CollectDiagnosticsToStringScope(MlirContext ctx) : context(ctx) {
619  handlerID = mlirContextAttachDiagnosticHandler(ctx, &handler, &errorMessage,
620  /*deleteUserData=*/nullptr);
621  }
623  assert(errorMessage.empty() && "unchecked error message");
624  mlirContextDetachDiagnosticHandler(context, handlerID);
625  }
626 
627  [[nodiscard]] std::string takeMessage() { return std::move(errorMessage); }
628 
629 private:
630  static MlirLogicalResult handler(MlirDiagnostic diag, void *data) {
631  auto printer = +[](MlirStringRef message, void *data) {
632  *static_cast<std::string *>(data) +=
633  llvm::StringRef(message.data, message.length);
634  };
635  MlirLocation loc = mlirDiagnosticGetLocation(diag);
636  *static_cast<std::string *>(data) += "at ";
637  mlirLocationPrint(loc, printer, data);
638  *static_cast<std::string *>(data) += ": ";
639  mlirDiagnosticPrint(diag, printer, data);
640  return mlirLogicalResultSuccess();
641  }
642 
643  MlirContext context;
644  MlirDiagnosticHandlerID handlerID;
645  std::string errorMessage = "";
646 };
647 
648 } // namespace python
649 } // namespace mlir
650 
651 #endif // MLIR_BINDINGS_PYTHON_PYBINDADAPTORS_H
static PyObject * mlirPythonModuleToCapsule(MlirModule module)
Creates a capsule object encapsulating the raw C-API MlirModule.
Definition: Interop.h:273
#define MLIR_PYTHON_MAYBE_DOWNCAST_ATTR
Attribute on MLIR Python objects that expose a function for downcasting the corresponding Python obje...
Definition: Interop.h:118
static MlirBlock mlirPythonCapsuleToBlock(PyObject *capsule)
Extracts an MlirBlock from a capsule as produced from mlirPythonBlockToCapsule.
Definition: Interop.h:206
static PyObject * mlirPythonTypeIDToCapsule(MlirTypeID typeID)
Creates a capsule object encapsulating the raw C-API MlirTypeID.
Definition: Interop.h:348
static MlirOperation mlirPythonCapsuleToOperation(PyObject *capsule)
Extracts an MlirOperations from a capsule as produced from mlirPythonOperationToCapsule.
Definition: Interop.h:338
static MlirFrozenRewritePatternSet mlirPythonCapsuleToFrozenRewritePatternSet(PyObject *capsule)
Extracts an MlirFrozenRewritePatternSet from a capsule as produced from mlirPythonFrozenRewritePatter...
Definition: Interop.h:302
#define MLIR_PYTHON_CAPI_PTR_ATTR
Attribute on MLIR Python objects that expose their C-API pointer.
Definition: Interop.h:97
static MlirAttribute mlirPythonCapsuleToAttribute(PyObject *capsule)
Extracts an MlirAttribute from a capsule as produced from mlirPythonAttributeToCapsule.
Definition: Interop.h:189
static PyObject * mlirPythonAttributeToCapsule(MlirAttribute attribute)
Creates a capsule object encapsulating the raw C-API MlirAttribute.
Definition: Interop.h:180
static PyObject * mlirPythonLocationToCapsule(MlirLocation loc)
Creates a capsule object encapsulating the raw C-API MlirLocation.
Definition: Interop.h:255
static MlirAffineMap mlirPythonCapsuleToAffineMap(PyObject *capsule)
Extracts an MlirAffineMap from a capsule as produced from mlirPythonAffineMapToCapsule.
Definition: Interop.h:395
#define MLIR_PYTHON_CAPI_FACTORY_ATTR
Attribute on MLIR Python objects that exposes a factory function for constructing the corresponding P...
Definition: Interop.h:110
static MlirModule mlirPythonCapsuleToModule(PyObject *capsule)
Extracts an MlirModule from a capsule as produced from mlirPythonModuleToCapsule.
Definition: Interop.h:282
static MlirContext mlirPythonCapsuleToContext(PyObject *capsule)
Extracts a MlirContext from a capsule as produced from mlirPythonContextToCapsule.
Definition: Interop.h:224
static MlirTypeID mlirPythonCapsuleToTypeID(PyObject *capsule)
Extracts an MlirTypeID from a capsule as produced from mlirPythonTypeIDToCapsule.
Definition: Interop.h:357
static PyObject * mlirPythonDialectRegistryToCapsule(MlirDialectRegistry registry)
Creates a capsule object encapsulating the raw C-API MlirDialectRegistry.
Definition: Interop.h:235
static PyObject * mlirPythonTypeToCapsule(MlirType type)
Creates a capsule object encapsulating the raw C-API MlirType.
Definition: Interop.h:367
static MlirDialectRegistry mlirPythonCapsuleToDialectRegistry(PyObject *capsule)
Extracts an MlirDialectRegistry from a capsule as produced from mlirPythonDialectRegistryToCapsule.
Definition: Interop.h:245
#define MAKE_MLIR_PYTHON_QUALNAME(local)
Definition: Interop.h:57
static PyObject * mlirPythonFrozenRewritePatternSetToCapsule(MlirFrozenRewritePatternSet pm)
Creates a capsule object encapsulating the raw C-API MlirFrozenRewritePatternSet.
Definition: Interop.h:293
static MlirType mlirPythonCapsuleToType(PyObject *capsule)
Extracts an MlirType from a capsule as produced from mlirPythonTypeToCapsule.
Definition: Interop.h:376
static MlirValue mlirPythonCapsuleToValue(PyObject *capsule)
Extracts an MlirValue from a capsule as produced from mlirPythonValueToCapsule.
Definition: Interop.h:454
static PyObject * mlirPythonAffineMapToCapsule(MlirAffineMap affineMap)
Creates a capsule object encapsulating the raw C-API MlirAffineMap.
Definition: Interop.h:386
static MlirPassManager mlirPythonCapsuleToPassManager(PyObject *capsule)
Extracts an MlirPassManager from a capsule as produced from mlirPythonPassManagerToCapsule.
Definition: Interop.h:320
static PyObject * mlirPythonOperationToCapsule(MlirOperation operation)
Creates a capsule object encapsulating the raw C-API MlirOperation.
Definition: Interop.h:330
static MlirLocation mlirPythonCapsuleToLocation(PyObject *capsule)
Extracts an MlirLocation from a capsule as produced from mlirPythonLocationToCapsule.
Definition: Interop.h:264
static PyObject * mlirPythonValueToCapsule(MlirValue value)
Creates a capsule object encapsulating the raw C-API MlirValue.
Definition: Interop.h:445
#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:130
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, GetTypeIDFunctionTy getTypeIDFunction=nullptr)
Subclasses with a provided mlir.ir.Attribute super-class.
mlir_attribute_subclass(py::handle scope, const char *attrClassName, IsAFunctionTy isaFunction, GetTypeIDFunctionTy getTypeIDFunction=nullptr)
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:1034
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:898
static bool mlirTypeIsNull(MlirType type)
Checks whether a type is null.
Definition: IR.h:999
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:817
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:299
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:519
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)
static handle cast(MlirFrozenRewritePatternSet v, return_value_policy, handle)
PYBIND11_TYPE_CASTER(MlirFrozenRewritePatternSet, _("MlirFrozenRewritePatternSet"))
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"))