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