1 //===-- mlir-c/Interop.h - Constants for Python/C-API interop -----*- C -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM
4 // Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This header declares constants and helpers necessary for C-level
11 // interop with the MLIR Python extension module. Since the Python bindings
12 // are a thin wrapper around the MLIR C-API, a further C-API is not provided
13 // specifically for the Python extension. Instead, simple facilities are
14 // provided for translating between Python types and corresponding MLIR C-API
15 // types.
16 //
17 // This header is standalone, requiring nothing beyond normal linking against
18 // the Python implementation.
19 //===----------------------------------------------------------------------===//
20
21 #ifndef MLIR_C_BINDINGS_PYTHON_INTEROP_H
22 #define MLIR_C_BINDINGS_PYTHON_INTEROP_H
23
24 #include <Python.h>
25
26 #include "mlir-c/IR.h"
27 #include "mlir-c/Pass.h"
28
29 #define MLIR_PYTHON_CAPSULE_ATTRIBUTE "mlir.ir.Attribute._CAPIPtr"
30 #define MLIR_PYTHON_CAPSULE_CONTEXT "mlir.ir.Context._CAPIPtr"
31 #define MLIR_PYTHON_CAPSULE_LOCATION "mlir.ir.Location._CAPIPtr"
32 #define MLIR_PYTHON_CAPSULE_MODULE "mlir.ir.Module._CAPIPtr"
33 #define MLIR_PYTHON_CAPSULE_OPERATION "mlir.ir.Operation._CAPIPtr"
34 #define MLIR_PYTHON_CAPSULE_TYPE "mlir.ir.Type._CAPIPtr"
35 #define MLIR_PYTHON_CAPSULE_PASS_MANAGER "mlir.passmanager.PassManager._CAPIPtr"
36
37 /** Attribute on MLIR Python objects that expose their C-API pointer.
38 * This will be a type-specific capsule created as per one of the helpers
39 * below.
40 *
41 * Ownership is not transferred by acquiring a capsule in this way: the
42 * validity of the pointer wrapped by the capsule will be bounded by the
43 * lifetime of the Python object that produced it. Only the name and pointer
44 * of the capsule are set. The caller is free to set a destructor and context
45 * as needed to manage anything further. */
46 #define MLIR_PYTHON_CAPI_PTR_ATTR "_CAPIPtr"
47
48 /** Attribute on MLIR Python objects that exposes a factory function for
49 * constructing the corresponding Python object from a type-specific
50 * capsule wrapping the C-API pointer. The signature of the function is:
51 * def _CAPICreate(capsule) -> object
52 * Calling such a function implies a transfer of ownership of the object the
53 * capsule wraps: after such a call, the capsule should be considered invalid,
54 * and its wrapped pointer must not be destroyed.
55 *
56 * Only a very small number of Python objects can be created in such a fashion
57 * (i.e. top-level types such as Context where the lifetime can be cleanly
58 * delineated). */
59 #define MLIR_PYTHON_CAPI_FACTORY_ATTR "_CAPICreate"
60
61 /// Gets a void* from a wrapped struct. Needed because const cast is different
62 /// between C/C++.
63 #ifdef __cplusplus
64 #define MLIR_PYTHON_GET_WRAPPED_POINTER(object) const_cast<void *>(object.ptr)
65 #else
66 #define MLIR_PYTHON_GET_WRAPPED_POINTER(object) (void *)(object.ptr)
67 #endif
68
69 #ifdef __cplusplus
70 extern "C" {
71 #endif
72
73 /** Creates a capsule object encapsulating the raw C-API MlirAttribute.
74 * The returned capsule does not extend or affect ownership of any Python
75 * objects that reference the attribute in any way.
76 */
mlirPythonAttributeToCapsule(MlirAttribute attribute)77 static inline PyObject *mlirPythonAttributeToCapsule(MlirAttribute attribute) {
78 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(attribute),
79 MLIR_PYTHON_CAPSULE_ATTRIBUTE, NULL);
80 }
81
82 /** Extracts an MlirAttribute from a capsule as produced from
83 * mlirPythonAttributeToCapsule. If the capsule is not of the right type, then
84 * a null attribute is returned (as checked via mlirAttributeIsNull). In such a
85 * case, the Python APIs will have already set an error. */
mlirPythonCapsuleToAttribute(PyObject * capsule)86 static inline MlirAttribute mlirPythonCapsuleToAttribute(PyObject *capsule) {
87 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_ATTRIBUTE);
88 MlirAttribute attr = {ptr};
89 return attr;
90 }
91
92 /** Creates a capsule object encapsulating the raw C-API MlirContext.
93 * The returned capsule does not extend or affect ownership of any Python
94 * objects that reference the context in any way.
95 */
mlirPythonContextToCapsule(MlirContext context)96 static inline PyObject *mlirPythonContextToCapsule(MlirContext context) {
97 return PyCapsule_New(context.ptr, MLIR_PYTHON_CAPSULE_CONTEXT, NULL);
98 }
99
100 /** Extracts a MlirContext from a capsule as produced from
101 * mlirPythonContextToCapsule. If the capsule is not of the right type, then
102 * a null context is returned (as checked via mlirContextIsNull). In such a
103 * case, the Python APIs will have already set an error. */
mlirPythonCapsuleToContext(PyObject * capsule)104 static inline MlirContext mlirPythonCapsuleToContext(PyObject *capsule) {
105 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_CONTEXT);
106 MlirContext context = {ptr};
107 return context;
108 }
109
110 /** Creates a capsule object encapsulating the raw C-API MlirLocation.
111 * The returned capsule does not extend or affect ownership of any Python
112 * objects that reference the location in any way. */
mlirPythonLocationToCapsule(MlirLocation loc)113 static inline PyObject *mlirPythonLocationToCapsule(MlirLocation loc) {
114 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(loc),
115 MLIR_PYTHON_CAPSULE_LOCATION, NULL);
116 }
117
118 /** Extracts an MlirLocation from a capsule as produced from
119 * mlirPythonLocationToCapsule. If the capsule is not of the right type, then
120 * a null module is returned (as checked via mlirLocationIsNull). In such a
121 * case, the Python APIs will have already set an error. */
mlirPythonCapsuleToLocation(PyObject * capsule)122 static inline MlirLocation mlirPythonCapsuleToLocation(PyObject *capsule) {
123 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_LOCATION);
124 MlirLocation loc = {ptr};
125 return loc;
126 }
127
128 /** Creates a capsule object encapsulating the raw C-API MlirModule.
129 * The returned capsule does not extend or affect ownership of any Python
130 * objects that reference the module in any way. */
mlirPythonModuleToCapsule(MlirModule module)131 static inline PyObject *mlirPythonModuleToCapsule(MlirModule module) {
132 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(module),
133 MLIR_PYTHON_CAPSULE_MODULE, NULL);
134 }
135
136 /** Extracts an MlirModule from a capsule as produced from
137 * mlirPythonModuleToCapsule. If the capsule is not of the right type, then
138 * a null module is returned (as checked via mlirModuleIsNull). In such a
139 * case, the Python APIs will have already set an error. */
mlirPythonCapsuleToModule(PyObject * capsule)140 static inline MlirModule mlirPythonCapsuleToModule(PyObject *capsule) {
141 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_MODULE);
142 MlirModule module = {ptr};
143 return module;
144 }
145
146 /** Creates a capsule object encapsulating the raw C-API MlirPassManager.
147 * The returned capsule does not extend or affect ownership of any Python
148 * objects that reference the module in any way. */
mlirPythonPassManagerToCapsule(MlirPassManager pm)149 static inline PyObject *mlirPythonPassManagerToCapsule(MlirPassManager pm) {
150 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(pm),
151 MLIR_PYTHON_CAPSULE_PASS_MANAGER, NULL);
152 }
153
154 /** Extracts an MlirPassManager from a capsule as produced from
155 * mlirPythonPassManagerToCapsule. If the capsule is not of the right type, then
156 * a null pass manager is returned (as checked via mlirPassManagerIsNull). */
157 static inline MlirPassManager
mlirPythonCapsuleToPassManager(PyObject * capsule)158 mlirPythonCapsuleToPassManager(PyObject *capsule) {
159 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_PASS_MANAGER);
160 MlirPassManager pm = {ptr};
161 return pm;
162 }
163
164 /** Creates a capsule object encapsulating the raw C-API MlirOperation.
165 * The returned capsule does not extend or affect ownership of any Python
166 * objects that reference the operation in any way.
167 */
mlirPythonOperationToCapsule(MlirOperation operation)168 static inline PyObject *mlirPythonOperationToCapsule(MlirOperation operation) {
169 return PyCapsule_New(operation.ptr, MLIR_PYTHON_CAPSULE_OPERATION, NULL);
170 }
171
172 /** Extracts an MlirOperations from a capsule as produced from
173 * mlirPythonOperationToCapsule. If the capsule is not of the right type, then
174 * a null type is returned (as checked via mlirOperationIsNull). In such a
175 * case, the Python APIs will have already set an error. */
mlirPythonCapsuleToOperation(PyObject * capsule)176 static inline MlirOperation mlirPythonCapsuleToOperation(PyObject *capsule) {
177 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_OPERATION);
178 MlirOperation op = {ptr};
179 return op;
180 }
181
182 /** Creates a capsule object encapsulating the raw C-API MlirType.
183 * The returned capsule does not extend or affect ownership of any Python
184 * objects that reference the type in any way.
185 */
mlirPythonTypeToCapsule(MlirType type)186 static inline PyObject *mlirPythonTypeToCapsule(MlirType type) {
187 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(type),
188 MLIR_PYTHON_CAPSULE_TYPE, NULL);
189 }
190
191 /** Extracts an MlirType from a capsule as produced from
192 * mlirPythonTypeToCapsule. If the capsule is not of the right type, then
193 * a null type is returned (as checked via mlirTypeIsNull). In such a
194 * case, the Python APIs will have already set an error. */
mlirPythonCapsuleToType(PyObject * capsule)195 static inline MlirType mlirPythonCapsuleToType(PyObject *capsule) {
196 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_TYPE);
197 MlirType type = {ptr};
198 return type;
199 }
200
201 #ifdef __cplusplus
202 }
203 #endif
204
205 #endif // MLIR_C_BINDINGS_PYTHON_INTEROP_H
206