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 */ 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. */ 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 */ 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. */ 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 */ 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. */ 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 * 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 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. */ 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. */ 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. */ 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. */ 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. */ 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 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 */ 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. */ 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 */ 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. */ 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 */ 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. */ 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 * 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. */ 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 * 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 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 */ 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. */ 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