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) const_cast<void *>(object.ptr) 100 #else 101 #define MLIR_PYTHON_GET_WRAPPED_POINTER(object) (void *)(object.ptr) 102 #endif 103 104 #ifdef __cplusplus 105 extern "C" { 106 #endif 107 108 /** Creates a capsule object encapsulating the raw C-API MlirAffineExpr. The 109 * returned capsule does not extend or affect ownership of any Python objects 110 * that reference the expression in any way. 111 */ 112 static inline PyObject *mlirPythonAffineExprToCapsule(MlirAffineExpr expr) { 113 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(expr), 114 MLIR_PYTHON_CAPSULE_AFFINE_EXPR, NULL); 115 } 116 117 /** Extracts an MlirAffineExpr from a capsule as produced from 118 * mlirPythonAffineExprToCapsule. If the capsule is not of the right type, then 119 * a null expression is returned (as checked via mlirAffineExprIsNull). In such 120 * a case, the Python APIs will have already set an error. */ 121 static inline MlirAffineExpr mlirPythonCapsuleToAffineExpr(PyObject *capsule) { 122 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_AFFINE_EXPR); 123 MlirAffineExpr expr = {ptr}; 124 return expr; 125 } 126 127 /** Creates a capsule object encapsulating the raw C-API MlirAttribute. 128 * The returned capsule does not extend or affect ownership of any Python 129 * objects that reference the attribute in any way. 130 */ 131 static inline PyObject *mlirPythonAttributeToCapsule(MlirAttribute attribute) { 132 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(attribute), 133 MLIR_PYTHON_CAPSULE_ATTRIBUTE, NULL); 134 } 135 136 /** Extracts an MlirAttribute from a capsule as produced from 137 * mlirPythonAttributeToCapsule. If the capsule is not of the right type, then 138 * a null attribute is returned (as checked via mlirAttributeIsNull). In such a 139 * case, the Python APIs will have already set an error. */ 140 static inline MlirAttribute mlirPythonCapsuleToAttribute(PyObject *capsule) { 141 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_ATTRIBUTE); 142 MlirAttribute attr = {ptr}; 143 return attr; 144 } 145 146 /** Creates a capsule object encapsulating the raw C-API MlirContext. 147 * The returned capsule does not extend or affect ownership of any Python 148 * objects that reference the context in any way. 149 */ 150 static inline PyObject *mlirPythonContextToCapsule(MlirContext context) { 151 return PyCapsule_New(context.ptr, MLIR_PYTHON_CAPSULE_CONTEXT, NULL); 152 } 153 154 /** Extracts a MlirContext from a capsule as produced from 155 * mlirPythonContextToCapsule. If the capsule is not of the right type, then 156 * a null context is returned (as checked via mlirContextIsNull). In such a 157 * case, the Python APIs will have already set an error. */ 158 static inline MlirContext mlirPythonCapsuleToContext(PyObject *capsule) { 159 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_CONTEXT); 160 MlirContext context = {ptr}; 161 return context; 162 } 163 164 /** Creates a capsule object encapsulating the raw C-API MlirLocation. 165 * The returned capsule does not extend or affect ownership of any Python 166 * objects that reference the location in any way. */ 167 static inline PyObject *mlirPythonLocationToCapsule(MlirLocation loc) { 168 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(loc), 169 MLIR_PYTHON_CAPSULE_LOCATION, NULL); 170 } 171 172 /** Extracts an MlirLocation from a capsule as produced from 173 * mlirPythonLocationToCapsule. If the capsule is not of the right type, then 174 * a null module is returned (as checked via mlirLocationIsNull). In such a 175 * case, the Python APIs will have already set an error. */ 176 static inline MlirLocation mlirPythonCapsuleToLocation(PyObject *capsule) { 177 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_LOCATION); 178 MlirLocation loc = {ptr}; 179 return loc; 180 } 181 182 /** Creates a capsule object encapsulating the raw C-API MlirModule. 183 * The returned capsule does not extend or affect ownership of any Python 184 * objects that reference the module in any way. */ 185 static inline PyObject *mlirPythonModuleToCapsule(MlirModule module) { 186 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(module), 187 MLIR_PYTHON_CAPSULE_MODULE, NULL); 188 } 189 190 /** Extracts an MlirModule from a capsule as produced from 191 * mlirPythonModuleToCapsule. If the capsule is not of the right type, then 192 * a null module is returned (as checked via mlirModuleIsNull). In such a 193 * case, the Python APIs will have already set an error. */ 194 static inline MlirModule mlirPythonCapsuleToModule(PyObject *capsule) { 195 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_MODULE); 196 MlirModule module = {ptr}; 197 return module; 198 } 199 200 /** Creates a capsule object encapsulating the raw C-API MlirPassManager. 201 * The returned capsule does not extend or affect ownership of any Python 202 * objects that reference the module in any way. */ 203 static inline PyObject *mlirPythonPassManagerToCapsule(MlirPassManager pm) { 204 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(pm), 205 MLIR_PYTHON_CAPSULE_PASS_MANAGER, NULL); 206 } 207 208 /** Extracts an MlirPassManager from a capsule as produced from 209 * mlirPythonPassManagerToCapsule. If the capsule is not of the right type, then 210 * a null pass manager is returned (as checked via mlirPassManagerIsNull). */ 211 static inline MlirPassManager 212 mlirPythonCapsuleToPassManager(PyObject *capsule) { 213 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_PASS_MANAGER); 214 MlirPassManager pm = {ptr}; 215 return pm; 216 } 217 218 /** Creates a capsule object encapsulating the raw C-API MlirOperation. 219 * The returned capsule does not extend or affect ownership of any Python 220 * objects that reference the operation in any way. 221 */ 222 static inline PyObject *mlirPythonOperationToCapsule(MlirOperation operation) { 223 return PyCapsule_New(operation.ptr, MLIR_PYTHON_CAPSULE_OPERATION, NULL); 224 } 225 226 /** Extracts an MlirOperations from a capsule as produced from 227 * mlirPythonOperationToCapsule. If the capsule is not of the right type, then 228 * a null type is returned (as checked via mlirOperationIsNull). In such a 229 * case, the Python APIs will have already set an error. */ 230 static inline MlirOperation mlirPythonCapsuleToOperation(PyObject *capsule) { 231 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_OPERATION); 232 MlirOperation op = {ptr}; 233 return op; 234 } 235 236 /** Creates a capsule object encapsulating the raw C-API MlirType. 237 * The returned capsule does not extend or affect ownership of any Python 238 * objects that reference the type in any way. 239 */ 240 static inline PyObject *mlirPythonTypeToCapsule(MlirType type) { 241 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(type), 242 MLIR_PYTHON_CAPSULE_TYPE, NULL); 243 } 244 245 /** Extracts an MlirType from a capsule as produced from 246 * mlirPythonTypeToCapsule. If the capsule is not of the right type, then 247 * a null type is returned (as checked via mlirTypeIsNull). In such a 248 * case, the Python APIs will have already set an error. */ 249 static inline MlirType mlirPythonCapsuleToType(PyObject *capsule) { 250 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_TYPE); 251 MlirType type = {ptr}; 252 return type; 253 } 254 255 /** Creates a capsule object encapsulating the raw C-API MlirAffineMap. 256 * The returned capsule does not extend or affect ownership of any Python 257 * objects that reference the type in any way. 258 */ 259 static inline PyObject *mlirPythonAffineMapToCapsule(MlirAffineMap affineMap) { 260 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(affineMap), 261 MLIR_PYTHON_CAPSULE_AFFINE_MAP, NULL); 262 } 263 264 /** Extracts an MlirAffineMap from a capsule as produced from 265 * mlirPythonAffineMapToCapsule. If the capsule is not of the right type, then 266 * a null type is returned (as checked via mlirAffineMapIsNull). In such a 267 * case, the Python APIs will have already set an error. */ 268 static inline MlirAffineMap mlirPythonCapsuleToAffineMap(PyObject *capsule) { 269 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_AFFINE_MAP); 270 MlirAffineMap affineMap = {ptr}; 271 return affineMap; 272 } 273 274 /** Creates a capsule object encapsulating the raw C-API MlirIntegerSet. 275 * The returned capsule does not extend or affect ownership of any Python 276 * objects that reference the set in any way. */ 277 static inline PyObject * 278 mlirPythonIntegerSetToCapsule(MlirIntegerSet integerSet) { 279 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(integerSet), 280 MLIR_PYTHON_CAPSULE_INTEGER_SET, NULL); 281 } 282 283 /** Extracts an MlirIntegerSet from a capsule as produced from 284 * mlirPythonIntegerSetToCapsule. If the capsule is not of the right type, then 285 * a null set is returned (as checked via mlirIntegerSetIsNull). In such a 286 * case, the Python APIs will have already set an error. */ 287 static inline MlirIntegerSet mlirPythonCapsuleToIntegerSet(PyObject *capsule) { 288 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_INTEGER_SET); 289 MlirIntegerSet integerSet = {ptr}; 290 return integerSet; 291 } 292 293 /** Creates a capsule object encapsulating the raw C-API MlirExecutionEngine. 294 * The returned capsule does not extend or affect ownership of any Python 295 * objects that reference the set in any way. */ 296 static inline PyObject * 297 mlirPythonExecutionEngineToCapsule(MlirExecutionEngine jit) { 298 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(jit), 299 MLIR_PYTHON_CAPSULE_EXECUTION_ENGINE, NULL); 300 } 301 302 /** Extracts an MlirExecutionEngine from a capsule as produced from 303 * mlirPythonIntegerSetToCapsule. If the capsule is not of the right type, then 304 * a null set is returned (as checked via mlirExecutionEngineIsNull). In such a 305 * case, the Python APIs will have already set an error. */ 306 static inline MlirExecutionEngine 307 mlirPythonCapsuleToExecutionEngine(PyObject *capsule) { 308 void *ptr = 309 PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_EXECUTION_ENGINE); 310 MlirExecutionEngine jit = {ptr}; 311 return jit; 312 } 313 314 /** Creates a capsule object encapsulating the raw C-API MlirValue. 315 * The returned capsule does not extend or affect ownership of any Python 316 * objects that reference the operation in any way. 317 */ 318 static inline PyObject *mlirPythonValueToCapsule(MlirValue value) { 319 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(value), 320 MLIR_PYTHON_CAPSULE_VALUE, NULL); 321 } 322 323 /** Extracts an MlirValue from a capsule as produced from 324 * mlirPythonValueToCapsule. If the capsule is not of the right type, then a 325 * null type is returned (as checked via mlirValueIsNull). In such a case, the 326 * Python APIs will have already set an error. */ 327 static inline MlirValue mlirPythonCapsuleToValue(PyObject *capsule) { 328 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_VALUE); 329 MlirValue value = {ptr}; 330 return value; 331 } 332 333 #ifdef __cplusplus 334 } 335 #endif 336 337 #endif // MLIR_C_BINDINGS_PYTHON_INTEROP_H 338