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_EXECUTION_ENGINE \ 68 MAKE_MLIR_PYTHON_QUALNAME("execution_engine.ExecutionEngine._CAPIPtr") 69 #define MLIR_PYTHON_CAPSULE_INTEGER_SET \ 70 MAKE_MLIR_PYTHON_QUALNAME("ir.IntegerSet._CAPIPtr") 71 #define MLIR_PYTHON_CAPSULE_LOCATION \ 72 MAKE_MLIR_PYTHON_QUALNAME("ir.Location._CAPIPtr") 73 #define MLIR_PYTHON_CAPSULE_MODULE \ 74 MAKE_MLIR_PYTHON_QUALNAME("ir.Module._CAPIPtr") 75 #define MLIR_PYTHON_CAPSULE_OPERATION \ 76 MAKE_MLIR_PYTHON_QUALNAME("ir.Operation._CAPIPtr") 77 #define MLIR_PYTHON_CAPSULE_TYPE MAKE_MLIR_PYTHON_QUALNAME("ir.Type._CAPIPtr") 78 #define MLIR_PYTHON_CAPSULE_PASS_MANAGER \ 79 MAKE_MLIR_PYTHON_QUALNAME("passmanager.PassManager._CAPIPtr") 80 #define MLIR_PYTHON_CAPSULE_VALUE MAKE_MLIR_PYTHON_QUALNAME("ir.Value._CAPIPtr") 81 82 /** Attribute on MLIR Python objects that expose their C-API pointer. 83 * This will be a type-specific capsule created as per one of the helpers 84 * below. 85 * 86 * Ownership is not transferred by acquiring a capsule in this way: the 87 * validity of the pointer wrapped by the capsule will be bounded by the 88 * lifetime of the Python object that produced it. Only the name and pointer 89 * of the capsule are set. The caller is free to set a destructor and context 90 * as needed to manage anything further. */ 91 #define MLIR_PYTHON_CAPI_PTR_ATTR "_CAPIPtr" 92 93 /** Attribute on MLIR Python objects that exposes a factory function for 94 * constructing the corresponding Python object from a type-specific 95 * capsule wrapping the C-API pointer. The signature of the function is: 96 * def _CAPICreate(capsule) -> object 97 * Calling such a function implies a transfer of ownership of the object the 98 * capsule wraps: after such a call, the capsule should be considered invalid, 99 * and its wrapped pointer must not be destroyed. 100 * 101 * Only a very small number of Python objects can be created in such a fashion 102 * (i.e. top-level types such as Context where the lifetime can be cleanly 103 * delineated). */ 104 #define MLIR_PYTHON_CAPI_FACTORY_ATTR "_CAPICreate" 105 106 /// Gets a void* from a wrapped struct. Needed because const cast is different 107 /// between C/C++. 108 #ifdef __cplusplus 109 #define MLIR_PYTHON_GET_WRAPPED_POINTER(object) \ 110 (const_cast<void *>((object).ptr)) 111 #else 112 #define MLIR_PYTHON_GET_WRAPPED_POINTER(object) (void *)(object.ptr) 113 #endif 114 115 #ifdef __cplusplus 116 extern "C" { 117 #endif 118 119 /** Creates a capsule object encapsulating the raw C-API MlirAffineExpr. The 120 * returned capsule does not extend or affect ownership of any Python objects 121 * that reference the expression in any way. 122 */ 123 static inline PyObject *mlirPythonAffineExprToCapsule(MlirAffineExpr expr) { 124 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(expr), 125 MLIR_PYTHON_CAPSULE_AFFINE_EXPR, NULL); 126 } 127 128 /** Extracts an MlirAffineExpr from a capsule as produced from 129 * mlirPythonAffineExprToCapsule. If the capsule is not of the right type, then 130 * a null expression is returned (as checked via mlirAffineExprIsNull). In such 131 * a case, the Python APIs will have already set an error. */ 132 static inline MlirAffineExpr mlirPythonCapsuleToAffineExpr(PyObject *capsule) { 133 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_AFFINE_EXPR); 134 MlirAffineExpr expr = {ptr}; 135 return expr; 136 } 137 138 /** Creates a capsule object encapsulating the raw C-API MlirAttribute. 139 * The returned capsule does not extend or affect ownership of any Python 140 * objects that reference the attribute in any way. 141 */ 142 static inline PyObject *mlirPythonAttributeToCapsule(MlirAttribute attribute) { 143 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(attribute), 144 MLIR_PYTHON_CAPSULE_ATTRIBUTE, NULL); 145 } 146 147 /** Extracts an MlirAttribute from a capsule as produced from 148 * mlirPythonAttributeToCapsule. If the capsule is not of the right type, then 149 * a null attribute is returned (as checked via mlirAttributeIsNull). In such a 150 * case, the Python APIs will have already set an error. */ 151 static inline MlirAttribute mlirPythonCapsuleToAttribute(PyObject *capsule) { 152 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_ATTRIBUTE); 153 MlirAttribute attr = {ptr}; 154 return attr; 155 } 156 157 /** Creates a capsule object encapsulating the raw C-API MlirContext. 158 * The returned capsule does not extend or affect ownership of any Python 159 * objects that reference the context in any way. 160 */ 161 static inline PyObject *mlirPythonContextToCapsule(MlirContext context) { 162 return PyCapsule_New(context.ptr, MLIR_PYTHON_CAPSULE_CONTEXT, NULL); 163 } 164 165 /** Extracts a MlirContext from a capsule as produced from 166 * mlirPythonContextToCapsule. If the capsule is not of the right type, then 167 * a null context is returned (as checked via mlirContextIsNull). In such a 168 * case, the Python APIs will have already set an error. */ 169 static inline MlirContext mlirPythonCapsuleToContext(PyObject *capsule) { 170 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_CONTEXT); 171 MlirContext context = {ptr}; 172 return context; 173 } 174 175 /** Creates a capsule object encapsulating the raw C-API MlirLocation. 176 * The returned capsule does not extend or affect ownership of any Python 177 * objects that reference the location in any way. */ 178 static inline PyObject *mlirPythonLocationToCapsule(MlirLocation loc) { 179 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(loc), 180 MLIR_PYTHON_CAPSULE_LOCATION, NULL); 181 } 182 183 /** Extracts an MlirLocation from a capsule as produced from 184 * mlirPythonLocationToCapsule. If the capsule is not of the right type, then 185 * a null module is returned (as checked via mlirLocationIsNull). In such a 186 * case, the Python APIs will have already set an error. */ 187 static inline MlirLocation mlirPythonCapsuleToLocation(PyObject *capsule) { 188 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_LOCATION); 189 MlirLocation loc = {ptr}; 190 return loc; 191 } 192 193 /** Creates a capsule object encapsulating the raw C-API MlirModule. 194 * The returned capsule does not extend or affect ownership of any Python 195 * objects that reference the module in any way. */ 196 static inline PyObject *mlirPythonModuleToCapsule(MlirModule module) { 197 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(module), 198 MLIR_PYTHON_CAPSULE_MODULE, NULL); 199 } 200 201 /** Extracts an MlirModule from a capsule as produced from 202 * mlirPythonModuleToCapsule. If the capsule is not of the right type, then 203 * a null module is returned (as checked via mlirModuleIsNull). In such a 204 * case, the Python APIs will have already set an error. */ 205 static inline MlirModule mlirPythonCapsuleToModule(PyObject *capsule) { 206 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_MODULE); 207 MlirModule module = {ptr}; 208 return module; 209 } 210 211 /** Creates a capsule object encapsulating the raw C-API MlirPassManager. 212 * The returned capsule does not extend or affect ownership of any Python 213 * objects that reference the module in any way. */ 214 static inline PyObject *mlirPythonPassManagerToCapsule(MlirPassManager pm) { 215 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(pm), 216 MLIR_PYTHON_CAPSULE_PASS_MANAGER, NULL); 217 } 218 219 /** Extracts an MlirPassManager from a capsule as produced from 220 * mlirPythonPassManagerToCapsule. If the capsule is not of the right type, then 221 * a null pass manager is returned (as checked via mlirPassManagerIsNull). */ 222 static inline MlirPassManager 223 mlirPythonCapsuleToPassManager(PyObject *capsule) { 224 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_PASS_MANAGER); 225 MlirPassManager pm = {ptr}; 226 return pm; 227 } 228 229 /** Creates a capsule object encapsulating the raw C-API MlirOperation. 230 * The returned capsule does not extend or affect ownership of any Python 231 * objects that reference the operation in any way. 232 */ 233 static inline PyObject *mlirPythonOperationToCapsule(MlirOperation operation) { 234 return PyCapsule_New(operation.ptr, MLIR_PYTHON_CAPSULE_OPERATION, NULL); 235 } 236 237 /** Extracts an MlirOperations from a capsule as produced from 238 * mlirPythonOperationToCapsule. If the capsule is not of the right type, then 239 * a null type is returned (as checked via mlirOperationIsNull). In such a 240 * case, the Python APIs will have already set an error. */ 241 static inline MlirOperation mlirPythonCapsuleToOperation(PyObject *capsule) { 242 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_OPERATION); 243 MlirOperation op = {ptr}; 244 return op; 245 } 246 247 /** Creates a capsule object encapsulating the raw C-API MlirType. 248 * The returned capsule does not extend or affect ownership of any Python 249 * objects that reference the type in any way. 250 */ 251 static inline PyObject *mlirPythonTypeToCapsule(MlirType type) { 252 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(type), 253 MLIR_PYTHON_CAPSULE_TYPE, NULL); 254 } 255 256 /** Extracts an MlirType from a capsule as produced from 257 * mlirPythonTypeToCapsule. If the capsule is not of the right type, then 258 * a null type is returned (as checked via mlirTypeIsNull). In such a 259 * case, the Python APIs will have already set an error. */ 260 static inline MlirType mlirPythonCapsuleToType(PyObject *capsule) { 261 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_TYPE); 262 MlirType type = {ptr}; 263 return type; 264 } 265 266 /** Creates a capsule object encapsulating the raw C-API MlirAffineMap. 267 * The returned capsule does not extend or affect ownership of any Python 268 * objects that reference the type in any way. 269 */ 270 static inline PyObject *mlirPythonAffineMapToCapsule(MlirAffineMap affineMap) { 271 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(affineMap), 272 MLIR_PYTHON_CAPSULE_AFFINE_MAP, NULL); 273 } 274 275 /** Extracts an MlirAffineMap from a capsule as produced from 276 * mlirPythonAffineMapToCapsule. If the capsule is not of the right type, then 277 * a null type is returned (as checked via mlirAffineMapIsNull). In such a 278 * case, the Python APIs will have already set an error. */ 279 static inline MlirAffineMap mlirPythonCapsuleToAffineMap(PyObject *capsule) { 280 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_AFFINE_MAP); 281 MlirAffineMap affineMap = {ptr}; 282 return affineMap; 283 } 284 285 /** Creates a capsule object encapsulating the raw C-API MlirIntegerSet. 286 * The returned capsule does not extend or affect ownership of any Python 287 * objects that reference the set in any way. */ 288 static inline PyObject * 289 mlirPythonIntegerSetToCapsule(MlirIntegerSet integerSet) { 290 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(integerSet), 291 MLIR_PYTHON_CAPSULE_INTEGER_SET, NULL); 292 } 293 294 /** Extracts an MlirIntegerSet from a capsule as produced from 295 * mlirPythonIntegerSetToCapsule. If the capsule is not of the right type, then 296 * a null set is returned (as checked via mlirIntegerSetIsNull). In such a 297 * case, the Python APIs will have already set an error. */ 298 static inline MlirIntegerSet mlirPythonCapsuleToIntegerSet(PyObject *capsule) { 299 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_INTEGER_SET); 300 MlirIntegerSet integerSet = {ptr}; 301 return integerSet; 302 } 303 304 /** Creates a capsule object encapsulating the raw C-API MlirExecutionEngine. 305 * The returned capsule does not extend or affect ownership of any Python 306 * objects that reference the set in any way. */ 307 static inline PyObject * 308 mlirPythonExecutionEngineToCapsule(MlirExecutionEngine jit) { 309 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(jit), 310 MLIR_PYTHON_CAPSULE_EXECUTION_ENGINE, NULL); 311 } 312 313 /** Extracts an MlirExecutionEngine from a capsule as produced from 314 * mlirPythonIntegerSetToCapsule. If the capsule is not of the right type, then 315 * a null set is returned (as checked via mlirExecutionEngineIsNull). In such a 316 * case, the Python APIs will have already set an error. */ 317 static inline MlirExecutionEngine 318 mlirPythonCapsuleToExecutionEngine(PyObject *capsule) { 319 void *ptr = 320 PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_EXECUTION_ENGINE); 321 MlirExecutionEngine jit = {ptr}; 322 return jit; 323 } 324 325 /** Creates a capsule object encapsulating the raw C-API MlirValue. 326 * The returned capsule does not extend or affect ownership of any Python 327 * objects that reference the operation in any way. 328 */ 329 static inline PyObject *mlirPythonValueToCapsule(MlirValue value) { 330 return PyCapsule_New(MLIR_PYTHON_GET_WRAPPED_POINTER(value), 331 MLIR_PYTHON_CAPSULE_VALUE, NULL); 332 } 333 334 /** Extracts an MlirValue from a capsule as produced from 335 * mlirPythonValueToCapsule. If the capsule is not of the right type, then a 336 * null type is returned (as checked via mlirValueIsNull). In such a case, the 337 * Python APIs will have already set an error. */ 338 static inline MlirValue mlirPythonCapsuleToValue(PyObject *capsule) { 339 void *ptr = PyCapsule_GetPointer(capsule, MLIR_PYTHON_CAPSULE_VALUE); 340 MlirValue value = {ptr}; 341 return value; 342 } 343 344 #ifdef __cplusplus 345 } 346 #endif 347 348 #endif // MLIR_C_BINDINGS_PYTHON_INTEROP_H 349