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/AffineExpr.h"
27 #include "mlir-c/AffineMap.h"
28 #include "mlir-c/ExecutionEngine.h"
29 #include "mlir-c/IR.h"
30 #include "mlir-c/IntegerSet.h"
31 #include "mlir-c/Pass.h"
32 
33 #define MLIR_PYTHON_CAPSULE_AFFINE_EXPR "mlir.ir.AffineExpr._CAPIPtr"
34 #define MLIR_PYTHON_CAPSULE_AFFINE_MAP "mlir.ir.AffineMap._CAPIPtr"
35 #define MLIR_PYTHON_CAPSULE_ATTRIBUTE "mlir.ir.Attribute._CAPIPtr"
36 #define MLIR_PYTHON_CAPSULE_CONTEXT "mlir.ir.Context._CAPIPtr"
37 #define MLIR_PYTHON_CAPSULE_EXECUTION_ENGINE                                   \
38   "mlir.execution_engine.ExecutionEngine._CAPIPtr"
39 #define MLIR_PYTHON_CAPSULE_INTEGER_SET "mlir.ir.IntegerSet._CAPIPtr"
40 #define MLIR_PYTHON_CAPSULE_LOCATION "mlir.ir.Location._CAPIPtr"
41 #define MLIR_PYTHON_CAPSULE_MODULE "mlir.ir.Module._CAPIPtr"
42 #define MLIR_PYTHON_CAPSULE_OPERATION "mlir.ir.Operation._CAPIPtr"
43 #define MLIR_PYTHON_CAPSULE_TYPE "mlir.ir.Type._CAPIPtr"
44 #define MLIR_PYTHON_CAPSULE_PASS_MANAGER "mlir.passmanager.PassManager._CAPIPtr"
45 
46 /** Attribute on MLIR Python objects that expose their C-API pointer.
47  * This will be a type-specific capsule created as per one of the helpers
48  * below.
49  *
50  * Ownership is not transferred by acquiring a capsule in this way: the
51  * validity of the pointer wrapped by the capsule will be bounded by the
52  * lifetime of the Python object that produced it. Only the name and pointer
53  * of the capsule are set. The caller is free to set a destructor and context
54  * as needed to manage anything further. */
55 #define MLIR_PYTHON_CAPI_PTR_ATTR "_CAPIPtr"
56 
57 /** Attribute on MLIR Python objects that exposes a factory function for
58  * constructing the corresponding Python object from a type-specific
59  * capsule wrapping the C-API pointer. The signature of the function is:
60  *   def _CAPICreate(capsule) -> object
61  * Calling such a function implies a transfer of ownership of the object the
62  * capsule wraps: after such a call, the capsule should be considered invalid,
63  * and its wrapped pointer must not be destroyed.
64  *
65  * Only a very small number of Python objects can be created in such a fashion
66  * (i.e. top-level types such as Context where the lifetime can be cleanly
67  * delineated). */
68 #define MLIR_PYTHON_CAPI_FACTORY_ATTR "_CAPICreate"
69 
70 /// Gets a void* from a wrapped struct. Needed because const cast is different
71 /// between C/C++.
72 #ifdef __cplusplus
73 #define MLIR_PYTHON_GET_WRAPPED_POINTER(object) const_cast<void *>(object.ptr)
74 #else
75 #define MLIR_PYTHON_GET_WRAPPED_POINTER(object) (void *)(object.ptr)
76 #endif
77 
78 #ifdef __cplusplus
79 extern "C" {
80 #endif
81 
82 /** Creates a capsule object encapsulating the raw C-API MlirAffineExpr. The
83  * returned capsule does not extend or affect ownership of any Python objects
84  * that reference the expression in any way.
85  */
86 static inline PyObject *mlirPythonAffineExprToCapsule(MlirAffineExpr expr) {
87   return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(expr),
88                        MLIR_PYTHON_CAPSULE_AFFINE_EXPR, NULL);
89 }
90 
91 /** Extracts an MlirAffineExpr from a capsule as produced from
92  * mlirPythonAffineExprToCapsule. If the capsule is not of the right type, then
93  * a null expression is returned (as checked via mlirAffineExprIsNull). In such
94  * a case, the Python APIs will have already set an error. */
95 static inline MlirAffineExpr mlirPythonCapsuleToAffineExpr(PyObject *capsule) {
96   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_AFFINE_EXPR);
97   MlirAffineExpr expr = {ptr};
98   return expr;
99 }
100 
101 /** Creates a capsule object encapsulating the raw C-API MlirAttribute.
102  * The returned capsule does not extend or affect ownership of any Python
103  * objects that reference the attribute in any way.
104  */
105 static inline PyObject *mlirPythonAttributeToCapsule(MlirAttribute attribute) {
106   return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(attribute),
107                        MLIR_PYTHON_CAPSULE_ATTRIBUTE, NULL);
108 }
109 
110 /** Extracts an MlirAttribute from a capsule as produced from
111  * mlirPythonAttributeToCapsule. If the capsule is not of the right type, then
112  * a null attribute is returned (as checked via mlirAttributeIsNull). In such a
113  * case, the Python APIs will have already set an error. */
114 static inline MlirAttribute mlirPythonCapsuleToAttribute(PyObject *capsule) {
115   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_ATTRIBUTE);
116   MlirAttribute attr = {ptr};
117   return attr;
118 }
119 
120 /** Creates a capsule object encapsulating the raw C-API MlirContext.
121  * The returned capsule does not extend or affect ownership of any Python
122  * objects that reference the context in any way.
123  */
124 static inline PyObject *mlirPythonContextToCapsule(MlirContext context) {
125   return PyCapsule_New(context.ptr, MLIR_PYTHON_CAPSULE_CONTEXT, NULL);
126 }
127 
128 /** Extracts a MlirContext from a capsule as produced from
129  * mlirPythonContextToCapsule. If the capsule is not of the right type, then
130  * a null context is returned (as checked via mlirContextIsNull). In such a
131  * case, the Python APIs will have already set an error. */
132 static inline MlirContext mlirPythonCapsuleToContext(PyObject *capsule) {
133   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_CONTEXT);
134   MlirContext context = {ptr};
135   return context;
136 }
137 
138 /** Creates a capsule object encapsulating the raw C-API MlirLocation.
139  * The returned capsule does not extend or affect ownership of any Python
140  * objects that reference the location in any way. */
141 static inline PyObject *mlirPythonLocationToCapsule(MlirLocation loc) {
142   return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(loc),
143                        MLIR_PYTHON_CAPSULE_LOCATION, NULL);
144 }
145 
146 /** Extracts an MlirLocation from a capsule as produced from
147  * mlirPythonLocationToCapsule. If the capsule is not of the right type, then
148  * a null module is returned (as checked via mlirLocationIsNull). In such a
149  * case, the Python APIs will have already set an error. */
150 static inline MlirLocation mlirPythonCapsuleToLocation(PyObject *capsule) {
151   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_LOCATION);
152   MlirLocation loc = {ptr};
153   return loc;
154 }
155 
156 /** Creates a capsule object encapsulating the raw C-API MlirModule.
157  * The returned capsule does not extend or affect ownership of any Python
158  * objects that reference the module in any way. */
159 static inline PyObject *mlirPythonModuleToCapsule(MlirModule module) {
160   return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(module),
161                        MLIR_PYTHON_CAPSULE_MODULE, NULL);
162 }
163 
164 /** Extracts an MlirModule from a capsule as produced from
165  * mlirPythonModuleToCapsule. If the capsule is not of the right type, then
166  * a null module is returned (as checked via mlirModuleIsNull). In such a
167  * case, the Python APIs will have already set an error. */
168 static inline MlirModule mlirPythonCapsuleToModule(PyObject *capsule) {
169   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_MODULE);
170   MlirModule module = {ptr};
171   return module;
172 }
173 
174 /** Creates a capsule object encapsulating the raw C-API MlirPassManager.
175  * The returned capsule does not extend or affect ownership of any Python
176  * objects that reference the module in any way. */
177 static inline PyObject *mlirPythonPassManagerToCapsule(MlirPassManager pm) {
178   return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(pm),
179                        MLIR_PYTHON_CAPSULE_PASS_MANAGER, NULL);
180 }
181 
182 /** Extracts an MlirPassManager from a capsule as produced from
183  * mlirPythonPassManagerToCapsule. If the capsule is not of the right type, then
184  * a null pass manager is returned (as checked via mlirPassManagerIsNull). */
185 static inline MlirPassManager
186 mlirPythonCapsuleToPassManager(PyObject *capsule) {
187   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_PASS_MANAGER);
188   MlirPassManager pm = {ptr};
189   return pm;
190 }
191 
192 /** Creates a capsule object encapsulating the raw C-API MlirOperation.
193  * The returned capsule does not extend or affect ownership of any Python
194  * objects that reference the operation in any way.
195  */
196 static inline PyObject *mlirPythonOperationToCapsule(MlirOperation operation) {
197   return PyCapsule_New(operation.ptr, MLIR_PYTHON_CAPSULE_OPERATION, NULL);
198 }
199 
200 /** Extracts an MlirOperations from a capsule as produced from
201  * mlirPythonOperationToCapsule. If the capsule is not of the right type, then
202  * a null type is returned (as checked via mlirOperationIsNull). In such a
203  * case, the Python APIs will have already set an error. */
204 static inline MlirOperation mlirPythonCapsuleToOperation(PyObject *capsule) {
205   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_OPERATION);
206   MlirOperation op = {ptr};
207   return op;
208 }
209 
210 /** Creates a capsule object encapsulating the raw C-API MlirType.
211  * The returned capsule does not extend or affect ownership of any Python
212  * objects that reference the type in any way.
213  */
214 static inline PyObject *mlirPythonTypeToCapsule(MlirType type) {
215   return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(type),
216                        MLIR_PYTHON_CAPSULE_TYPE, NULL);
217 }
218 
219 /** Extracts an MlirType from a capsule as produced from
220  * mlirPythonTypeToCapsule. If the capsule is not of the right type, then
221  * a null type is returned (as checked via mlirTypeIsNull). In such a
222  * case, the Python APIs will have already set an error. */
223 static inline MlirType mlirPythonCapsuleToType(PyObject *capsule) {
224   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_TYPE);
225   MlirType type = {ptr};
226   return type;
227 }
228 
229 /** Creates a capsule object encapsulating the raw C-API MlirAffineMap.
230  * The returned capsule does not extend or affect ownership of any Python
231  * objects that reference the type in any way.
232  */
233 static inline PyObject *mlirPythonAffineMapToCapsule(MlirAffineMap affineMap) {
234   return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(affineMap),
235                        MLIR_PYTHON_CAPSULE_AFFINE_MAP, NULL);
236 }
237 
238 /** Extracts an MlirAffineMap from a capsule as produced from
239  * mlirPythonAffineMapToCapsule. If the capsule is not of the right type, then
240  * a null type is returned (as checked via mlirAffineMapIsNull). In such a
241  * case, the Python APIs will have already set an error. */
242 static inline MlirAffineMap mlirPythonCapsuleToAffineMap(PyObject *capsule) {
243   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_AFFINE_MAP);
244   MlirAffineMap affineMap = {ptr};
245   return affineMap;
246 }
247 
248 /** Creates a capsule object encapsulating the raw C-API MlirIntegerSet.
249  * The returned capsule does not extend or affect ownership of any Python
250  * objects that reference the set in any way. */
251 static inline PyObject *
252 mlirPythonIntegerSetToCapsule(MlirIntegerSet integerSet) {
253   return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(integerSet),
254                        MLIR_PYTHON_CAPSULE_INTEGER_SET, NULL);
255 }
256 
257 /** Extracts an MlirIntegerSet from a capsule as produced from
258  * mlirPythonIntegerSetToCapsule. If the capsule is not of the right type, then
259  * a null set is returned (as checked via mlirIntegerSetIsNull). In such a
260  * case, the Python APIs will have already set an error. */
261 static inline MlirIntegerSet mlirPythonCapsuleToIntegerSet(PyObject *capsule) {
262   void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_INTEGER_SET);
263   MlirIntegerSet integerSet = {ptr};
264   return integerSet;
265 }
266 
267 /** Creates a capsule object encapsulating the raw C-API MlirExecutionEngine.
268  * The returned capsule does not extend or affect ownership of any Python
269  * objects that reference the set in any way. */
270 static inline PyObject *
271 mlirPythonExecutionEngineToCapsule(MlirExecutionEngine jit) {
272   return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(jit),
273                        MLIR_PYTHON_CAPSULE_EXECUTION_ENGINE, NULL);
274 }
275 
276 /** Extracts an MlirExecutionEngine from a capsule as produced from
277  * mlirPythonIntegerSetToCapsule. If the capsule is not of the right type, then
278  * a null set is returned (as checked via mlirExecutionEngineIsNull). In such a
279  * case, the Python APIs will have already set an error. */
280 static inline MlirExecutionEngine
281 mlirPythonCapsuleToExecutionEngine(PyObject *capsule) {
282   void *ptr =
283       PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_EXECUTION_ENGINE);
284   MlirExecutionEngine jit = {ptr};
285   return jit;
286 }
287 
288 #ifdef __cplusplus
289 }
290 #endif
291 
292 #endif // MLIR_C_BINDINGS_PYTHON_INTEROP_H
293