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