1 //===- IRModules.h - IR Submodules of pybind module -----------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef MLIR_BINDINGS_PYTHON_IRMODULES_H 10 #define MLIR_BINDINGS_PYTHON_IRMODULES_H 11 12 #include <vector> 13 14 #include "PybindUtils.h" 15 16 #include "mlir-c/AffineExpr.h" 17 #include "mlir-c/AffineMap.h" 18 #include "mlir-c/IR.h" 19 #include "mlir-c/IntegerSet.h" 20 #include "llvm/ADT/DenseMap.h" 21 22 namespace mlir { 23 namespace python { 24 25 class PyBlock; 26 class PyInsertionPoint; 27 class PyLocation; 28 class DefaultingPyLocation; 29 class PyMlirContext; 30 class DefaultingPyMlirContext; 31 class PyModule; 32 class PyOperation; 33 class PyType; 34 class PyValue; 35 36 /// Template for a reference to a concrete type which captures a python 37 /// reference to its underlying python object. 38 template <typename T> 39 class PyObjectRef { 40 public: 41 PyObjectRef(T *referrent, pybind11::object object) 42 : referrent(referrent), object(std::move(object)) { 43 assert(this->referrent && 44 "cannot construct PyObjectRef with null referrent"); 45 assert(this->object && "cannot construct PyObjectRef with null object"); 46 } 47 PyObjectRef(PyObjectRef &&other) 48 : referrent(other.referrent), object(std::move(other.object)) { 49 other.referrent = nullptr; 50 assert(!other.object); 51 } 52 PyObjectRef(const PyObjectRef &other) 53 : referrent(other.referrent), object(other.object /* copies */) {} 54 ~PyObjectRef() {} 55 56 int getRefCount() { 57 if (!object) 58 return 0; 59 return object.ref_count(); 60 } 61 62 /// Releases the object held by this instance, returning it. 63 /// This is the proper thing to return from a function that wants to return 64 /// the reference. Note that this does not work from initializers. 65 pybind11::object releaseObject() { 66 assert(referrent && object); 67 referrent = nullptr; 68 auto stolen = std::move(object); 69 return stolen; 70 } 71 72 T *get() { return referrent; } 73 T *operator->() { 74 assert(referrent && object); 75 return referrent; 76 } 77 pybind11::object getObject() { 78 assert(referrent && object); 79 return object; 80 } 81 operator bool() const { return referrent && object; } 82 83 private: 84 T *referrent; 85 pybind11::object object; 86 }; 87 88 /// Tracks an entry in the thread context stack. New entries are pushed onto 89 /// here for each with block that activates a new InsertionPoint, Context or 90 /// Location. 91 /// 92 /// Pushing either a Location or InsertionPoint also pushes its associated 93 /// Context. Pushing a Context will not modify the Location or InsertionPoint 94 /// unless if they are from a different context, in which case, they are 95 /// cleared. 96 class PyThreadContextEntry { 97 public: 98 enum class FrameKind { 99 Context, 100 InsertionPoint, 101 Location, 102 }; 103 104 PyThreadContextEntry(FrameKind frameKind, pybind11::object context, 105 pybind11::object insertionPoint, 106 pybind11::object location) 107 : context(std::move(context)), insertionPoint(std::move(insertionPoint)), 108 location(std::move(location)), frameKind(frameKind) {} 109 110 /// Gets the top of stack context and return nullptr if not defined. 111 static PyMlirContext *getDefaultContext(); 112 113 /// Gets the top of stack insertion point and return nullptr if not defined. 114 static PyInsertionPoint *getDefaultInsertionPoint(); 115 116 /// Gets the top of stack location and returns nullptr if not defined. 117 static PyLocation *getDefaultLocation(); 118 119 PyMlirContext *getContext(); 120 PyInsertionPoint *getInsertionPoint(); 121 PyLocation *getLocation(); 122 FrameKind getFrameKind() { return frameKind; } 123 124 /// Stack management. 125 static PyThreadContextEntry *getTopOfStack(); 126 static pybind11::object pushContext(PyMlirContext &context); 127 static void popContext(PyMlirContext &context); 128 static pybind11::object pushInsertionPoint(PyInsertionPoint &insertionPoint); 129 static void popInsertionPoint(PyInsertionPoint &insertionPoint); 130 static pybind11::object pushLocation(PyLocation &location); 131 static void popLocation(PyLocation &location); 132 133 /// Gets the thread local stack. 134 static std::vector<PyThreadContextEntry> &getStack(); 135 136 private: 137 static void push(FrameKind frameKind, pybind11::object context, 138 pybind11::object insertionPoint, pybind11::object location); 139 140 /// An object reference to the PyContext. 141 pybind11::object context; 142 /// An object reference to the current insertion point. 143 pybind11::object insertionPoint; 144 /// An object reference to the current location. 145 pybind11::object location; 146 // The kind of push that was performed. 147 FrameKind frameKind; 148 }; 149 150 /// Wrapper around MlirContext. 151 using PyMlirContextRef = PyObjectRef<PyMlirContext>; 152 class PyMlirContext { 153 public: 154 PyMlirContext() = delete; 155 PyMlirContext(const PyMlirContext &) = delete; 156 PyMlirContext(PyMlirContext &&) = delete; 157 158 /// For the case of a python __init__ (py::init) method, pybind11 is quite 159 /// strict about needing to return a pointer that is not yet associated to 160 /// an py::object. Since the forContext() method acts like a pool, possibly 161 /// returning a recycled context, it does not satisfy this need. The usual 162 /// way in python to accomplish such a thing is to override __new__, but 163 /// that is also not supported by pybind11. Instead, we use this entry 164 /// point which always constructs a fresh context (which cannot alias an 165 /// existing one because it is fresh). 166 static PyMlirContext *createNewContextForInit(); 167 168 /// Returns a context reference for the singleton PyMlirContext wrapper for 169 /// the given context. 170 static PyMlirContextRef forContext(MlirContext context); 171 ~PyMlirContext(); 172 173 /// Accesses the underlying MlirContext. 174 MlirContext get() { return context; } 175 176 /// Gets a strong reference to this context, which will ensure it is kept 177 /// alive for the life of the reference. 178 PyMlirContextRef getRef() { 179 return PyMlirContextRef(this, pybind11::cast(this)); 180 } 181 182 /// Gets a capsule wrapping the void* within the MlirContext. 183 pybind11::object getCapsule(); 184 185 /// Creates a PyMlirContext from the MlirContext wrapped by a capsule. 186 /// Note that PyMlirContext instances are uniqued, so the returned object 187 /// may be a pre-existing object. Ownership of the underlying MlirContext 188 /// is taken by calling this function. 189 static pybind11::object createFromCapsule(pybind11::object capsule); 190 191 /// Gets the count of live context objects. Used for testing. 192 static size_t getLiveCount(); 193 194 /// Gets the count of live operations associated with this context. 195 /// Used for testing. 196 size_t getLiveOperationCount(); 197 198 /// Gets the count of live modules associated with this context. 199 /// Used for testing. 200 size_t getLiveModuleCount(); 201 202 /// Enter and exit the context manager. 203 pybind11::object contextEnter(); 204 void contextExit(pybind11::object excType, pybind11::object excVal, 205 pybind11::object excTb); 206 207 private: 208 PyMlirContext(MlirContext context); 209 // Interns the mapping of live MlirContext::ptr to PyMlirContext instances, 210 // preserving the relationship that an MlirContext maps to a single 211 // PyMlirContext wrapper. This could be replaced in the future with an 212 // extension mechanism on the MlirContext for stashing user pointers. 213 // Note that this holds a handle, which does not imply ownership. 214 // Mappings will be removed when the context is destructed. 215 using LiveContextMap = llvm::DenseMap<void *, PyMlirContext *>; 216 static LiveContextMap &getLiveContexts(); 217 218 // Interns all live modules associated with this context. Modules tracked 219 // in this map are valid. When a module is invalidated, it is removed 220 // from this map, and while it still exists as an instance, any 221 // attempt to access it will raise an error. 222 using LiveModuleMap = 223 llvm::DenseMap<const void *, std::pair<pybind11::handle, PyModule *>>; 224 LiveModuleMap liveModules; 225 226 // Interns all live operations associated with this context. Operations 227 // tracked in this map are valid. When an operation is invalidated, it is 228 // removed from this map, and while it still exists as an instance, any 229 // attempt to access it will raise an error. 230 using LiveOperationMap = 231 llvm::DenseMap<void *, std::pair<pybind11::handle, PyOperation *>>; 232 LiveOperationMap liveOperations; 233 234 MlirContext context; 235 friend class PyModule; 236 friend class PyOperation; 237 }; 238 239 /// Used in function arguments when None should resolve to the current context 240 /// manager set instance. 241 class DefaultingPyMlirContext 242 : public Defaulting<DefaultingPyMlirContext, PyMlirContext> { 243 public: 244 using Defaulting::Defaulting; 245 static constexpr const char kTypeDescription[] = 246 "[ThreadContextAware] mlir.ir.Context"; 247 static PyMlirContext &resolve(); 248 }; 249 250 /// Base class for all objects that directly or indirectly depend on an 251 /// MlirContext. The lifetime of the context will extend at least to the 252 /// lifetime of these instances. 253 /// Immutable objects that depend on a context extend this directly. 254 class BaseContextObject { 255 public: 256 BaseContextObject(PyMlirContextRef ref) : contextRef(std::move(ref)) { 257 assert(this->contextRef && 258 "context object constructed with null context ref"); 259 } 260 261 /// Accesses the context reference. 262 PyMlirContextRef &getContext() { return contextRef; } 263 264 private: 265 PyMlirContextRef contextRef; 266 }; 267 268 /// Wrapper around an MlirDialect. This is exported as `DialectDescriptor` in 269 /// order to differentiate it from the `Dialect` base class which is extended by 270 /// plugins which extend dialect functionality through extension python code. 271 /// This should be seen as the "low-level" object and `Dialect` as the 272 /// high-level, user facing object. 273 class PyDialectDescriptor : public BaseContextObject { 274 public: 275 PyDialectDescriptor(PyMlirContextRef contextRef, MlirDialect dialect) 276 : BaseContextObject(std::move(contextRef)), dialect(dialect) {} 277 278 MlirDialect get() { return dialect; } 279 280 private: 281 MlirDialect dialect; 282 }; 283 284 /// User-level object for accessing dialects with dotted syntax such as: 285 /// ctx.dialect.std 286 class PyDialects : public BaseContextObject { 287 public: 288 PyDialects(PyMlirContextRef contextRef) 289 : BaseContextObject(std::move(contextRef)) {} 290 291 MlirDialect getDialectForKey(const std::string &key, bool attrError); 292 }; 293 294 /// User-level dialect object. For dialects that have a registered extension, 295 /// this will be the base class of the extension dialect type. For un-extended, 296 /// objects of this type will be returned directly. 297 class PyDialect { 298 public: 299 PyDialect(pybind11::object descriptor) : descriptor(std::move(descriptor)) {} 300 301 pybind11::object getDescriptor() { return descriptor; } 302 303 private: 304 pybind11::object descriptor; 305 }; 306 307 /// Wrapper around an MlirLocation. 308 class PyLocation : public BaseContextObject { 309 public: 310 PyLocation(PyMlirContextRef contextRef, MlirLocation loc) 311 : BaseContextObject(std::move(contextRef)), loc(loc) {} 312 313 operator MlirLocation() const { return loc; } 314 MlirLocation get() const { return loc; } 315 316 /// Enter and exit the context manager. 317 pybind11::object contextEnter(); 318 void contextExit(pybind11::object excType, pybind11::object excVal, 319 pybind11::object excTb); 320 321 /// Gets a capsule wrapping the void* within the MlirLocation. 322 pybind11::object getCapsule(); 323 324 /// Creates a PyLocation from the MlirLocation wrapped by a capsule. 325 /// Note that PyLocation instances are uniqued, so the returned object 326 /// may be a pre-existing object. Ownership of the underlying MlirLocation 327 /// is taken by calling this function. 328 static PyLocation createFromCapsule(pybind11::object capsule); 329 330 private: 331 MlirLocation loc; 332 }; 333 334 /// Used in function arguments when None should resolve to the current context 335 /// manager set instance. 336 class DefaultingPyLocation 337 : public Defaulting<DefaultingPyLocation, PyLocation> { 338 public: 339 using Defaulting::Defaulting; 340 static constexpr const char kTypeDescription[] = 341 "[ThreadContextAware] mlir.ir.Location"; 342 static PyLocation &resolve(); 343 344 operator MlirLocation() const { return *get(); } 345 }; 346 347 /// Wrapper around MlirModule. 348 /// This is the top-level, user-owned object that contains regions/ops/blocks. 349 class PyModule; 350 using PyModuleRef = PyObjectRef<PyModule>; 351 class PyModule : public BaseContextObject { 352 public: 353 /// Returns a PyModule reference for the given MlirModule. This may return 354 /// a pre-existing or new object. 355 static PyModuleRef forModule(MlirModule module); 356 PyModule(PyModule &) = delete; 357 PyModule(PyMlirContext &&) = delete; 358 ~PyModule(); 359 360 /// Gets the backing MlirModule. 361 MlirModule get() { return module; } 362 363 /// Gets a strong reference to this module. 364 PyModuleRef getRef() { 365 return PyModuleRef(this, 366 pybind11::reinterpret_borrow<pybind11::object>(handle)); 367 } 368 369 /// Gets a capsule wrapping the void* within the MlirModule. 370 /// Note that the module does not (yet) provide a corresponding factory for 371 /// constructing from a capsule as that would require uniquing PyModule 372 /// instances, which is not currently done. 373 pybind11::object getCapsule(); 374 375 /// Creates a PyModule from the MlirModule wrapped by a capsule. 376 /// Note that PyModule instances are uniqued, so the returned object 377 /// may be a pre-existing object. Ownership of the underlying MlirModule 378 /// is taken by calling this function. 379 static pybind11::object createFromCapsule(pybind11::object capsule); 380 381 private: 382 PyModule(PyMlirContextRef contextRef, MlirModule module); 383 MlirModule module; 384 pybind11::handle handle; 385 }; 386 387 /// Base class for PyOperation and PyOpView which exposes the primary, user 388 /// visible methods for manipulating it. 389 class PyOperationBase { 390 public: 391 virtual ~PyOperationBase() = default; 392 /// Implements the bound 'print' method and helps with others. 393 void print(pybind11::object fileObject, bool binary, 394 llvm::Optional<int64_t> largeElementsLimit, bool enableDebugInfo, 395 bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope); 396 pybind11::object getAsm(bool binary, 397 llvm::Optional<int64_t> largeElementsLimit, 398 bool enableDebugInfo, bool prettyDebugInfo, 399 bool printGenericOpForm, bool useLocalScope); 400 401 /// Each must provide access to the raw Operation. 402 virtual PyOperation &getOperation() = 0; 403 }; 404 405 /// Wrapper around PyOperation. 406 /// Operations exist in either an attached (dependent) or detached (top-level) 407 /// state. In the detached state (as on creation), an operation is owned by 408 /// the creator and its lifetime extends either until its reference count 409 /// drops to zero or it is attached to a parent, at which point its lifetime 410 /// is bounded by its top-level parent reference. 411 class PyOperation; 412 using PyOperationRef = PyObjectRef<PyOperation>; 413 class PyOperation : public PyOperationBase, public BaseContextObject { 414 public: 415 ~PyOperation(); 416 PyOperation &getOperation() override { return *this; } 417 418 /// Returns a PyOperation for the given MlirOperation, optionally associating 419 /// it with a parentKeepAlive. 420 static PyOperationRef 421 forOperation(PyMlirContextRef contextRef, MlirOperation operation, 422 pybind11::object parentKeepAlive = pybind11::object()); 423 424 /// Creates a detached operation. The operation must not be associated with 425 /// any existing live operation. 426 static PyOperationRef 427 createDetached(PyMlirContextRef contextRef, MlirOperation operation, 428 pybind11::object parentKeepAlive = pybind11::object()); 429 430 /// Gets the backing operation. 431 operator MlirOperation() const { return get(); } 432 MlirOperation get() const { 433 checkValid(); 434 return operation; 435 } 436 437 PyOperationRef getRef() { 438 return PyOperationRef( 439 this, pybind11::reinterpret_borrow<pybind11::object>(handle)); 440 } 441 442 bool isAttached() { return attached; } 443 void setAttached() { 444 assert(!attached && "operation already attached"); 445 attached = true; 446 } 447 void checkValid() const; 448 449 /// Gets the owning block or raises an exception if the operation has no 450 /// owning block. 451 PyBlock getBlock(); 452 453 /// Gets the parent operation or raises an exception if the operation has 454 /// no parent. 455 PyOperationRef getParentOperation(); 456 457 /// Gets a capsule wrapping the void* within the MlirOperation. 458 pybind11::object getCapsule(); 459 460 /// Creates a PyOperation from the MlirOperation wrapped by a capsule. 461 /// Ownership of the underlying MlirOperation is taken by calling this 462 /// function. 463 static pybind11::object createFromCapsule(pybind11::object capsule); 464 465 /// Creates an operation. See corresponding python docstring. 466 static pybind11::object 467 create(std::string name, llvm::Optional<std::vector<PyType *>> results, 468 llvm::Optional<std::vector<PyValue *>> operands, 469 llvm::Optional<pybind11::dict> attributes, 470 llvm::Optional<std::vector<PyBlock *>> successors, int regions, 471 DefaultingPyLocation location, pybind11::object ip); 472 473 /// Creates an OpView suitable for this operation. 474 pybind11::object createOpView(); 475 476 private: 477 PyOperation(PyMlirContextRef contextRef, MlirOperation operation); 478 static PyOperationRef createInstance(PyMlirContextRef contextRef, 479 MlirOperation operation, 480 pybind11::object parentKeepAlive); 481 482 MlirOperation operation; 483 pybind11::handle handle; 484 // Keeps the parent alive, regardless of whether it is an Operation or 485 // Module. 486 // TODO: As implemented, this facility is only sufficient for modeling the 487 // trivial module parent back-reference. Generalize this to also account for 488 // transitions from detached to attached and address TODOs in the 489 // ir_operation.py regarding testing corresponding lifetime guarantees. 490 pybind11::object parentKeepAlive; 491 bool attached = true; 492 bool valid = true; 493 }; 494 495 /// A PyOpView is equivalent to the C++ "Op" wrappers: these are the basis for 496 /// providing more instance-specific accessors and serve as the base class for 497 /// custom ODS-style operation classes. Since this class is subclass on the 498 /// python side, it must present an __init__ method that operates in pure 499 /// python types. 500 class PyOpView : public PyOperationBase { 501 public: 502 PyOpView(pybind11::object operationObject); 503 PyOperation &getOperation() override { return operation; } 504 505 static pybind11::object createRawSubclass(pybind11::object userClass); 506 507 pybind11::object getOperationObject() { return operationObject; } 508 509 static pybind11::object 510 buildGeneric(pybind11::object cls, pybind11::list resultTypeList, 511 pybind11::list operandList, 512 llvm::Optional<pybind11::dict> attributes, 513 llvm::Optional<std::vector<PyBlock *>> successors, 514 llvm::Optional<int> regions, DefaultingPyLocation location, 515 pybind11::object maybeIp); 516 517 private: 518 PyOperation &operation; // For efficient, cast-free access from C++ 519 pybind11::object operationObject; // Holds the reference. 520 }; 521 522 /// Wrapper around an MlirRegion. 523 /// Regions are managed completely by their containing operation. Unlike the 524 /// C++ API, the python API does not support detached regions. 525 class PyRegion { 526 public: 527 PyRegion(PyOperationRef parentOperation, MlirRegion region) 528 : parentOperation(std::move(parentOperation)), region(region) { 529 assert(!mlirRegionIsNull(region) && "python region cannot be null"); 530 } 531 532 MlirRegion get() { return region; } 533 PyOperationRef &getParentOperation() { return parentOperation; } 534 535 void checkValid() { return parentOperation->checkValid(); } 536 537 private: 538 PyOperationRef parentOperation; 539 MlirRegion region; 540 }; 541 542 /// Wrapper around an MlirBlock. 543 /// Blocks are managed completely by their containing operation. Unlike the 544 /// C++ API, the python API does not support detached blocks. 545 class PyBlock { 546 public: 547 PyBlock(PyOperationRef parentOperation, MlirBlock block) 548 : parentOperation(std::move(parentOperation)), block(block) { 549 assert(!mlirBlockIsNull(block) && "python block cannot be null"); 550 } 551 552 MlirBlock get() { return block; } 553 PyOperationRef &getParentOperation() { return parentOperation; } 554 555 void checkValid() { return parentOperation->checkValid(); } 556 557 private: 558 PyOperationRef parentOperation; 559 MlirBlock block; 560 }; 561 562 /// An insertion point maintains a pointer to a Block and a reference operation. 563 /// Calls to insert() will insert a new operation before the 564 /// reference operation. If the reference operation is null, then appends to 565 /// the end of the block. 566 class PyInsertionPoint { 567 public: 568 /// Creates an insertion point positioned after the last operation in the 569 /// block, but still inside the block. 570 PyInsertionPoint(PyBlock &block); 571 /// Creates an insertion point positioned before a reference operation. 572 PyInsertionPoint(PyOperationBase &beforeOperationBase); 573 574 /// Shortcut to create an insertion point at the beginning of the block. 575 static PyInsertionPoint atBlockBegin(PyBlock &block); 576 /// Shortcut to create an insertion point before the block terminator. 577 static PyInsertionPoint atBlockTerminator(PyBlock &block); 578 579 /// Inserts an operation. 580 void insert(PyOperationBase &operationBase); 581 582 /// Enter and exit the context manager. 583 pybind11::object contextEnter(); 584 void contextExit(pybind11::object excType, pybind11::object excVal, 585 pybind11::object excTb); 586 587 PyBlock &getBlock() { return block; } 588 589 private: 590 // Trampoline constructor that avoids null initializing members while 591 // looking up parents. 592 PyInsertionPoint(PyBlock block, llvm::Optional<PyOperationRef> refOperation) 593 : refOperation(std::move(refOperation)), block(std::move(block)) {} 594 595 llvm::Optional<PyOperationRef> refOperation; 596 PyBlock block; 597 }; 598 599 /// Wrapper around the generic MlirAttribute. 600 /// The lifetime of a type is bound by the PyContext that created it. 601 class PyAttribute : public BaseContextObject { 602 public: 603 PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr) 604 : BaseContextObject(std::move(contextRef)), attr(attr) {} 605 bool operator==(const PyAttribute &other); 606 operator MlirAttribute() const { return attr; } 607 MlirAttribute get() const { return attr; } 608 609 /// Gets a capsule wrapping the void* within the MlirAttribute. 610 pybind11::object getCapsule(); 611 612 /// Creates a PyAttribute from the MlirAttribute wrapped by a capsule. 613 /// Note that PyAttribute instances are uniqued, so the returned object 614 /// may be a pre-existing object. Ownership of the underlying MlirAttribute 615 /// is taken by calling this function. 616 static PyAttribute createFromCapsule(pybind11::object capsule); 617 618 private: 619 MlirAttribute attr; 620 }; 621 622 /// Represents a Python MlirNamedAttr, carrying an optional owned name. 623 /// TODO: Refactor this and the C-API to be based on an Identifier owned 624 /// by the context so as to avoid ownership issues here. 625 class PyNamedAttribute { 626 public: 627 /// Constructs a PyNamedAttr that retains an owned name. This should be 628 /// used in any code that originates an MlirNamedAttribute from a python 629 /// string. 630 /// The lifetime of the PyNamedAttr must extend to the lifetime of the 631 /// passed attribute. 632 PyNamedAttribute(MlirAttribute attr, std::string ownedName); 633 634 MlirNamedAttribute namedAttr; 635 636 private: 637 // Since the MlirNamedAttr contains an internal pointer to the actual 638 // memory of the owned string, it must be heap allocated to remain valid. 639 // Otherwise, strings that fit within the small object optimization threshold 640 // will have their memory address change as the containing object is moved, 641 // resulting in an invalid aliased pointer. 642 std::unique_ptr<std::string> ownedName; 643 }; 644 645 /// Wrapper around the generic MlirType. 646 /// The lifetime of a type is bound by the PyContext that created it. 647 class PyType : public BaseContextObject { 648 public: 649 PyType(PyMlirContextRef contextRef, MlirType type) 650 : BaseContextObject(std::move(contextRef)), type(type) {} 651 bool operator==(const PyType &other); 652 operator MlirType() const { return type; } 653 MlirType get() const { return type; } 654 655 /// Gets a capsule wrapping the void* within the MlirType. 656 pybind11::object getCapsule(); 657 658 /// Creates a PyType from the MlirType wrapped by a capsule. 659 /// Note that PyType instances are uniqued, so the returned object 660 /// may be a pre-existing object. Ownership of the underlying MlirType 661 /// is taken by calling this function. 662 static PyType createFromCapsule(pybind11::object capsule); 663 664 private: 665 MlirType type; 666 }; 667 668 /// Wrapper around the generic MlirValue. 669 /// Values are managed completely by the operation that resulted in their 670 /// definition. For op result value, this is the operation that defines the 671 /// value. For block argument values, this is the operation that contains the 672 /// block to which the value is an argument (blocks cannot be detached in Python 673 /// bindings so such operation always exists). 674 class PyValue { 675 public: 676 PyValue(PyOperationRef parentOperation, MlirValue value) 677 : parentOperation(parentOperation), value(value) {} 678 679 MlirValue get() { return value; } 680 PyOperationRef &getParentOperation() { return parentOperation; } 681 682 void checkValid() { return parentOperation->checkValid(); } 683 684 private: 685 PyOperationRef parentOperation; 686 MlirValue value; 687 }; 688 689 /// Wrapper around MlirAffineExpr. Affine expressions are owned by the context. 690 class PyAffineExpr : public BaseContextObject { 691 public: 692 PyAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr) 693 : BaseContextObject(std::move(contextRef)), affineExpr(affineExpr) {} 694 bool operator==(const PyAffineExpr &other); 695 operator MlirAffineExpr() const { return affineExpr; } 696 MlirAffineExpr get() const { return affineExpr; } 697 698 /// Gets a capsule wrapping the void* within the MlirAffineExpr. 699 pybind11::object getCapsule(); 700 701 /// Creates a PyAffineExpr from the MlirAffineExpr wrapped by a capsule. 702 /// Note that PyAffineExpr instances are uniqued, so the returned object 703 /// may be a pre-existing object. Ownership of the underlying MlirAffineExpr 704 /// is taken by calling this function. 705 static PyAffineExpr createFromCapsule(pybind11::object capsule); 706 707 PyAffineExpr add(const PyAffineExpr &other) const; 708 PyAffineExpr mul(const PyAffineExpr &other) const; 709 PyAffineExpr floorDiv(const PyAffineExpr &other) const; 710 PyAffineExpr ceilDiv(const PyAffineExpr &other) const; 711 PyAffineExpr mod(const PyAffineExpr &other) const; 712 713 private: 714 MlirAffineExpr affineExpr; 715 }; 716 717 class PyAffineMap : public BaseContextObject { 718 public: 719 PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap) 720 : BaseContextObject(std::move(contextRef)), affineMap(affineMap) {} 721 bool operator==(const PyAffineMap &other); 722 operator MlirAffineMap() const { return affineMap; } 723 MlirAffineMap get() const { return affineMap; } 724 725 /// Gets a capsule wrapping the void* within the MlirAffineMap. 726 pybind11::object getCapsule(); 727 728 /// Creates a PyAffineMap from the MlirAffineMap wrapped by a capsule. 729 /// Note that PyAffineMap instances are uniqued, so the returned object 730 /// may be a pre-existing object. Ownership of the underlying MlirAffineMap 731 /// is taken by calling this function. 732 static PyAffineMap createFromCapsule(pybind11::object capsule); 733 734 private: 735 MlirAffineMap affineMap; 736 }; 737 738 class PyIntegerSet : public BaseContextObject { 739 public: 740 PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet) 741 : BaseContextObject(std::move(contextRef)), integerSet(integerSet) {} 742 bool operator==(const PyIntegerSet &other); 743 operator MlirIntegerSet() const { return integerSet; } 744 MlirIntegerSet get() const { return integerSet; } 745 746 /// Gets a capsule wrapping the void* within the MlirIntegerSet. 747 pybind11::object getCapsule(); 748 749 /// Creates a PyIntegerSet from the MlirAffineMap wrapped by a capsule. 750 /// Note that PyIntegerSet instances may be uniqued, so the returned object 751 /// may be a pre-existing object. Integer sets are owned by the context. 752 static PyIntegerSet createFromCapsule(pybind11::object capsule); 753 754 private: 755 MlirIntegerSet integerSet; 756 }; 757 758 void populateIRAffine(pybind11::module &m); 759 void populateIRAttributes(pybind11::module &m); 760 void populateIRCore(pybind11::module &m); 761 void populateIRTypes(pybind11::module &m); 762 763 } // namespace python 764 } // namespace mlir 765 766 namespace pybind11 { 767 namespace detail { 768 769 template <> 770 struct type_caster<mlir::python::DefaultingPyMlirContext> 771 : MlirDefaultingCaster<mlir::python::DefaultingPyMlirContext> {}; 772 template <> 773 struct type_caster<mlir::python::DefaultingPyLocation> 774 : MlirDefaultingCaster<mlir::python::DefaultingPyLocation> {}; 775 776 } // namespace detail 777 } // namespace pybind11 778 779 #endif // MLIR_BINDINGS_PYTHON_IRMODULES_H 780