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