MLIR 23.0.0git
IRInterfaces.h
Go to the documentation of this file.
1//===- IRInterfaces.h - IR Interfaces for Python Bindings -------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef MLIR_BINDINGS_PYTHON_IRINTERFACES_H
10#define MLIR_BINDINGS_PYTHON_IRINTERFACES_H
11
12#include "mlir-c/IR.h"
13#include "mlir-c/Interfaces.h"
14#include "mlir-c/Support.h"
16
17#include <nanobind/nanobind.h>
18
19namespace mlir {
20namespace python {
22
23constexpr static const char *constructorDoc =
24 R"(Creates an interface from a given operation/opview object or from a
25subclass of OpView. Raises ValueError if the operation does not implement the
26interface.)";
27
28constexpr static const char *operationDoc =
29 R"(Returns an Operation for which the interface was constructed.)";
30
31constexpr static const char *opviewDoc =
32 R"(Returns an OpView subclass _instance_ for which the interface was
33constructed)";
34
35/// CRTP base class for Python classes representing MLIR Op interfaces.
36/// Interface hierarchies are flat so no base class is expected here. The
37/// derived class is expected to define the following static fields:
38/// - `const char *pyClassName` - the name of the Python class to create;
39/// - `GetTypeIDFunctionTy getInterfaceID` - the function producing the TypeID
40/// of the interface.
41/// Derived classes may redefine the `bindDerived(ClassTy &)` method to bind
42/// interface-specific methods.
43///
44/// An interface class may be constructed from either an Operation/OpView object
45/// or from a subclass of OpView. In the latter case, only the static interface
46/// methods are available, similarly to calling ConcereteOp::staticMethod on the
47/// C++ side. Implementations of concrete interfaces can use the `isStatic`
48/// method to check whether the interface object was constructed from a class or
49/// an operation/opview instance. The `getOpName` always succeeds and returns a
50/// canonical name of the operation suitable for lookups.
51template <typename ConcreteIface>
53protected:
54 using ClassTy = nanobind::class_<ConcreteIface>;
55 using GetTypeIDFunctionTy = MlirTypeID (*)();
56
57public:
58 /// Constructs an interface instance from an object that is either an
59 /// operation or a subclass of OpView. In the latter case, only the static
60 /// methods of the interface are accessible to the caller.
61 PyConcreteOpInterface(nanobind::object object,
63 : obj(std::move(object)) {
64 if (!nanobind::try_cast<PyOperation *>(obj, operation)) {
65 PyOpView *opview;
66 if (nanobind::try_cast<PyOpView *>(obj, opview)) {
67 operation = &opview->getOperation();
68 };
69 }
70
71 if (operation != nullptr) {
73 ConcreteIface::getInterfaceID())) {
74 std::string msg = "the operation does not implement ";
75 throw nanobind::value_error((msg + ConcreteIface::pyClassName).c_str());
76 }
77
78 MlirIdentifier identifier = mlirOperationGetName(*operation);
79 MlirStringRef stringRef = mlirIdentifierStr(identifier);
80 opName = std::string(stringRef.data, stringRef.length);
81 } else {
82 if (!nanobind::try_cast<std::string>(obj.attr("OPERATION_NAME"), opName))
83 throw nanobind::type_error(
84 "Op interface does not refer to an operation or OpView class");
85
87 mlirStringRefCreate(opName.data(), opName.length()),
88 context.resolve().get(), ConcreteIface::getInterfaceID())) {
89 std::string msg = "the operation does not implement ";
90 throw nanobind::value_error((msg + ConcreteIface::pyClassName).c_str());
91 }
92 }
93 }
94
95 /// Creates the Python bindings for this class in the given module.
96 static void bind(nanobind::module_ &m) {
97 nanobind::class_<ConcreteIface> cls(m, ConcreteIface::pyClassName);
98 cls.def(nanobind::init<nanobind::object, DefaultingPyMlirContext>(),
99 nanobind::arg("object"),
100 nanobind::arg("context") = nanobind::none(), constructorDoc)
101 .def_prop_ro("operation", &PyConcreteOpInterface::getOperationObject,
103 .def_prop_ro("opview", &PyConcreteOpInterface::getOpView, opviewDoc);
104 ConcreteIface::bindDerived(cls);
105 }
106
107 /// Hook for derived classes to add class-specific bindings.
108 static void bindDerived(ClassTy &cls) {}
109
110 /// Returns `true` if this object was constructed from a subclass of OpView
111 /// rather than from an operation instance.
112 bool isStatic() { return operation == nullptr; }
113
114 /// Returns the operation instance from which this object was constructed.
115 /// Throws a type error if this object was constructed from a subclass of
116 /// OpView.
117 nanobind::typed<nanobind::object, PyOperation> getOperationObject() {
118 if (operation == nullptr)
119 throw nanobind::type_error(
120 "Cannot get an operation from a static interface");
121 return operation->getRef().releaseObject();
122 }
123
124 /// Returns the opview of the operation instance from which this object was
125 /// constructed. Throws a type error if this object was constructed form a
126 /// subclass of OpView.
127 nanobind::typed<nanobind::object, PyOpView> getOpView() {
128 if (operation == nullptr)
129 throw nanobind::type_error(
130 "Cannot get an opview from a static interface");
131 return operation->createOpView();
132 }
133
134 /// Returns the canonical name of the operation this interface is constructed
135 /// from.
136 const std::string &getOpName() { return opName; }
137
138private:
139 PyOperation *operation = nullptr;
140 std::string opName;
141 nanobind::object obj;
142};
143
145 MlirMemoryEffectInstancesList effects;
146};
147
148} // namespace MLIR_BINDINGS_PYTHON_DOMAIN
149} // namespace python
150} // namespace mlir
151
152#endif // MLIR_BINDINGS_PYTHON_IRINTERFACES_H
MlirIdentifier mlirOperationGetName(MlirOperation op)
Definition IR.cpp:668
Used in function arguments when None should resolve to the current context manager set instance.
Definition IRCore.h:279
static void bind(nanobind::module_ &m)
Creates the Python bindings for this class in the given module.
const std::string & getOpName()
Returns the canonical name of the operation this interface is constructed from.
PyConcreteOpInterface(nanobind::object object, DefaultingPyMlirContext context)
Constructs an interface instance from an object that is either an operation or a subclass of OpView.
nanobind::typed< nanobind::object, PyOperation > getOperationObject()
Returns the operation instance from which this object was constructed.
nanobind::typed< nanobind::object, PyOpView > getOpView()
Returns the opview of the operation instance from which this object was constructed.
bool isStatic()
Returns true if this object was constructed from a subclass of OpView rather than from an operation i...
static void bindDerived(ClassTy &cls)
Hook for derived classes to add class-specific bindings.
MlirContext get()
Accesses the underlying MlirContext.
Definition IRCore.h:212
A PyOpView is equivalent to the C++ "Op" wrappers: these are the basis for providing more instance-sp...
Definition IRCore.h:735
PyOperation & getOperation() override
Each must provide access to the raw Operation.
Definition IRCore.h:738
MLIR_CAPI_EXPORTED MlirStringRef mlirIdentifierStr(MlirIdentifier ident)
Gets the string value of the identifier.
Definition IR.cpp:1336
MLIR_CAPI_EXPORTED bool mlirOperationImplementsInterfaceStatic(MlirStringRef operationName, MlirContext context, MlirTypeID interfaceTypeID)
Returns true if the operation identified by its canonical string name implements the interface identi...
MLIR_CAPI_EXPORTED bool mlirOperationImplementsInterface(MlirOperation operation, MlirTypeID interfaceTypeID)
Returns true if the given operation implements an interface identified by its TypeID.
static MlirStringRef mlirStringRefCreate(const char *str, size_t length)
Constructs a string reference from the pointer and length.
Definition Support.h:87
static constexpr const char * operationDoc
static constexpr const char * opviewDoc
static constexpr const char * constructorDoc
Include the generated interface declarations.
A pointer to a sized fragment of a string, not necessarily null-terminated.
Definition Support.h:78
const char * data
Pointer to the first symbol.
Definition Support.h:79
size_t length
Length of the fragment.
Definition Support.h:80