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