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