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