1 //===- IRModules.cpp - 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 #include "IRModule.h" 10 11 #include "Globals.h" 12 #include "PybindUtils.h" 13 14 #include "mlir-c/Bindings/Python/Interop.h" 15 #include "mlir-c/BuiltinAttributes.h" 16 #include "mlir-c/BuiltinTypes.h" 17 #include "mlir-c/Debug.h" 18 #include "mlir-c/IR.h" 19 #include "mlir-c/Registration.h" 20 #include "llvm/ADT/ArrayRef.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include <pybind11/stl.h> 23 24 #include <utility> 25 26 namespace py = pybind11; 27 using namespace mlir; 28 using namespace mlir::python; 29 30 using llvm::SmallVector; 31 using llvm::StringRef; 32 using llvm::Twine; 33 34 //------------------------------------------------------------------------------ 35 // Docstrings (trivial, non-duplicated docstrings are included inline). 36 //------------------------------------------------------------------------------ 37 38 static const char kContextParseTypeDocstring[] = 39 R"(Parses the assembly form of a type. 40 41 Returns a Type object or raises a ValueError if the type cannot be parsed. 42 43 See also: https://mlir.llvm.org/docs/LangRef/#type-system 44 )"; 45 46 static const char kContextGetCallSiteLocationDocstring[] = 47 R"(Gets a Location representing a caller and callsite)"; 48 49 static const char kContextGetFileLocationDocstring[] = 50 R"(Gets a Location representing a file, line and column)"; 51 52 static const char kContextGetFusedLocationDocstring[] = 53 R"(Gets a Location representing a fused location with optional metadata)"; 54 55 static const char kContextGetNameLocationDocString[] = 56 R"(Gets a Location representing a named location with optional child location)"; 57 58 static const char kModuleParseDocstring[] = 59 R"(Parses a module's assembly format from a string. 60 61 Returns a new MlirModule or raises a ValueError if the parsing fails. 62 63 See also: https://mlir.llvm.org/docs/LangRef/ 64 )"; 65 66 static const char kOperationCreateDocstring[] = 67 R"(Creates a new operation. 68 69 Args: 70 name: Operation name (e.g. "dialect.operation"). 71 results: Sequence of Type representing op result types. 72 attributes: Dict of str:Attribute. 73 successors: List of Block for the operation's successors. 74 regions: Number of regions to create. 75 location: A Location object (defaults to resolve from context manager). 76 ip: An InsertionPoint (defaults to resolve from context manager or set to 77 False to disable insertion, even with an insertion point set in the 78 context manager). 79 Returns: 80 A new "detached" Operation object. Detached operations can be added 81 to blocks, which causes them to become "attached." 82 )"; 83 84 static const char kOperationPrintDocstring[] = 85 R"(Prints the assembly form of the operation to a file like object. 86 87 Args: 88 file: The file like object to write to. Defaults to sys.stdout. 89 binary: Whether to write bytes (True) or str (False). Defaults to False. 90 large_elements_limit: Whether to elide elements attributes above this 91 number of elements. Defaults to None (no limit). 92 enable_debug_info: Whether to print debug/location information. Defaults 93 to False. 94 pretty_debug_info: Whether to format debug information for easier reading 95 by a human (warning: the result is unparseable). 96 print_generic_op_form: Whether to print the generic assembly forms of all 97 ops. Defaults to False. 98 use_local_Scope: Whether to print in a way that is more optimized for 99 multi-threaded access but may not be consistent with how the overall 100 module prints. 101 assume_verified: By default, if not printing generic form, the verifier 102 will be run and if it fails, generic form will be printed with a comment 103 about failed verification. While a reasonable default for interactive use, 104 for systematic use, it is often better for the caller to verify explicitly 105 and report failures in a more robust fashion. Set this to True if doing this 106 in order to avoid running a redundant verification. If the IR is actually 107 invalid, behavior is undefined. 108 )"; 109 110 static const char kOperationGetAsmDocstring[] = 111 R"(Gets the assembly form of the operation with all options available. 112 113 Args: 114 binary: Whether to return a bytes (True) or str (False) object. Defaults to 115 False. 116 ... others ...: See the print() method for common keyword arguments for 117 configuring the printout. 118 Returns: 119 Either a bytes or str object, depending on the setting of the 'binary' 120 argument. 121 )"; 122 123 static const char kOperationStrDunderDocstring[] = 124 R"(Gets the assembly form of the operation with default options. 125 126 If more advanced control over the assembly formatting or I/O options is needed, 127 use the dedicated print or get_asm method, which supports keyword arguments to 128 customize behavior. 129 )"; 130 131 static const char kDumpDocstring[] = 132 R"(Dumps a debug representation of the object to stderr.)"; 133 134 static const char kAppendBlockDocstring[] = 135 R"(Appends a new block, with argument types as positional args. 136 137 Returns: 138 The created block. 139 )"; 140 141 static const char kValueDunderStrDocstring[] = 142 R"(Returns the string form of the value. 143 144 If the value is a block argument, this is the assembly form of its type and the 145 position in the argument list. If the value is an operation result, this is 146 equivalent to printing the operation that produced it. 147 )"; 148 149 //------------------------------------------------------------------------------ 150 // Utilities. 151 //------------------------------------------------------------------------------ 152 153 /// Helper for creating an @classmethod. 154 template <class Func, typename... Args> 155 py::object classmethod(Func f, Args... args) { 156 py::object cf = py::cpp_function(f, args...); 157 return py::reinterpret_borrow<py::object>((PyClassMethod_New(cf.ptr()))); 158 } 159 160 static py::object 161 createCustomDialectWrapper(const std::string &dialectNamespace, 162 py::object dialectDescriptor) { 163 auto dialectClass = PyGlobals::get().lookupDialectClass(dialectNamespace); 164 if (!dialectClass) { 165 // Use the base class. 166 return py::cast(PyDialect(std::move(dialectDescriptor))); 167 } 168 169 // Create the custom implementation. 170 return (*dialectClass)(std::move(dialectDescriptor)); 171 } 172 173 static MlirStringRef toMlirStringRef(const std::string &s) { 174 return mlirStringRefCreate(s.data(), s.size()); 175 } 176 177 /// Wrapper for the global LLVM debugging flag. 178 struct PyGlobalDebugFlag { 179 static void set(py::object &o, bool enable) { mlirEnableGlobalDebug(enable); } 180 181 static bool get(const py::object &) { return mlirIsGlobalDebugEnabled(); } 182 183 static void bind(py::module &m) { 184 // Debug flags. 185 py::class_<PyGlobalDebugFlag>(m, "_GlobalDebug", py::module_local()) 186 .def_property_static("flag", &PyGlobalDebugFlag::get, 187 &PyGlobalDebugFlag::set, "LLVM-wide debug flag"); 188 } 189 }; 190 191 //------------------------------------------------------------------------------ 192 // Collections. 193 //------------------------------------------------------------------------------ 194 195 namespace { 196 197 class PyRegionIterator { 198 public: 199 PyRegionIterator(PyOperationRef operation) 200 : operation(std::move(operation)) {} 201 202 PyRegionIterator &dunderIter() { return *this; } 203 204 PyRegion dunderNext() { 205 operation->checkValid(); 206 if (nextIndex >= mlirOperationGetNumRegions(operation->get())) { 207 throw py::stop_iteration(); 208 } 209 MlirRegion region = mlirOperationGetRegion(operation->get(), nextIndex++); 210 return PyRegion(operation, region); 211 } 212 213 static void bind(py::module &m) { 214 py::class_<PyRegionIterator>(m, "RegionIterator", py::module_local()) 215 .def("__iter__", &PyRegionIterator::dunderIter) 216 .def("__next__", &PyRegionIterator::dunderNext); 217 } 218 219 private: 220 PyOperationRef operation; 221 int nextIndex = 0; 222 }; 223 224 /// Regions of an op are fixed length and indexed numerically so are represented 225 /// with a sequence-like container. 226 class PyRegionList { 227 public: 228 PyRegionList(PyOperationRef operation) : operation(std::move(operation)) {} 229 230 intptr_t dunderLen() { 231 operation->checkValid(); 232 return mlirOperationGetNumRegions(operation->get()); 233 } 234 235 PyRegion dunderGetItem(intptr_t index) { 236 // dunderLen checks validity. 237 if (index < 0 || index >= dunderLen()) { 238 throw SetPyError(PyExc_IndexError, 239 "attempt to access out of bounds region"); 240 } 241 MlirRegion region = mlirOperationGetRegion(operation->get(), index); 242 return PyRegion(operation, region); 243 } 244 245 static void bind(py::module &m) { 246 py::class_<PyRegionList>(m, "RegionSequence", py::module_local()) 247 .def("__len__", &PyRegionList::dunderLen) 248 .def("__getitem__", &PyRegionList::dunderGetItem); 249 } 250 251 private: 252 PyOperationRef operation; 253 }; 254 255 class PyBlockIterator { 256 public: 257 PyBlockIterator(PyOperationRef operation, MlirBlock next) 258 : operation(std::move(operation)), next(next) {} 259 260 PyBlockIterator &dunderIter() { return *this; } 261 262 PyBlock dunderNext() { 263 operation->checkValid(); 264 if (mlirBlockIsNull(next)) { 265 throw py::stop_iteration(); 266 } 267 268 PyBlock returnBlock(operation, next); 269 next = mlirBlockGetNextInRegion(next); 270 return returnBlock; 271 } 272 273 static void bind(py::module &m) { 274 py::class_<PyBlockIterator>(m, "BlockIterator", py::module_local()) 275 .def("__iter__", &PyBlockIterator::dunderIter) 276 .def("__next__", &PyBlockIterator::dunderNext); 277 } 278 279 private: 280 PyOperationRef operation; 281 MlirBlock next; 282 }; 283 284 /// Blocks are exposed by the C-API as a forward-only linked list. In Python, 285 /// we present them as a more full-featured list-like container but optimize 286 /// it for forward iteration. Blocks are always owned by a region. 287 class PyBlockList { 288 public: 289 PyBlockList(PyOperationRef operation, MlirRegion region) 290 : operation(std::move(operation)), region(region) {} 291 292 PyBlockIterator dunderIter() { 293 operation->checkValid(); 294 return PyBlockIterator(operation, mlirRegionGetFirstBlock(region)); 295 } 296 297 intptr_t dunderLen() { 298 operation->checkValid(); 299 intptr_t count = 0; 300 MlirBlock block = mlirRegionGetFirstBlock(region); 301 while (!mlirBlockIsNull(block)) { 302 count += 1; 303 block = mlirBlockGetNextInRegion(block); 304 } 305 return count; 306 } 307 308 PyBlock dunderGetItem(intptr_t index) { 309 operation->checkValid(); 310 if (index < 0) { 311 throw SetPyError(PyExc_IndexError, 312 "attempt to access out of bounds block"); 313 } 314 MlirBlock block = mlirRegionGetFirstBlock(region); 315 while (!mlirBlockIsNull(block)) { 316 if (index == 0) { 317 return PyBlock(operation, block); 318 } 319 block = mlirBlockGetNextInRegion(block); 320 index -= 1; 321 } 322 throw SetPyError(PyExc_IndexError, "attempt to access out of bounds block"); 323 } 324 325 PyBlock appendBlock(const py::args &pyArgTypes) { 326 operation->checkValid(); 327 llvm::SmallVector<MlirType, 4> argTypes; 328 argTypes.reserve(pyArgTypes.size()); 329 for (auto &pyArg : pyArgTypes) { 330 argTypes.push_back(pyArg.cast<PyType &>()); 331 } 332 333 MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data()); 334 mlirRegionAppendOwnedBlock(region, block); 335 return PyBlock(operation, block); 336 } 337 338 static void bind(py::module &m) { 339 py::class_<PyBlockList>(m, "BlockList", py::module_local()) 340 .def("__getitem__", &PyBlockList::dunderGetItem) 341 .def("__iter__", &PyBlockList::dunderIter) 342 .def("__len__", &PyBlockList::dunderLen) 343 .def("append", &PyBlockList::appendBlock, kAppendBlockDocstring); 344 } 345 346 private: 347 PyOperationRef operation; 348 MlirRegion region; 349 }; 350 351 class PyOperationIterator { 352 public: 353 PyOperationIterator(PyOperationRef parentOperation, MlirOperation next) 354 : parentOperation(std::move(parentOperation)), next(next) {} 355 356 PyOperationIterator &dunderIter() { return *this; } 357 358 py::object dunderNext() { 359 parentOperation->checkValid(); 360 if (mlirOperationIsNull(next)) { 361 throw py::stop_iteration(); 362 } 363 364 PyOperationRef returnOperation = 365 PyOperation::forOperation(parentOperation->getContext(), next); 366 next = mlirOperationGetNextInBlock(next); 367 return returnOperation->createOpView(); 368 } 369 370 static void bind(py::module &m) { 371 py::class_<PyOperationIterator>(m, "OperationIterator", py::module_local()) 372 .def("__iter__", &PyOperationIterator::dunderIter) 373 .def("__next__", &PyOperationIterator::dunderNext); 374 } 375 376 private: 377 PyOperationRef parentOperation; 378 MlirOperation next; 379 }; 380 381 /// Operations are exposed by the C-API as a forward-only linked list. In 382 /// Python, we present them as a more full-featured list-like container but 383 /// optimize it for forward iteration. Iterable operations are always owned 384 /// by a block. 385 class PyOperationList { 386 public: 387 PyOperationList(PyOperationRef parentOperation, MlirBlock block) 388 : parentOperation(std::move(parentOperation)), block(block) {} 389 390 PyOperationIterator dunderIter() { 391 parentOperation->checkValid(); 392 return PyOperationIterator(parentOperation, 393 mlirBlockGetFirstOperation(block)); 394 } 395 396 intptr_t dunderLen() { 397 parentOperation->checkValid(); 398 intptr_t count = 0; 399 MlirOperation childOp = mlirBlockGetFirstOperation(block); 400 while (!mlirOperationIsNull(childOp)) { 401 count += 1; 402 childOp = mlirOperationGetNextInBlock(childOp); 403 } 404 return count; 405 } 406 407 py::object dunderGetItem(intptr_t index) { 408 parentOperation->checkValid(); 409 if (index < 0) { 410 throw SetPyError(PyExc_IndexError, 411 "attempt to access out of bounds operation"); 412 } 413 MlirOperation childOp = mlirBlockGetFirstOperation(block); 414 while (!mlirOperationIsNull(childOp)) { 415 if (index == 0) { 416 return PyOperation::forOperation(parentOperation->getContext(), childOp) 417 ->createOpView(); 418 } 419 childOp = mlirOperationGetNextInBlock(childOp); 420 index -= 1; 421 } 422 throw SetPyError(PyExc_IndexError, 423 "attempt to access out of bounds operation"); 424 } 425 426 static void bind(py::module &m) { 427 py::class_<PyOperationList>(m, "OperationList", py::module_local()) 428 .def("__getitem__", &PyOperationList::dunderGetItem) 429 .def("__iter__", &PyOperationList::dunderIter) 430 .def("__len__", &PyOperationList::dunderLen); 431 } 432 433 private: 434 PyOperationRef parentOperation; 435 MlirBlock block; 436 }; 437 438 } // namespace 439 440 //------------------------------------------------------------------------------ 441 // PyMlirContext 442 //------------------------------------------------------------------------------ 443 444 PyMlirContext::PyMlirContext(MlirContext context) : context(context) { 445 py::gil_scoped_acquire acquire; 446 auto &liveContexts = getLiveContexts(); 447 liveContexts[context.ptr] = this; 448 } 449 450 PyMlirContext::~PyMlirContext() { 451 // Note that the only public way to construct an instance is via the 452 // forContext method, which always puts the associated handle into 453 // liveContexts. 454 py::gil_scoped_acquire acquire; 455 getLiveContexts().erase(context.ptr); 456 mlirContextDestroy(context); 457 } 458 459 py::object PyMlirContext::getCapsule() { 460 return py::reinterpret_steal<py::object>(mlirPythonContextToCapsule(get())); 461 } 462 463 py::object PyMlirContext::createFromCapsule(py::object capsule) { 464 MlirContext rawContext = mlirPythonCapsuleToContext(capsule.ptr()); 465 if (mlirContextIsNull(rawContext)) 466 throw py::error_already_set(); 467 return forContext(rawContext).releaseObject(); 468 } 469 470 PyMlirContext *PyMlirContext::createNewContextForInit() { 471 MlirContext context = mlirContextCreate(); 472 mlirRegisterAllDialects(context); 473 return new PyMlirContext(context); 474 } 475 476 PyMlirContextRef PyMlirContext::forContext(MlirContext context) { 477 py::gil_scoped_acquire acquire; 478 auto &liveContexts = getLiveContexts(); 479 auto it = liveContexts.find(context.ptr); 480 if (it == liveContexts.end()) { 481 // Create. 482 PyMlirContext *unownedContextWrapper = new PyMlirContext(context); 483 py::object pyRef = py::cast(unownedContextWrapper); 484 assert(pyRef && "cast to py::object failed"); 485 liveContexts[context.ptr] = unownedContextWrapper; 486 return PyMlirContextRef(unownedContextWrapper, std::move(pyRef)); 487 } 488 // Use existing. 489 py::object pyRef = py::cast(it->second); 490 return PyMlirContextRef(it->second, std::move(pyRef)); 491 } 492 493 PyMlirContext::LiveContextMap &PyMlirContext::getLiveContexts() { 494 static LiveContextMap liveContexts; 495 return liveContexts; 496 } 497 498 size_t PyMlirContext::getLiveCount() { return getLiveContexts().size(); } 499 500 size_t PyMlirContext::getLiveOperationCount() { return liveOperations.size(); } 501 502 size_t PyMlirContext::getLiveModuleCount() { return liveModules.size(); } 503 504 pybind11::object PyMlirContext::contextEnter() { 505 return PyThreadContextEntry::pushContext(*this); 506 } 507 508 void PyMlirContext::contextExit(const pybind11::object &excType, 509 const pybind11::object &excVal, 510 const pybind11::object &excTb) { 511 PyThreadContextEntry::popContext(*this); 512 } 513 514 PyMlirContext &DefaultingPyMlirContext::resolve() { 515 PyMlirContext *context = PyThreadContextEntry::getDefaultContext(); 516 if (!context) { 517 throw SetPyError( 518 PyExc_RuntimeError, 519 "An MLIR function requires a Context but none was provided in the call " 520 "or from the surrounding environment. Either pass to the function with " 521 "a 'context=' argument or establish a default using 'with Context():'"); 522 } 523 return *context; 524 } 525 526 //------------------------------------------------------------------------------ 527 // PyThreadContextEntry management 528 //------------------------------------------------------------------------------ 529 530 std::vector<PyThreadContextEntry> &PyThreadContextEntry::getStack() { 531 static thread_local std::vector<PyThreadContextEntry> stack; 532 return stack; 533 } 534 535 PyThreadContextEntry *PyThreadContextEntry::getTopOfStack() { 536 auto &stack = getStack(); 537 if (stack.empty()) 538 return nullptr; 539 return &stack.back(); 540 } 541 542 void PyThreadContextEntry::push(FrameKind frameKind, py::object context, 543 py::object insertionPoint, 544 py::object location) { 545 auto &stack = getStack(); 546 stack.emplace_back(frameKind, std::move(context), std::move(insertionPoint), 547 std::move(location)); 548 // If the new stack has more than one entry and the context of the new top 549 // entry matches the previous, copy the insertionPoint and location from the 550 // previous entry if missing from the new top entry. 551 if (stack.size() > 1) { 552 auto &prev = *(stack.rbegin() + 1); 553 auto ¤t = stack.back(); 554 if (current.context.is(prev.context)) { 555 // Default non-context objects from the previous entry. 556 if (!current.insertionPoint) 557 current.insertionPoint = prev.insertionPoint; 558 if (!current.location) 559 current.location = prev.location; 560 } 561 } 562 } 563 564 PyMlirContext *PyThreadContextEntry::getContext() { 565 if (!context) 566 return nullptr; 567 return py::cast<PyMlirContext *>(context); 568 } 569 570 PyInsertionPoint *PyThreadContextEntry::getInsertionPoint() { 571 if (!insertionPoint) 572 return nullptr; 573 return py::cast<PyInsertionPoint *>(insertionPoint); 574 } 575 576 PyLocation *PyThreadContextEntry::getLocation() { 577 if (!location) 578 return nullptr; 579 return py::cast<PyLocation *>(location); 580 } 581 582 PyMlirContext *PyThreadContextEntry::getDefaultContext() { 583 auto *tos = getTopOfStack(); 584 return tos ? tos->getContext() : nullptr; 585 } 586 587 PyInsertionPoint *PyThreadContextEntry::getDefaultInsertionPoint() { 588 auto *tos = getTopOfStack(); 589 return tos ? tos->getInsertionPoint() : nullptr; 590 } 591 592 PyLocation *PyThreadContextEntry::getDefaultLocation() { 593 auto *tos = getTopOfStack(); 594 return tos ? tos->getLocation() : nullptr; 595 } 596 597 py::object PyThreadContextEntry::pushContext(PyMlirContext &context) { 598 py::object contextObj = py::cast(context); 599 push(FrameKind::Context, /*context=*/contextObj, 600 /*insertionPoint=*/py::object(), 601 /*location=*/py::object()); 602 return contextObj; 603 } 604 605 void PyThreadContextEntry::popContext(PyMlirContext &context) { 606 auto &stack = getStack(); 607 if (stack.empty()) 608 throw SetPyError(PyExc_RuntimeError, "Unbalanced Context enter/exit"); 609 auto &tos = stack.back(); 610 if (tos.frameKind != FrameKind::Context && tos.getContext() != &context) 611 throw SetPyError(PyExc_RuntimeError, "Unbalanced Context enter/exit"); 612 stack.pop_back(); 613 } 614 615 py::object 616 PyThreadContextEntry::pushInsertionPoint(PyInsertionPoint &insertionPoint) { 617 py::object contextObj = 618 insertionPoint.getBlock().getParentOperation()->getContext().getObject(); 619 py::object insertionPointObj = py::cast(insertionPoint); 620 push(FrameKind::InsertionPoint, 621 /*context=*/contextObj, 622 /*insertionPoint=*/insertionPointObj, 623 /*location=*/py::object()); 624 return insertionPointObj; 625 } 626 627 void PyThreadContextEntry::popInsertionPoint(PyInsertionPoint &insertionPoint) { 628 auto &stack = getStack(); 629 if (stack.empty()) 630 throw SetPyError(PyExc_RuntimeError, 631 "Unbalanced InsertionPoint enter/exit"); 632 auto &tos = stack.back(); 633 if (tos.frameKind != FrameKind::InsertionPoint && 634 tos.getInsertionPoint() != &insertionPoint) 635 throw SetPyError(PyExc_RuntimeError, 636 "Unbalanced InsertionPoint enter/exit"); 637 stack.pop_back(); 638 } 639 640 py::object PyThreadContextEntry::pushLocation(PyLocation &location) { 641 py::object contextObj = location.getContext().getObject(); 642 py::object locationObj = py::cast(location); 643 push(FrameKind::Location, /*context=*/contextObj, 644 /*insertionPoint=*/py::object(), 645 /*location=*/locationObj); 646 return locationObj; 647 } 648 649 void PyThreadContextEntry::popLocation(PyLocation &location) { 650 auto &stack = getStack(); 651 if (stack.empty()) 652 throw SetPyError(PyExc_RuntimeError, "Unbalanced Location enter/exit"); 653 auto &tos = stack.back(); 654 if (tos.frameKind != FrameKind::Location && tos.getLocation() != &location) 655 throw SetPyError(PyExc_RuntimeError, "Unbalanced Location enter/exit"); 656 stack.pop_back(); 657 } 658 659 //------------------------------------------------------------------------------ 660 // PyDialect, PyDialectDescriptor, PyDialects 661 //------------------------------------------------------------------------------ 662 663 MlirDialect PyDialects::getDialectForKey(const std::string &key, 664 bool attrError) { 665 MlirDialect dialect = mlirContextGetOrLoadDialect(getContext()->get(), 666 {key.data(), key.size()}); 667 if (mlirDialectIsNull(dialect)) { 668 throw SetPyError(attrError ? PyExc_AttributeError : PyExc_IndexError, 669 Twine("Dialect '") + key + "' not found"); 670 } 671 return dialect; 672 } 673 674 //------------------------------------------------------------------------------ 675 // PyLocation 676 //------------------------------------------------------------------------------ 677 678 py::object PyLocation::getCapsule() { 679 return py::reinterpret_steal<py::object>(mlirPythonLocationToCapsule(*this)); 680 } 681 682 PyLocation PyLocation::createFromCapsule(py::object capsule) { 683 MlirLocation rawLoc = mlirPythonCapsuleToLocation(capsule.ptr()); 684 if (mlirLocationIsNull(rawLoc)) 685 throw py::error_already_set(); 686 return PyLocation(PyMlirContext::forContext(mlirLocationGetContext(rawLoc)), 687 rawLoc); 688 } 689 690 py::object PyLocation::contextEnter() { 691 return PyThreadContextEntry::pushLocation(*this); 692 } 693 694 void PyLocation::contextExit(const pybind11::object &excType, 695 const pybind11::object &excVal, 696 const pybind11::object &excTb) { 697 PyThreadContextEntry::popLocation(*this); 698 } 699 700 PyLocation &DefaultingPyLocation::resolve() { 701 auto *location = PyThreadContextEntry::getDefaultLocation(); 702 if (!location) { 703 throw SetPyError( 704 PyExc_RuntimeError, 705 "An MLIR function requires a Location but none was provided in the " 706 "call or from the surrounding environment. Either pass to the function " 707 "with a 'loc=' argument or establish a default using 'with loc:'"); 708 } 709 return *location; 710 } 711 712 //------------------------------------------------------------------------------ 713 // PyModule 714 //------------------------------------------------------------------------------ 715 716 PyModule::PyModule(PyMlirContextRef contextRef, MlirModule module) 717 : BaseContextObject(std::move(contextRef)), module(module) {} 718 719 PyModule::~PyModule() { 720 py::gil_scoped_acquire acquire; 721 auto &liveModules = getContext()->liveModules; 722 assert(liveModules.count(module.ptr) == 1 && 723 "destroying module not in live map"); 724 liveModules.erase(module.ptr); 725 mlirModuleDestroy(module); 726 } 727 728 PyModuleRef PyModule::forModule(MlirModule module) { 729 MlirContext context = mlirModuleGetContext(module); 730 PyMlirContextRef contextRef = PyMlirContext::forContext(context); 731 732 py::gil_scoped_acquire acquire; 733 auto &liveModules = contextRef->liveModules; 734 auto it = liveModules.find(module.ptr); 735 if (it == liveModules.end()) { 736 // Create. 737 PyModule *unownedModule = new PyModule(std::move(contextRef), module); 738 // Note that the default return value policy on cast is automatic_reference, 739 // which does not take ownership (delete will not be called). 740 // Just be explicit. 741 py::object pyRef = 742 py::cast(unownedModule, py::return_value_policy::take_ownership); 743 unownedModule->handle = pyRef; 744 liveModules[module.ptr] = 745 std::make_pair(unownedModule->handle, unownedModule); 746 return PyModuleRef(unownedModule, std::move(pyRef)); 747 } 748 // Use existing. 749 PyModule *existing = it->second.second; 750 py::object pyRef = py::reinterpret_borrow<py::object>(it->second.first); 751 return PyModuleRef(existing, std::move(pyRef)); 752 } 753 754 py::object PyModule::createFromCapsule(py::object capsule) { 755 MlirModule rawModule = mlirPythonCapsuleToModule(capsule.ptr()); 756 if (mlirModuleIsNull(rawModule)) 757 throw py::error_already_set(); 758 return forModule(rawModule).releaseObject(); 759 } 760 761 py::object PyModule::getCapsule() { 762 return py::reinterpret_steal<py::object>(mlirPythonModuleToCapsule(get())); 763 } 764 765 //------------------------------------------------------------------------------ 766 // PyOperation 767 //------------------------------------------------------------------------------ 768 769 PyOperation::PyOperation(PyMlirContextRef contextRef, MlirOperation operation) 770 : BaseContextObject(std::move(contextRef)), operation(operation) {} 771 772 PyOperation::~PyOperation() { 773 // If the operation has already been invalidated there is nothing to do. 774 if (!valid) 775 return; 776 auto &liveOperations = getContext()->liveOperations; 777 assert(liveOperations.count(operation.ptr) == 1 && 778 "destroying operation not in live map"); 779 liveOperations.erase(operation.ptr); 780 if (!isAttached()) { 781 mlirOperationDestroy(operation); 782 } 783 } 784 785 PyOperationRef PyOperation::createInstance(PyMlirContextRef contextRef, 786 MlirOperation operation, 787 py::object parentKeepAlive) { 788 auto &liveOperations = contextRef->liveOperations; 789 // Create. 790 PyOperation *unownedOperation = 791 new PyOperation(std::move(contextRef), operation); 792 // Note that the default return value policy on cast is automatic_reference, 793 // which does not take ownership (delete will not be called). 794 // Just be explicit. 795 py::object pyRef = 796 py::cast(unownedOperation, py::return_value_policy::take_ownership); 797 unownedOperation->handle = pyRef; 798 if (parentKeepAlive) { 799 unownedOperation->parentKeepAlive = std::move(parentKeepAlive); 800 } 801 liveOperations[operation.ptr] = std::make_pair(pyRef, unownedOperation); 802 return PyOperationRef(unownedOperation, std::move(pyRef)); 803 } 804 805 PyOperationRef PyOperation::forOperation(PyMlirContextRef contextRef, 806 MlirOperation operation, 807 py::object parentKeepAlive) { 808 auto &liveOperations = contextRef->liveOperations; 809 auto it = liveOperations.find(operation.ptr); 810 if (it == liveOperations.end()) { 811 // Create. 812 return createInstance(std::move(contextRef), operation, 813 std::move(parentKeepAlive)); 814 } 815 // Use existing. 816 PyOperation *existing = it->second.second; 817 py::object pyRef = py::reinterpret_borrow<py::object>(it->second.first); 818 return PyOperationRef(existing, std::move(pyRef)); 819 } 820 821 PyOperationRef PyOperation::createDetached(PyMlirContextRef contextRef, 822 MlirOperation operation, 823 py::object parentKeepAlive) { 824 auto &liveOperations = contextRef->liveOperations; 825 assert(liveOperations.count(operation.ptr) == 0 && 826 "cannot create detached operation that already exists"); 827 (void)liveOperations; 828 829 PyOperationRef created = createInstance(std::move(contextRef), operation, 830 std::move(parentKeepAlive)); 831 created->attached = false; 832 return created; 833 } 834 835 void PyOperation::checkValid() const { 836 if (!valid) { 837 throw SetPyError(PyExc_RuntimeError, "the operation has been invalidated"); 838 } 839 } 840 841 void PyOperationBase::print(py::object fileObject, bool binary, 842 llvm::Optional<int64_t> largeElementsLimit, 843 bool enableDebugInfo, bool prettyDebugInfo, 844 bool printGenericOpForm, bool useLocalScope, 845 bool assumeVerified) { 846 PyOperation &operation = getOperation(); 847 operation.checkValid(); 848 if (fileObject.is_none()) 849 fileObject = py::module::import("sys").attr("stdout"); 850 851 if (!assumeVerified && !printGenericOpForm && 852 !mlirOperationVerify(operation)) { 853 std::string message("// Verification failed, printing generic form\n"); 854 if (binary) { 855 fileObject.attr("write")(py::bytes(message)); 856 } else { 857 fileObject.attr("write")(py::str(message)); 858 } 859 printGenericOpForm = true; 860 } 861 862 MlirOpPrintingFlags flags = mlirOpPrintingFlagsCreate(); 863 if (largeElementsLimit) 864 mlirOpPrintingFlagsElideLargeElementsAttrs(flags, *largeElementsLimit); 865 if (enableDebugInfo) 866 mlirOpPrintingFlagsEnableDebugInfo(flags, /*prettyForm=*/prettyDebugInfo); 867 if (printGenericOpForm) 868 mlirOpPrintingFlagsPrintGenericOpForm(flags); 869 870 PyFileAccumulator accum(fileObject, binary); 871 py::gil_scoped_release(); 872 mlirOperationPrintWithFlags(operation, flags, accum.getCallback(), 873 accum.getUserData()); 874 mlirOpPrintingFlagsDestroy(flags); 875 } 876 877 py::object PyOperationBase::getAsm(bool binary, 878 llvm::Optional<int64_t> largeElementsLimit, 879 bool enableDebugInfo, bool prettyDebugInfo, 880 bool printGenericOpForm, bool useLocalScope, 881 bool assumeVerified) { 882 py::object fileObject; 883 if (binary) { 884 fileObject = py::module::import("io").attr("BytesIO")(); 885 } else { 886 fileObject = py::module::import("io").attr("StringIO")(); 887 } 888 print(fileObject, /*binary=*/binary, 889 /*largeElementsLimit=*/largeElementsLimit, 890 /*enableDebugInfo=*/enableDebugInfo, 891 /*prettyDebugInfo=*/prettyDebugInfo, 892 /*printGenericOpForm=*/printGenericOpForm, 893 /*useLocalScope=*/useLocalScope, 894 /*assumeVerified=*/assumeVerified); 895 896 return fileObject.attr("getvalue")(); 897 } 898 899 void PyOperationBase::moveAfter(PyOperationBase &other) { 900 PyOperation &operation = getOperation(); 901 PyOperation &otherOp = other.getOperation(); 902 operation.checkValid(); 903 otherOp.checkValid(); 904 mlirOperationMoveAfter(operation, otherOp); 905 operation.parentKeepAlive = otherOp.parentKeepAlive; 906 } 907 908 void PyOperationBase::moveBefore(PyOperationBase &other) { 909 PyOperation &operation = getOperation(); 910 PyOperation &otherOp = other.getOperation(); 911 operation.checkValid(); 912 otherOp.checkValid(); 913 mlirOperationMoveBefore(operation, otherOp); 914 operation.parentKeepAlive = otherOp.parentKeepAlive; 915 } 916 917 llvm::Optional<PyOperationRef> PyOperation::getParentOperation() { 918 checkValid(); 919 if (!isAttached()) 920 throw SetPyError(PyExc_ValueError, "Detached operations have no parent"); 921 MlirOperation operation = mlirOperationGetParentOperation(get()); 922 if (mlirOperationIsNull(operation)) 923 return {}; 924 return PyOperation::forOperation(getContext(), operation); 925 } 926 927 PyBlock PyOperation::getBlock() { 928 checkValid(); 929 llvm::Optional<PyOperationRef> parentOperation = getParentOperation(); 930 MlirBlock block = mlirOperationGetBlock(get()); 931 assert(!mlirBlockIsNull(block) && "Attached operation has null parent"); 932 assert(parentOperation && "Operation has no parent"); 933 return PyBlock{std::move(*parentOperation), block}; 934 } 935 936 py::object PyOperation::getCapsule() { 937 checkValid(); 938 return py::reinterpret_steal<py::object>(mlirPythonOperationToCapsule(get())); 939 } 940 941 py::object PyOperation::createFromCapsule(py::object capsule) { 942 MlirOperation rawOperation = mlirPythonCapsuleToOperation(capsule.ptr()); 943 if (mlirOperationIsNull(rawOperation)) 944 throw py::error_already_set(); 945 MlirContext rawCtxt = mlirOperationGetContext(rawOperation); 946 return forOperation(PyMlirContext::forContext(rawCtxt), rawOperation) 947 .releaseObject(); 948 } 949 950 py::object PyOperation::create( 951 const std::string &name, llvm::Optional<std::vector<PyType *>> results, 952 llvm::Optional<std::vector<PyValue *>> operands, 953 llvm::Optional<py::dict> attributes, 954 llvm::Optional<std::vector<PyBlock *>> successors, int regions, 955 DefaultingPyLocation location, const py::object &maybeIp) { 956 llvm::SmallVector<MlirValue, 4> mlirOperands; 957 llvm::SmallVector<MlirType, 4> mlirResults; 958 llvm::SmallVector<MlirBlock, 4> mlirSuccessors; 959 llvm::SmallVector<std::pair<std::string, MlirAttribute>, 4> mlirAttributes; 960 961 // General parameter validation. 962 if (regions < 0) 963 throw SetPyError(PyExc_ValueError, "number of regions must be >= 0"); 964 965 // Unpack/validate operands. 966 if (operands) { 967 mlirOperands.reserve(operands->size()); 968 for (PyValue *operand : *operands) { 969 if (!operand) 970 throw SetPyError(PyExc_ValueError, "operand value cannot be None"); 971 mlirOperands.push_back(operand->get()); 972 } 973 } 974 975 // Unpack/validate results. 976 if (results) { 977 mlirResults.reserve(results->size()); 978 for (PyType *result : *results) { 979 // TODO: Verify result type originate from the same context. 980 if (!result) 981 throw SetPyError(PyExc_ValueError, "result type cannot be None"); 982 mlirResults.push_back(*result); 983 } 984 } 985 // Unpack/validate attributes. 986 if (attributes) { 987 mlirAttributes.reserve(attributes->size()); 988 for (auto &it : *attributes) { 989 std::string key; 990 try { 991 key = it.first.cast<std::string>(); 992 } catch (py::cast_error &err) { 993 std::string msg = "Invalid attribute key (not a string) when " 994 "attempting to create the operation \"" + 995 name + "\" (" + err.what() + ")"; 996 throw py::cast_error(msg); 997 } 998 try { 999 auto &attribute = it.second.cast<PyAttribute &>(); 1000 // TODO: Verify attribute originates from the same context. 1001 mlirAttributes.emplace_back(std::move(key), attribute); 1002 } catch (py::reference_cast_error &) { 1003 // This exception seems thrown when the value is "None". 1004 std::string msg = 1005 "Found an invalid (`None`?) attribute value for the key \"" + key + 1006 "\" when attempting to create the operation \"" + name + "\""; 1007 throw py::cast_error(msg); 1008 } catch (py::cast_error &err) { 1009 std::string msg = "Invalid attribute value for the key \"" + key + 1010 "\" when attempting to create the operation \"" + 1011 name + "\" (" + err.what() + ")"; 1012 throw py::cast_error(msg); 1013 } 1014 } 1015 } 1016 // Unpack/validate successors. 1017 if (successors) { 1018 mlirSuccessors.reserve(successors->size()); 1019 for (auto *successor : *successors) { 1020 // TODO: Verify successor originate from the same context. 1021 if (!successor) 1022 throw SetPyError(PyExc_ValueError, "successor block cannot be None"); 1023 mlirSuccessors.push_back(successor->get()); 1024 } 1025 } 1026 1027 // Apply unpacked/validated to the operation state. Beyond this 1028 // point, exceptions cannot be thrown or else the state will leak. 1029 MlirOperationState state = 1030 mlirOperationStateGet(toMlirStringRef(name), location); 1031 if (!mlirOperands.empty()) 1032 mlirOperationStateAddOperands(&state, mlirOperands.size(), 1033 mlirOperands.data()); 1034 if (!mlirResults.empty()) 1035 mlirOperationStateAddResults(&state, mlirResults.size(), 1036 mlirResults.data()); 1037 if (!mlirAttributes.empty()) { 1038 // Note that the attribute names directly reference bytes in 1039 // mlirAttributes, so that vector must not be changed from here 1040 // on. 1041 llvm::SmallVector<MlirNamedAttribute, 4> mlirNamedAttributes; 1042 mlirNamedAttributes.reserve(mlirAttributes.size()); 1043 for (auto &it : mlirAttributes) 1044 mlirNamedAttributes.push_back(mlirNamedAttributeGet( 1045 mlirIdentifierGet(mlirAttributeGetContext(it.second), 1046 toMlirStringRef(it.first)), 1047 it.second)); 1048 mlirOperationStateAddAttributes(&state, mlirNamedAttributes.size(), 1049 mlirNamedAttributes.data()); 1050 } 1051 if (!mlirSuccessors.empty()) 1052 mlirOperationStateAddSuccessors(&state, mlirSuccessors.size(), 1053 mlirSuccessors.data()); 1054 if (regions) { 1055 llvm::SmallVector<MlirRegion, 4> mlirRegions; 1056 mlirRegions.resize(regions); 1057 for (int i = 0; i < regions; ++i) 1058 mlirRegions[i] = mlirRegionCreate(); 1059 mlirOperationStateAddOwnedRegions(&state, mlirRegions.size(), 1060 mlirRegions.data()); 1061 } 1062 1063 // Construct the operation. 1064 MlirOperation operation = mlirOperationCreate(&state); 1065 PyOperationRef created = 1066 PyOperation::createDetached(location->getContext(), operation); 1067 1068 // InsertPoint active? 1069 if (!maybeIp.is(py::cast(false))) { 1070 PyInsertionPoint *ip; 1071 if (maybeIp.is_none()) { 1072 ip = PyThreadContextEntry::getDefaultInsertionPoint(); 1073 } else { 1074 ip = py::cast<PyInsertionPoint *>(maybeIp); 1075 } 1076 if (ip) 1077 ip->insert(*created.get()); 1078 } 1079 1080 return created->createOpView(); 1081 } 1082 1083 py::object PyOperation::createOpView() { 1084 checkValid(); 1085 MlirIdentifier ident = mlirOperationGetName(get()); 1086 MlirStringRef identStr = mlirIdentifierStr(ident); 1087 auto opViewClass = PyGlobals::get().lookupRawOpViewClass( 1088 StringRef(identStr.data, identStr.length)); 1089 if (opViewClass) 1090 return (*opViewClass)(getRef().getObject()); 1091 return py::cast(PyOpView(getRef().getObject())); 1092 } 1093 1094 void PyOperation::erase() { 1095 checkValid(); 1096 // TODO: Fix memory hazards when erasing a tree of operations for which a deep 1097 // Python reference to a child operation is live. All children should also 1098 // have their `valid` bit set to false. 1099 auto &liveOperations = getContext()->liveOperations; 1100 if (liveOperations.count(operation.ptr)) 1101 liveOperations.erase(operation.ptr); 1102 mlirOperationDestroy(operation); 1103 valid = false; 1104 } 1105 1106 //------------------------------------------------------------------------------ 1107 // PyOpView 1108 //------------------------------------------------------------------------------ 1109 1110 py::object 1111 PyOpView::buildGeneric(const py::object &cls, py::list resultTypeList, 1112 py::list operandList, 1113 llvm::Optional<py::dict> attributes, 1114 llvm::Optional<std::vector<PyBlock *>> successors, 1115 llvm::Optional<int> regions, 1116 DefaultingPyLocation location, py::object maybeIp) { 1117 PyMlirContextRef context = location->getContext(); 1118 // Class level operation construction metadata. 1119 std::string name = py::cast<std::string>(cls.attr("OPERATION_NAME")); 1120 // Operand and result segment specs are either none, which does no 1121 // variadic unpacking, or a list of ints with segment sizes, where each 1122 // element is either a positive number (typically 1 for a scalar) or -1 to 1123 // indicate that it is derived from the length of the same-indexed operand 1124 // or result (implying that it is a list at that position). 1125 py::object operandSegmentSpecObj = cls.attr("_ODS_OPERAND_SEGMENTS"); 1126 py::object resultSegmentSpecObj = cls.attr("_ODS_RESULT_SEGMENTS"); 1127 1128 std::vector<uint32_t> operandSegmentLengths; 1129 std::vector<uint32_t> resultSegmentLengths; 1130 1131 // Validate/determine region count. 1132 auto opRegionSpec = py::cast<std::tuple<int, bool>>(cls.attr("_ODS_REGIONS")); 1133 int opMinRegionCount = std::get<0>(opRegionSpec); 1134 bool opHasNoVariadicRegions = std::get<1>(opRegionSpec); 1135 if (!regions) { 1136 regions = opMinRegionCount; 1137 } 1138 if (*regions < opMinRegionCount) { 1139 throw py::value_error( 1140 (llvm::Twine("Operation \"") + name + "\" requires a minimum of " + 1141 llvm::Twine(opMinRegionCount) + 1142 " regions but was built with regions=" + llvm::Twine(*regions)) 1143 .str()); 1144 } 1145 if (opHasNoVariadicRegions && *regions > opMinRegionCount) { 1146 throw py::value_error( 1147 (llvm::Twine("Operation \"") + name + "\" requires a maximum of " + 1148 llvm::Twine(opMinRegionCount) + 1149 " regions but was built with regions=" + llvm::Twine(*regions)) 1150 .str()); 1151 } 1152 1153 // Unpack results. 1154 std::vector<PyType *> resultTypes; 1155 resultTypes.reserve(resultTypeList.size()); 1156 if (resultSegmentSpecObj.is_none()) { 1157 // Non-variadic result unpacking. 1158 for (const auto &it : llvm::enumerate(resultTypeList)) { 1159 try { 1160 resultTypes.push_back(py::cast<PyType *>(it.value())); 1161 if (!resultTypes.back()) 1162 throw py::cast_error(); 1163 } catch (py::cast_error &err) { 1164 throw py::value_error((llvm::Twine("Result ") + 1165 llvm::Twine(it.index()) + " of operation \"" + 1166 name + "\" must be a Type (" + err.what() + ")") 1167 .str()); 1168 } 1169 } 1170 } else { 1171 // Sized result unpacking. 1172 auto resultSegmentSpec = py::cast<std::vector<int>>(resultSegmentSpecObj); 1173 if (resultSegmentSpec.size() != resultTypeList.size()) { 1174 throw py::value_error((llvm::Twine("Operation \"") + name + 1175 "\" requires " + 1176 llvm::Twine(resultSegmentSpec.size()) + 1177 " result segments but was provided " + 1178 llvm::Twine(resultTypeList.size())) 1179 .str()); 1180 } 1181 resultSegmentLengths.reserve(resultTypeList.size()); 1182 for (const auto &it : 1183 llvm::enumerate(llvm::zip(resultTypeList, resultSegmentSpec))) { 1184 int segmentSpec = std::get<1>(it.value()); 1185 if (segmentSpec == 1 || segmentSpec == 0) { 1186 // Unpack unary element. 1187 try { 1188 auto *resultType = py::cast<PyType *>(std::get<0>(it.value())); 1189 if (resultType) { 1190 resultTypes.push_back(resultType); 1191 resultSegmentLengths.push_back(1); 1192 } else if (segmentSpec == 0) { 1193 // Allowed to be optional. 1194 resultSegmentLengths.push_back(0); 1195 } else { 1196 throw py::cast_error("was None and result is not optional"); 1197 } 1198 } catch (py::cast_error &err) { 1199 throw py::value_error((llvm::Twine("Result ") + 1200 llvm::Twine(it.index()) + " of operation \"" + 1201 name + "\" must be a Type (" + err.what() + 1202 ")") 1203 .str()); 1204 } 1205 } else if (segmentSpec == -1) { 1206 // Unpack sequence by appending. 1207 try { 1208 if (std::get<0>(it.value()).is_none()) { 1209 // Treat it as an empty list. 1210 resultSegmentLengths.push_back(0); 1211 } else { 1212 // Unpack the list. 1213 auto segment = py::cast<py::sequence>(std::get<0>(it.value())); 1214 for (py::object segmentItem : segment) { 1215 resultTypes.push_back(py::cast<PyType *>(segmentItem)); 1216 if (!resultTypes.back()) { 1217 throw py::cast_error("contained a None item"); 1218 } 1219 } 1220 resultSegmentLengths.push_back(segment.size()); 1221 } 1222 } catch (std::exception &err) { 1223 // NOTE: Sloppy to be using a catch-all here, but there are at least 1224 // three different unrelated exceptions that can be thrown in the 1225 // above "casts". Just keep the scope above small and catch them all. 1226 throw py::value_error((llvm::Twine("Result ") + 1227 llvm::Twine(it.index()) + " of operation \"" + 1228 name + "\" must be a Sequence of Types (" + 1229 err.what() + ")") 1230 .str()); 1231 } 1232 } else { 1233 throw py::value_error("Unexpected segment spec"); 1234 } 1235 } 1236 } 1237 1238 // Unpack operands. 1239 std::vector<PyValue *> operands; 1240 operands.reserve(operands.size()); 1241 if (operandSegmentSpecObj.is_none()) { 1242 // Non-sized operand unpacking. 1243 for (const auto &it : llvm::enumerate(operandList)) { 1244 try { 1245 operands.push_back(py::cast<PyValue *>(it.value())); 1246 if (!operands.back()) 1247 throw py::cast_error(); 1248 } catch (py::cast_error &err) { 1249 throw py::value_error((llvm::Twine("Operand ") + 1250 llvm::Twine(it.index()) + " of operation \"" + 1251 name + "\" must be a Value (" + err.what() + ")") 1252 .str()); 1253 } 1254 } 1255 } else { 1256 // Sized operand unpacking. 1257 auto operandSegmentSpec = py::cast<std::vector<int>>(operandSegmentSpecObj); 1258 if (operandSegmentSpec.size() != operandList.size()) { 1259 throw py::value_error((llvm::Twine("Operation \"") + name + 1260 "\" requires " + 1261 llvm::Twine(operandSegmentSpec.size()) + 1262 "operand segments but was provided " + 1263 llvm::Twine(operandList.size())) 1264 .str()); 1265 } 1266 operandSegmentLengths.reserve(operandList.size()); 1267 for (const auto &it : 1268 llvm::enumerate(llvm::zip(operandList, operandSegmentSpec))) { 1269 int segmentSpec = std::get<1>(it.value()); 1270 if (segmentSpec == 1 || segmentSpec == 0) { 1271 // Unpack unary element. 1272 try { 1273 auto *operandValue = py::cast<PyValue *>(std::get<0>(it.value())); 1274 if (operandValue) { 1275 operands.push_back(operandValue); 1276 operandSegmentLengths.push_back(1); 1277 } else if (segmentSpec == 0) { 1278 // Allowed to be optional. 1279 operandSegmentLengths.push_back(0); 1280 } else { 1281 throw py::cast_error("was None and operand is not optional"); 1282 } 1283 } catch (py::cast_error &err) { 1284 throw py::value_error((llvm::Twine("Operand ") + 1285 llvm::Twine(it.index()) + " of operation \"" + 1286 name + "\" must be a Value (" + err.what() + 1287 ")") 1288 .str()); 1289 } 1290 } else if (segmentSpec == -1) { 1291 // Unpack sequence by appending. 1292 try { 1293 if (std::get<0>(it.value()).is_none()) { 1294 // Treat it as an empty list. 1295 operandSegmentLengths.push_back(0); 1296 } else { 1297 // Unpack the list. 1298 auto segment = py::cast<py::sequence>(std::get<0>(it.value())); 1299 for (py::object segmentItem : segment) { 1300 operands.push_back(py::cast<PyValue *>(segmentItem)); 1301 if (!operands.back()) { 1302 throw py::cast_error("contained a None item"); 1303 } 1304 } 1305 operandSegmentLengths.push_back(segment.size()); 1306 } 1307 } catch (std::exception &err) { 1308 // NOTE: Sloppy to be using a catch-all here, but there are at least 1309 // three different unrelated exceptions that can be thrown in the 1310 // above "casts". Just keep the scope above small and catch them all. 1311 throw py::value_error((llvm::Twine("Operand ") + 1312 llvm::Twine(it.index()) + " of operation \"" + 1313 name + "\" must be a Sequence of Values (" + 1314 err.what() + ")") 1315 .str()); 1316 } 1317 } else { 1318 throw py::value_error("Unexpected segment spec"); 1319 } 1320 } 1321 } 1322 1323 // Merge operand/result segment lengths into attributes if needed. 1324 if (!operandSegmentLengths.empty() || !resultSegmentLengths.empty()) { 1325 // Dup. 1326 if (attributes) { 1327 attributes = py::dict(*attributes); 1328 } else { 1329 attributes = py::dict(); 1330 } 1331 if (attributes->contains("result_segment_sizes") || 1332 attributes->contains("operand_segment_sizes")) { 1333 throw py::value_error("Manually setting a 'result_segment_sizes' or " 1334 "'operand_segment_sizes' attribute is unsupported. " 1335 "Use Operation.create for such low-level access."); 1336 } 1337 1338 // Add result_segment_sizes attribute. 1339 if (!resultSegmentLengths.empty()) { 1340 int64_t size = resultSegmentLengths.size(); 1341 MlirAttribute segmentLengthAttr = mlirDenseElementsAttrUInt32Get( 1342 mlirVectorTypeGet(1, &size, mlirIntegerTypeGet(context->get(), 32)), 1343 resultSegmentLengths.size(), resultSegmentLengths.data()); 1344 (*attributes)["result_segment_sizes"] = 1345 PyAttribute(context, segmentLengthAttr); 1346 } 1347 1348 // Add operand_segment_sizes attribute. 1349 if (!operandSegmentLengths.empty()) { 1350 int64_t size = operandSegmentLengths.size(); 1351 MlirAttribute segmentLengthAttr = mlirDenseElementsAttrUInt32Get( 1352 mlirVectorTypeGet(1, &size, mlirIntegerTypeGet(context->get(), 32)), 1353 operandSegmentLengths.size(), operandSegmentLengths.data()); 1354 (*attributes)["operand_segment_sizes"] = 1355 PyAttribute(context, segmentLengthAttr); 1356 } 1357 } 1358 1359 // Delegate to create. 1360 return PyOperation::create(std::move(name), 1361 /*results=*/std::move(resultTypes), 1362 /*operands=*/std::move(operands), 1363 /*attributes=*/std::move(attributes), 1364 /*successors=*/std::move(successors), 1365 /*regions=*/*regions, location, 1366 std::move(maybeIp)); 1367 } 1368 1369 PyOpView::PyOpView(const py::object &operationObject) 1370 // Casting through the PyOperationBase base-class and then back to the 1371 // Operation lets us accept any PyOperationBase subclass. 1372 : operation(py::cast<PyOperationBase &>(operationObject).getOperation()), 1373 operationObject(operation.getRef().getObject()) {} 1374 1375 py::object PyOpView::createRawSubclass(const py::object &userClass) { 1376 // This is... a little gross. The typical pattern is to have a pure python 1377 // class that extends OpView like: 1378 // class AddFOp(_cext.ir.OpView): 1379 // def __init__(self, loc, lhs, rhs): 1380 // operation = loc.context.create_operation( 1381 // "addf", lhs, rhs, results=[lhs.type]) 1382 // super().__init__(operation) 1383 // 1384 // I.e. The goal of the user facing type is to provide a nice constructor 1385 // that has complete freedom for the op under construction. This is at odds 1386 // with our other desire to sometimes create this object by just passing an 1387 // operation (to initialize the base class). We could do *arg and **kwargs 1388 // munging to try to make it work, but instead, we synthesize a new class 1389 // on the fly which extends this user class (AddFOp in this example) and 1390 // *give it* the base class's __init__ method, thus bypassing the 1391 // intermediate subclass's __init__ method entirely. While slightly, 1392 // underhanded, this is safe/legal because the type hierarchy has not changed 1393 // (we just added a new leaf) and we aren't mucking around with __new__. 1394 // Typically, this new class will be stored on the original as "_Raw" and will 1395 // be used for casts and other things that need a variant of the class that 1396 // is initialized purely from an operation. 1397 py::object parentMetaclass = 1398 py::reinterpret_borrow<py::object>((PyObject *)&PyType_Type); 1399 py::dict attributes; 1400 // TODO: pybind11 2.6 supports a more direct form. Upgrade many years from 1401 // now. 1402 // auto opViewType = py::type::of<PyOpView>(); 1403 auto opViewType = py::detail::get_type_handle(typeid(PyOpView), true); 1404 attributes["__init__"] = opViewType.attr("__init__"); 1405 py::str origName = userClass.attr("__name__"); 1406 py::str newName = py::str("_") + origName; 1407 return parentMetaclass(newName, py::make_tuple(userClass), attributes); 1408 } 1409 1410 //------------------------------------------------------------------------------ 1411 // PyInsertionPoint. 1412 //------------------------------------------------------------------------------ 1413 1414 PyInsertionPoint::PyInsertionPoint(PyBlock &block) : block(block) {} 1415 1416 PyInsertionPoint::PyInsertionPoint(PyOperationBase &beforeOperationBase) 1417 : refOperation(beforeOperationBase.getOperation().getRef()), 1418 block((*refOperation)->getBlock()) {} 1419 1420 void PyInsertionPoint::insert(PyOperationBase &operationBase) { 1421 PyOperation &operation = operationBase.getOperation(); 1422 if (operation.isAttached()) 1423 throw SetPyError(PyExc_ValueError, 1424 "Attempt to insert operation that is already attached"); 1425 block.getParentOperation()->checkValid(); 1426 MlirOperation beforeOp = {nullptr}; 1427 if (refOperation) { 1428 // Insert before operation. 1429 (*refOperation)->checkValid(); 1430 beforeOp = (*refOperation)->get(); 1431 } else { 1432 // Insert at end (before null) is only valid if the block does not 1433 // already end in a known terminator (violating this will cause assertion 1434 // failures later). 1435 if (!mlirOperationIsNull(mlirBlockGetTerminator(block.get()))) { 1436 throw py::index_error("Cannot insert operation at the end of a block " 1437 "that already has a terminator. Did you mean to " 1438 "use 'InsertionPoint.at_block_terminator(block)' " 1439 "versus 'InsertionPoint(block)'?"); 1440 } 1441 } 1442 mlirBlockInsertOwnedOperationBefore(block.get(), beforeOp, operation); 1443 operation.setAttached(); 1444 } 1445 1446 PyInsertionPoint PyInsertionPoint::atBlockBegin(PyBlock &block) { 1447 MlirOperation firstOp = mlirBlockGetFirstOperation(block.get()); 1448 if (mlirOperationIsNull(firstOp)) { 1449 // Just insert at end. 1450 return PyInsertionPoint(block); 1451 } 1452 1453 // Insert before first op. 1454 PyOperationRef firstOpRef = PyOperation::forOperation( 1455 block.getParentOperation()->getContext(), firstOp); 1456 return PyInsertionPoint{block, std::move(firstOpRef)}; 1457 } 1458 1459 PyInsertionPoint PyInsertionPoint::atBlockTerminator(PyBlock &block) { 1460 MlirOperation terminator = mlirBlockGetTerminator(block.get()); 1461 if (mlirOperationIsNull(terminator)) 1462 throw SetPyError(PyExc_ValueError, "Block has no terminator"); 1463 PyOperationRef terminatorOpRef = PyOperation::forOperation( 1464 block.getParentOperation()->getContext(), terminator); 1465 return PyInsertionPoint{block, std::move(terminatorOpRef)}; 1466 } 1467 1468 py::object PyInsertionPoint::contextEnter() { 1469 return PyThreadContextEntry::pushInsertionPoint(*this); 1470 } 1471 1472 void PyInsertionPoint::contextExit(const pybind11::object &excType, 1473 const pybind11::object &excVal, 1474 const pybind11::object &excTb) { 1475 PyThreadContextEntry::popInsertionPoint(*this); 1476 } 1477 1478 //------------------------------------------------------------------------------ 1479 // PyAttribute. 1480 //------------------------------------------------------------------------------ 1481 1482 bool PyAttribute::operator==(const PyAttribute &other) { 1483 return mlirAttributeEqual(attr, other.attr); 1484 } 1485 1486 py::object PyAttribute::getCapsule() { 1487 return py::reinterpret_steal<py::object>(mlirPythonAttributeToCapsule(*this)); 1488 } 1489 1490 PyAttribute PyAttribute::createFromCapsule(py::object capsule) { 1491 MlirAttribute rawAttr = mlirPythonCapsuleToAttribute(capsule.ptr()); 1492 if (mlirAttributeIsNull(rawAttr)) 1493 throw py::error_already_set(); 1494 return PyAttribute( 1495 PyMlirContext::forContext(mlirAttributeGetContext(rawAttr)), rawAttr); 1496 } 1497 1498 //------------------------------------------------------------------------------ 1499 // PyNamedAttribute. 1500 //------------------------------------------------------------------------------ 1501 1502 PyNamedAttribute::PyNamedAttribute(MlirAttribute attr, std::string ownedName) 1503 : ownedName(new std::string(std::move(ownedName))) { 1504 namedAttr = mlirNamedAttributeGet( 1505 mlirIdentifierGet(mlirAttributeGetContext(attr), 1506 toMlirStringRef(*this->ownedName)), 1507 attr); 1508 } 1509 1510 //------------------------------------------------------------------------------ 1511 // PyType. 1512 //------------------------------------------------------------------------------ 1513 1514 bool PyType::operator==(const PyType &other) { 1515 return mlirTypeEqual(type, other.type); 1516 } 1517 1518 py::object PyType::getCapsule() { 1519 return py::reinterpret_steal<py::object>(mlirPythonTypeToCapsule(*this)); 1520 } 1521 1522 PyType PyType::createFromCapsule(py::object capsule) { 1523 MlirType rawType = mlirPythonCapsuleToType(capsule.ptr()); 1524 if (mlirTypeIsNull(rawType)) 1525 throw py::error_already_set(); 1526 return PyType(PyMlirContext::forContext(mlirTypeGetContext(rawType)), 1527 rawType); 1528 } 1529 1530 //------------------------------------------------------------------------------ 1531 // PyValue and subclases. 1532 //------------------------------------------------------------------------------ 1533 1534 pybind11::object PyValue::getCapsule() { 1535 return py::reinterpret_steal<py::object>(mlirPythonValueToCapsule(get())); 1536 } 1537 1538 PyValue PyValue::createFromCapsule(pybind11::object capsule) { 1539 MlirValue value = mlirPythonCapsuleToValue(capsule.ptr()); 1540 if (mlirValueIsNull(value)) 1541 throw py::error_already_set(); 1542 MlirOperation owner; 1543 if (mlirValueIsAOpResult(value)) 1544 owner = mlirOpResultGetOwner(value); 1545 if (mlirValueIsABlockArgument(value)) 1546 owner = mlirBlockGetParentOperation(mlirBlockArgumentGetOwner(value)); 1547 if (mlirOperationIsNull(owner)) 1548 throw py::error_already_set(); 1549 MlirContext ctx = mlirOperationGetContext(owner); 1550 PyOperationRef ownerRef = 1551 PyOperation::forOperation(PyMlirContext::forContext(ctx), owner); 1552 return PyValue(ownerRef, value); 1553 } 1554 1555 //------------------------------------------------------------------------------ 1556 // PySymbolTable. 1557 //------------------------------------------------------------------------------ 1558 1559 PySymbolTable::PySymbolTable(PyOperationBase &operation) 1560 : operation(operation.getOperation().getRef()) { 1561 symbolTable = mlirSymbolTableCreate(operation.getOperation().get()); 1562 if (mlirSymbolTableIsNull(symbolTable)) { 1563 throw py::cast_error("Operation is not a Symbol Table."); 1564 } 1565 } 1566 1567 py::object PySymbolTable::dunderGetItem(const std::string &name) { 1568 operation->checkValid(); 1569 MlirOperation symbol = mlirSymbolTableLookup( 1570 symbolTable, mlirStringRefCreate(name.data(), name.length())); 1571 if (mlirOperationIsNull(symbol)) 1572 throw py::key_error("Symbol '" + name + "' not in the symbol table."); 1573 1574 return PyOperation::forOperation(operation->getContext(), symbol, 1575 operation.getObject()) 1576 ->createOpView(); 1577 } 1578 1579 void PySymbolTable::erase(PyOperationBase &symbol) { 1580 operation->checkValid(); 1581 symbol.getOperation().checkValid(); 1582 mlirSymbolTableErase(symbolTable, symbol.getOperation().get()); 1583 // The operation is also erased, so we must invalidate it. There may be Python 1584 // references to this operation so we don't want to delete it from the list of 1585 // live operations here. 1586 symbol.getOperation().valid = false; 1587 } 1588 1589 void PySymbolTable::dunderDel(const std::string &name) { 1590 py::object operation = dunderGetItem(name); 1591 erase(py::cast<PyOperationBase &>(operation)); 1592 } 1593 1594 PyAttribute PySymbolTable::insert(PyOperationBase &symbol) { 1595 operation->checkValid(); 1596 symbol.getOperation().checkValid(); 1597 MlirAttribute symbolAttr = mlirOperationGetAttributeByName( 1598 symbol.getOperation().get(), mlirSymbolTableGetSymbolAttributeName()); 1599 if (mlirAttributeIsNull(symbolAttr)) 1600 throw py::value_error("Expected operation to have a symbol name."); 1601 return PyAttribute( 1602 symbol.getOperation().getContext(), 1603 mlirSymbolTableInsert(symbolTable, symbol.getOperation().get())); 1604 } 1605 1606 PyAttribute PySymbolTable::getSymbolName(PyOperationBase &symbol) { 1607 // Op must already be a symbol. 1608 PyOperation &operation = symbol.getOperation(); 1609 operation.checkValid(); 1610 MlirStringRef attrName = mlirSymbolTableGetSymbolAttributeName(); 1611 MlirAttribute existingNameAttr = 1612 mlirOperationGetAttributeByName(operation.get(), attrName); 1613 if (mlirAttributeIsNull(existingNameAttr)) 1614 throw py::value_error("Expected operation to have a symbol name."); 1615 return PyAttribute(symbol.getOperation().getContext(), existingNameAttr); 1616 } 1617 1618 void PySymbolTable::setSymbolName(PyOperationBase &symbol, 1619 const std::string &name) { 1620 // Op must already be a symbol. 1621 PyOperation &operation = symbol.getOperation(); 1622 operation.checkValid(); 1623 MlirStringRef attrName = mlirSymbolTableGetSymbolAttributeName(); 1624 MlirAttribute existingNameAttr = 1625 mlirOperationGetAttributeByName(operation.get(), attrName); 1626 if (mlirAttributeIsNull(existingNameAttr)) 1627 throw py::value_error("Expected operation to have a symbol name."); 1628 MlirAttribute newNameAttr = 1629 mlirStringAttrGet(operation.getContext()->get(), toMlirStringRef(name)); 1630 mlirOperationSetAttributeByName(operation.get(), attrName, newNameAttr); 1631 } 1632 1633 PyAttribute PySymbolTable::getVisibility(PyOperationBase &symbol) { 1634 PyOperation &operation = symbol.getOperation(); 1635 operation.checkValid(); 1636 MlirStringRef attrName = mlirSymbolTableGetVisibilityAttributeName(); 1637 MlirAttribute existingVisAttr = 1638 mlirOperationGetAttributeByName(operation.get(), attrName); 1639 if (mlirAttributeIsNull(existingVisAttr)) 1640 throw py::value_error("Expected operation to have a symbol visibility."); 1641 return PyAttribute(symbol.getOperation().getContext(), existingVisAttr); 1642 } 1643 1644 void PySymbolTable::setVisibility(PyOperationBase &symbol, 1645 const std::string &visibility) { 1646 if (visibility != "public" && visibility != "private" && 1647 visibility != "nested") 1648 throw py::value_error( 1649 "Expected visibility to be 'public', 'private' or 'nested'"); 1650 PyOperation &operation = symbol.getOperation(); 1651 operation.checkValid(); 1652 MlirStringRef attrName = mlirSymbolTableGetVisibilityAttributeName(); 1653 MlirAttribute existingVisAttr = 1654 mlirOperationGetAttributeByName(operation.get(), attrName); 1655 if (mlirAttributeIsNull(existingVisAttr)) 1656 throw py::value_error("Expected operation to have a symbol visibility."); 1657 MlirAttribute newVisAttr = mlirStringAttrGet(operation.getContext()->get(), 1658 toMlirStringRef(visibility)); 1659 mlirOperationSetAttributeByName(operation.get(), attrName, newVisAttr); 1660 } 1661 1662 void PySymbolTable::replaceAllSymbolUses(const std::string &oldSymbol, 1663 const std::string &newSymbol, 1664 PyOperationBase &from) { 1665 PyOperation &fromOperation = from.getOperation(); 1666 fromOperation.checkValid(); 1667 if (mlirLogicalResultIsFailure(mlirSymbolTableReplaceAllSymbolUses( 1668 toMlirStringRef(oldSymbol), toMlirStringRef(newSymbol), 1669 from.getOperation()))) 1670 1671 throw py::value_error("Symbol rename failed"); 1672 } 1673 1674 void PySymbolTable::walkSymbolTables(PyOperationBase &from, 1675 bool allSymUsesVisible, 1676 py::object callback) { 1677 PyOperation &fromOperation = from.getOperation(); 1678 fromOperation.checkValid(); 1679 struct UserData { 1680 PyMlirContextRef context; 1681 py::object callback; 1682 bool gotException; 1683 std::string exceptionWhat; 1684 py::object exceptionType; 1685 }; 1686 UserData userData{ 1687 fromOperation.getContext(), std::move(callback), false, {}, {}}; 1688 mlirSymbolTableWalkSymbolTables( 1689 fromOperation.get(), allSymUsesVisible, 1690 [](MlirOperation foundOp, bool isVisible, void *calleeUserDataVoid) { 1691 UserData *calleeUserData = static_cast<UserData *>(calleeUserDataVoid); 1692 auto pyFoundOp = 1693 PyOperation::forOperation(calleeUserData->context, foundOp); 1694 if (calleeUserData->gotException) 1695 return; 1696 try { 1697 calleeUserData->callback(pyFoundOp.getObject(), isVisible); 1698 } catch (py::error_already_set &e) { 1699 calleeUserData->gotException = true; 1700 calleeUserData->exceptionWhat = e.what(); 1701 calleeUserData->exceptionType = e.type(); 1702 } 1703 }, 1704 static_cast<void *>(&userData)); 1705 if (userData.gotException) { 1706 std::string message("Exception raised in callback: "); 1707 message.append(userData.exceptionWhat); 1708 throw std::runtime_error(std::move(message)); 1709 } 1710 } 1711 1712 namespace { 1713 /// CRTP base class for Python MLIR values that subclass Value and should be 1714 /// castable from it. The value hierarchy is one level deep and is not supposed 1715 /// to accommodate other levels unless core MLIR changes. 1716 template <typename DerivedTy> 1717 class PyConcreteValue : public PyValue { 1718 public: 1719 // Derived classes must define statics for: 1720 // IsAFunctionTy isaFunction 1721 // const char *pyClassName 1722 // and redefine bindDerived. 1723 using ClassTy = py::class_<DerivedTy, PyValue>; 1724 using IsAFunctionTy = bool (*)(MlirValue); 1725 1726 PyConcreteValue() = default; 1727 PyConcreteValue(PyOperationRef operationRef, MlirValue value) 1728 : PyValue(operationRef, value) {} 1729 PyConcreteValue(PyValue &orig) 1730 : PyConcreteValue(orig.getParentOperation(), castFrom(orig)) {} 1731 1732 /// Attempts to cast the original value to the derived type and throws on 1733 /// type mismatches. 1734 static MlirValue castFrom(PyValue &orig) { 1735 if (!DerivedTy::isaFunction(orig.get())) { 1736 auto origRepr = py::repr(py::cast(orig)).cast<std::string>(); 1737 throw SetPyError(PyExc_ValueError, Twine("Cannot cast value to ") + 1738 DerivedTy::pyClassName + 1739 " (from " + origRepr + ")"); 1740 } 1741 return orig.get(); 1742 } 1743 1744 /// Binds the Python module objects to functions of this class. 1745 static void bind(py::module &m) { 1746 auto cls = ClassTy(m, DerivedTy::pyClassName, py::module_local()); 1747 cls.def(py::init<PyValue &>(), py::keep_alive<0, 1>(), py::arg("value")); 1748 cls.def_static( 1749 "isinstance", 1750 [](PyValue &otherValue) -> bool { 1751 return DerivedTy::isaFunction(otherValue); 1752 }, 1753 py::arg("other_value")); 1754 DerivedTy::bindDerived(cls); 1755 } 1756 1757 /// Implemented by derived classes to add methods to the Python subclass. 1758 static void bindDerived(ClassTy &m) {} 1759 }; 1760 1761 /// Python wrapper for MlirBlockArgument. 1762 class PyBlockArgument : public PyConcreteValue<PyBlockArgument> { 1763 public: 1764 static constexpr IsAFunctionTy isaFunction = mlirValueIsABlockArgument; 1765 static constexpr const char *pyClassName = "BlockArgument"; 1766 using PyConcreteValue::PyConcreteValue; 1767 1768 static void bindDerived(ClassTy &c) { 1769 c.def_property_readonly("owner", [](PyBlockArgument &self) { 1770 return PyBlock(self.getParentOperation(), 1771 mlirBlockArgumentGetOwner(self.get())); 1772 }); 1773 c.def_property_readonly("arg_number", [](PyBlockArgument &self) { 1774 return mlirBlockArgumentGetArgNumber(self.get()); 1775 }); 1776 c.def( 1777 "set_type", 1778 [](PyBlockArgument &self, PyType type) { 1779 return mlirBlockArgumentSetType(self.get(), type); 1780 }, 1781 py::arg("type")); 1782 } 1783 }; 1784 1785 /// Python wrapper for MlirOpResult. 1786 class PyOpResult : public PyConcreteValue<PyOpResult> { 1787 public: 1788 static constexpr IsAFunctionTy isaFunction = mlirValueIsAOpResult; 1789 static constexpr const char *pyClassName = "OpResult"; 1790 using PyConcreteValue::PyConcreteValue; 1791 1792 static void bindDerived(ClassTy &c) { 1793 c.def_property_readonly("owner", [](PyOpResult &self) { 1794 assert( 1795 mlirOperationEqual(self.getParentOperation()->get(), 1796 mlirOpResultGetOwner(self.get())) && 1797 "expected the owner of the value in Python to match that in the IR"); 1798 return self.getParentOperation().getObject(); 1799 }); 1800 c.def_property_readonly("result_number", [](PyOpResult &self) { 1801 return mlirOpResultGetResultNumber(self.get()); 1802 }); 1803 } 1804 }; 1805 1806 /// Returns the list of types of the values held by container. 1807 template <typename Container> 1808 static std::vector<PyType> getValueTypes(Container &container, 1809 PyMlirContextRef &context) { 1810 std::vector<PyType> result; 1811 result.reserve(container.getNumElements()); 1812 for (int i = 0, e = container.getNumElements(); i < e; ++i) { 1813 result.push_back( 1814 PyType(context, mlirValueGetType(container.getElement(i).get()))); 1815 } 1816 return result; 1817 } 1818 1819 /// A list of block arguments. Internally, these are stored as consecutive 1820 /// elements, random access is cheap. The argument list is associated with the 1821 /// operation that contains the block (detached blocks are not allowed in 1822 /// Python bindings) and extends its lifetime. 1823 class PyBlockArgumentList 1824 : public Sliceable<PyBlockArgumentList, PyBlockArgument> { 1825 public: 1826 static constexpr const char *pyClassName = "BlockArgumentList"; 1827 1828 PyBlockArgumentList(PyOperationRef operation, MlirBlock block, 1829 intptr_t startIndex = 0, intptr_t length = -1, 1830 intptr_t step = 1) 1831 : Sliceable(startIndex, 1832 length == -1 ? mlirBlockGetNumArguments(block) : length, 1833 step), 1834 operation(std::move(operation)), block(block) {} 1835 1836 /// Returns the number of arguments in the list. 1837 intptr_t getNumElements() { 1838 operation->checkValid(); 1839 return mlirBlockGetNumArguments(block); 1840 } 1841 1842 /// Returns `pos`-the element in the list. Asserts on out-of-bounds. 1843 PyBlockArgument getElement(intptr_t pos) { 1844 MlirValue argument = mlirBlockGetArgument(block, pos); 1845 return PyBlockArgument(operation, argument); 1846 } 1847 1848 /// Returns a sublist of this list. 1849 PyBlockArgumentList slice(intptr_t startIndex, intptr_t length, 1850 intptr_t step) { 1851 return PyBlockArgumentList(operation, block, startIndex, length, step); 1852 } 1853 1854 static void bindDerived(ClassTy &c) { 1855 c.def_property_readonly("types", [](PyBlockArgumentList &self) { 1856 return getValueTypes(self, self.operation->getContext()); 1857 }); 1858 } 1859 1860 private: 1861 PyOperationRef operation; 1862 MlirBlock block; 1863 }; 1864 1865 /// A list of operation operands. Internally, these are stored as consecutive 1866 /// elements, random access is cheap. The result list is associated with the 1867 /// operation whose results these are, and extends the lifetime of this 1868 /// operation. 1869 class PyOpOperandList : public Sliceable<PyOpOperandList, PyValue> { 1870 public: 1871 static constexpr const char *pyClassName = "OpOperandList"; 1872 1873 PyOpOperandList(PyOperationRef operation, intptr_t startIndex = 0, 1874 intptr_t length = -1, intptr_t step = 1) 1875 : Sliceable(startIndex, 1876 length == -1 ? mlirOperationGetNumOperands(operation->get()) 1877 : length, 1878 step), 1879 operation(operation) {} 1880 1881 intptr_t getNumElements() { 1882 operation->checkValid(); 1883 return mlirOperationGetNumOperands(operation->get()); 1884 } 1885 1886 PyValue getElement(intptr_t pos) { 1887 MlirValue operand = mlirOperationGetOperand(operation->get(), pos); 1888 MlirOperation owner; 1889 if (mlirValueIsAOpResult(operand)) 1890 owner = mlirOpResultGetOwner(operand); 1891 else if (mlirValueIsABlockArgument(operand)) 1892 owner = mlirBlockGetParentOperation(mlirBlockArgumentGetOwner(operand)); 1893 else 1894 assert(false && "Value must be an block arg or op result."); 1895 PyOperationRef pyOwner = 1896 PyOperation::forOperation(operation->getContext(), owner); 1897 return PyValue(pyOwner, operand); 1898 } 1899 1900 PyOpOperandList slice(intptr_t startIndex, intptr_t length, intptr_t step) { 1901 return PyOpOperandList(operation, startIndex, length, step); 1902 } 1903 1904 void dunderSetItem(intptr_t index, PyValue value) { 1905 index = wrapIndex(index); 1906 mlirOperationSetOperand(operation->get(), index, value.get()); 1907 } 1908 1909 static void bindDerived(ClassTy &c) { 1910 c.def("__setitem__", &PyOpOperandList::dunderSetItem); 1911 } 1912 1913 private: 1914 PyOperationRef operation; 1915 }; 1916 1917 /// A list of operation results. Internally, these are stored as consecutive 1918 /// elements, random access is cheap. The result list is associated with the 1919 /// operation whose results these are, and extends the lifetime of this 1920 /// operation. 1921 class PyOpResultList : public Sliceable<PyOpResultList, PyOpResult> { 1922 public: 1923 static constexpr const char *pyClassName = "OpResultList"; 1924 1925 PyOpResultList(PyOperationRef operation, intptr_t startIndex = 0, 1926 intptr_t length = -1, intptr_t step = 1) 1927 : Sliceable(startIndex, 1928 length == -1 ? mlirOperationGetNumResults(operation->get()) 1929 : length, 1930 step), 1931 operation(operation) {} 1932 1933 intptr_t getNumElements() { 1934 operation->checkValid(); 1935 return mlirOperationGetNumResults(operation->get()); 1936 } 1937 1938 PyOpResult getElement(intptr_t index) { 1939 PyValue value(operation, mlirOperationGetResult(operation->get(), index)); 1940 return PyOpResult(value); 1941 } 1942 1943 PyOpResultList slice(intptr_t startIndex, intptr_t length, intptr_t step) { 1944 return PyOpResultList(operation, startIndex, length, step); 1945 } 1946 1947 static void bindDerived(ClassTy &c) { 1948 c.def_property_readonly("types", [](PyOpResultList &self) { 1949 return getValueTypes(self, self.operation->getContext()); 1950 }); 1951 } 1952 1953 private: 1954 PyOperationRef operation; 1955 }; 1956 1957 /// A list of operation attributes. Can be indexed by name, producing 1958 /// attributes, or by index, producing named attributes. 1959 class PyOpAttributeMap { 1960 public: 1961 PyOpAttributeMap(PyOperationRef operation) 1962 : operation(std::move(operation)) {} 1963 1964 PyAttribute dunderGetItemNamed(const std::string &name) { 1965 MlirAttribute attr = mlirOperationGetAttributeByName(operation->get(), 1966 toMlirStringRef(name)); 1967 if (mlirAttributeIsNull(attr)) { 1968 throw SetPyError(PyExc_KeyError, 1969 "attempt to access a non-existent attribute"); 1970 } 1971 return PyAttribute(operation->getContext(), attr); 1972 } 1973 1974 PyNamedAttribute dunderGetItemIndexed(intptr_t index) { 1975 if (index < 0 || index >= dunderLen()) { 1976 throw SetPyError(PyExc_IndexError, 1977 "attempt to access out of bounds attribute"); 1978 } 1979 MlirNamedAttribute namedAttr = 1980 mlirOperationGetAttribute(operation->get(), index); 1981 return PyNamedAttribute( 1982 namedAttr.attribute, 1983 std::string(mlirIdentifierStr(namedAttr.name).data, 1984 mlirIdentifierStr(namedAttr.name).length)); 1985 } 1986 1987 void dunderSetItem(const std::string &name, const PyAttribute &attr) { 1988 mlirOperationSetAttributeByName(operation->get(), toMlirStringRef(name), 1989 attr); 1990 } 1991 1992 void dunderDelItem(const std::string &name) { 1993 int removed = mlirOperationRemoveAttributeByName(operation->get(), 1994 toMlirStringRef(name)); 1995 if (!removed) 1996 throw SetPyError(PyExc_KeyError, 1997 "attempt to delete a non-existent attribute"); 1998 } 1999 2000 intptr_t dunderLen() { 2001 return mlirOperationGetNumAttributes(operation->get()); 2002 } 2003 2004 bool dunderContains(const std::string &name) { 2005 return !mlirAttributeIsNull(mlirOperationGetAttributeByName( 2006 operation->get(), toMlirStringRef(name))); 2007 } 2008 2009 static void bind(py::module &m) { 2010 py::class_<PyOpAttributeMap>(m, "OpAttributeMap", py::module_local()) 2011 .def("__contains__", &PyOpAttributeMap::dunderContains) 2012 .def("__len__", &PyOpAttributeMap::dunderLen) 2013 .def("__getitem__", &PyOpAttributeMap::dunderGetItemNamed) 2014 .def("__getitem__", &PyOpAttributeMap::dunderGetItemIndexed) 2015 .def("__setitem__", &PyOpAttributeMap::dunderSetItem) 2016 .def("__delitem__", &PyOpAttributeMap::dunderDelItem); 2017 } 2018 2019 private: 2020 PyOperationRef operation; 2021 }; 2022 2023 } // namespace 2024 2025 //------------------------------------------------------------------------------ 2026 // Populates the core exports of the 'ir' submodule. 2027 //------------------------------------------------------------------------------ 2028 2029 void mlir::python::populateIRCore(py::module &m) { 2030 //---------------------------------------------------------------------------- 2031 // Mapping of MlirContext. 2032 //---------------------------------------------------------------------------- 2033 py::class_<PyMlirContext>(m, "Context", py::module_local()) 2034 .def(py::init<>(&PyMlirContext::createNewContextForInit)) 2035 .def_static("_get_live_count", &PyMlirContext::getLiveCount) 2036 .def("_get_context_again", 2037 [](PyMlirContext &self) { 2038 PyMlirContextRef ref = PyMlirContext::forContext(self.get()); 2039 return ref.releaseObject(); 2040 }) 2041 .def("_get_live_operation_count", &PyMlirContext::getLiveOperationCount) 2042 .def("_get_live_module_count", &PyMlirContext::getLiveModuleCount) 2043 .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, 2044 &PyMlirContext::getCapsule) 2045 .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyMlirContext::createFromCapsule) 2046 .def("__enter__", &PyMlirContext::contextEnter) 2047 .def("__exit__", &PyMlirContext::contextExit) 2048 .def_property_readonly_static( 2049 "current", 2050 [](py::object & /*class*/) { 2051 auto *context = PyThreadContextEntry::getDefaultContext(); 2052 if (!context) 2053 throw SetPyError(PyExc_ValueError, "No current Context"); 2054 return context; 2055 }, 2056 "Gets the Context bound to the current thread or raises ValueError") 2057 .def_property_readonly( 2058 "dialects", 2059 [](PyMlirContext &self) { return PyDialects(self.getRef()); }, 2060 "Gets a container for accessing dialects by name") 2061 .def_property_readonly( 2062 "d", [](PyMlirContext &self) { return PyDialects(self.getRef()); }, 2063 "Alias for 'dialect'") 2064 .def( 2065 "get_dialect_descriptor", 2066 [=](PyMlirContext &self, std::string &name) { 2067 MlirDialect dialect = mlirContextGetOrLoadDialect( 2068 self.get(), {name.data(), name.size()}); 2069 if (mlirDialectIsNull(dialect)) { 2070 throw SetPyError(PyExc_ValueError, 2071 Twine("Dialect '") + name + "' not found"); 2072 } 2073 return PyDialectDescriptor(self.getRef(), dialect); 2074 }, 2075 py::arg("dialect_name"), 2076 "Gets or loads a dialect by name, returning its descriptor object") 2077 .def_property( 2078 "allow_unregistered_dialects", 2079 [](PyMlirContext &self) -> bool { 2080 return mlirContextGetAllowUnregisteredDialects(self.get()); 2081 }, 2082 [](PyMlirContext &self, bool value) { 2083 mlirContextSetAllowUnregisteredDialects(self.get(), value); 2084 }) 2085 .def( 2086 "enable_multithreading", 2087 [](PyMlirContext &self, bool enable) { 2088 mlirContextEnableMultithreading(self.get(), enable); 2089 }, 2090 py::arg("enable")) 2091 .def( 2092 "is_registered_operation", 2093 [](PyMlirContext &self, std::string &name) { 2094 return mlirContextIsRegisteredOperation( 2095 self.get(), MlirStringRef{name.data(), name.size()}); 2096 }, 2097 py::arg("operation_name")); 2098 2099 //---------------------------------------------------------------------------- 2100 // Mapping of PyDialectDescriptor 2101 //---------------------------------------------------------------------------- 2102 py::class_<PyDialectDescriptor>(m, "DialectDescriptor", py::module_local()) 2103 .def_property_readonly("namespace", 2104 [](PyDialectDescriptor &self) { 2105 MlirStringRef ns = 2106 mlirDialectGetNamespace(self.get()); 2107 return py::str(ns.data, ns.length); 2108 }) 2109 .def("__repr__", [](PyDialectDescriptor &self) { 2110 MlirStringRef ns = mlirDialectGetNamespace(self.get()); 2111 std::string repr("<DialectDescriptor "); 2112 repr.append(ns.data, ns.length); 2113 repr.append(">"); 2114 return repr; 2115 }); 2116 2117 //---------------------------------------------------------------------------- 2118 // Mapping of PyDialects 2119 //---------------------------------------------------------------------------- 2120 py::class_<PyDialects>(m, "Dialects", py::module_local()) 2121 .def("__getitem__", 2122 [=](PyDialects &self, std::string keyName) { 2123 MlirDialect dialect = 2124 self.getDialectForKey(keyName, /*attrError=*/false); 2125 py::object descriptor = 2126 py::cast(PyDialectDescriptor{self.getContext(), dialect}); 2127 return createCustomDialectWrapper(keyName, std::move(descriptor)); 2128 }) 2129 .def("__getattr__", [=](PyDialects &self, std::string attrName) { 2130 MlirDialect dialect = 2131 self.getDialectForKey(attrName, /*attrError=*/true); 2132 py::object descriptor = 2133 py::cast(PyDialectDescriptor{self.getContext(), dialect}); 2134 return createCustomDialectWrapper(attrName, std::move(descriptor)); 2135 }); 2136 2137 //---------------------------------------------------------------------------- 2138 // Mapping of PyDialect 2139 //---------------------------------------------------------------------------- 2140 py::class_<PyDialect>(m, "Dialect", py::module_local()) 2141 .def(py::init<py::object>(), py::arg("descriptor")) 2142 .def_property_readonly( 2143 "descriptor", [](PyDialect &self) { return self.getDescriptor(); }) 2144 .def("__repr__", [](py::object self) { 2145 auto clazz = self.attr("__class__"); 2146 return py::str("<Dialect ") + 2147 self.attr("descriptor").attr("namespace") + py::str(" (class ") + 2148 clazz.attr("__module__") + py::str(".") + 2149 clazz.attr("__name__") + py::str(")>"); 2150 }); 2151 2152 //---------------------------------------------------------------------------- 2153 // Mapping of Location 2154 //---------------------------------------------------------------------------- 2155 py::class_<PyLocation>(m, "Location", py::module_local()) 2156 .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyLocation::getCapsule) 2157 .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyLocation::createFromCapsule) 2158 .def("__enter__", &PyLocation::contextEnter) 2159 .def("__exit__", &PyLocation::contextExit) 2160 .def("__eq__", 2161 [](PyLocation &self, PyLocation &other) -> bool { 2162 return mlirLocationEqual(self, other); 2163 }) 2164 .def("__eq__", [](PyLocation &self, py::object other) { return false; }) 2165 .def_property_readonly_static( 2166 "current", 2167 [](py::object & /*class*/) { 2168 auto *loc = PyThreadContextEntry::getDefaultLocation(); 2169 if (!loc) 2170 throw SetPyError(PyExc_ValueError, "No current Location"); 2171 return loc; 2172 }, 2173 "Gets the Location bound to the current thread or raises ValueError") 2174 .def_static( 2175 "unknown", 2176 [](DefaultingPyMlirContext context) { 2177 return PyLocation(context->getRef(), 2178 mlirLocationUnknownGet(context->get())); 2179 }, 2180 py::arg("context") = py::none(), 2181 "Gets a Location representing an unknown location") 2182 .def_static( 2183 "callsite", 2184 [](PyLocation callee, const std::vector<PyLocation> &frames, 2185 DefaultingPyMlirContext context) { 2186 if (frames.empty()) 2187 throw py::value_error("No caller frames provided"); 2188 MlirLocation caller = frames.back().get(); 2189 for (const PyLocation &frame : 2190 llvm::reverse(llvm::makeArrayRef(frames).drop_back())) 2191 caller = mlirLocationCallSiteGet(frame.get(), caller); 2192 return PyLocation(context->getRef(), 2193 mlirLocationCallSiteGet(callee.get(), caller)); 2194 }, 2195 py::arg("callee"), py::arg("frames"), py::arg("context") = py::none(), 2196 kContextGetCallSiteLocationDocstring) 2197 .def_static( 2198 "file", 2199 [](std::string filename, int line, int col, 2200 DefaultingPyMlirContext context) { 2201 return PyLocation( 2202 context->getRef(), 2203 mlirLocationFileLineColGet( 2204 context->get(), toMlirStringRef(filename), line, col)); 2205 }, 2206 py::arg("filename"), py::arg("line"), py::arg("col"), 2207 py::arg("context") = py::none(), kContextGetFileLocationDocstring) 2208 .def_static( 2209 "fused", 2210 [](const std::vector<PyLocation> &pyLocations, llvm::Optional<PyAttribute> metadata, 2211 DefaultingPyMlirContext context) { 2212 if (pyLocations.empty()) 2213 throw py::value_error("No locations provided"); 2214 llvm::SmallVector<MlirLocation, 4> locations; 2215 locations.reserve(pyLocations.size()); 2216 for (auto &pyLocation : pyLocations) 2217 locations.push_back(pyLocation.get()); 2218 MlirLocation location = mlirLocationFusedGet( 2219 context->get(), locations.size(), locations.data(), 2220 metadata ? metadata->get() : MlirAttribute{0}); 2221 return PyLocation(context->getRef(), location); 2222 }, 2223 py::arg("locations"), py::arg("metadata") = py::none(), 2224 py::arg("context") = py::none(), kContextGetFusedLocationDocstring) 2225 .def_static( 2226 "name", 2227 [](std::string name, llvm::Optional<PyLocation> childLoc, 2228 DefaultingPyMlirContext context) { 2229 return PyLocation( 2230 context->getRef(), 2231 mlirLocationNameGet( 2232 context->get(), toMlirStringRef(name), 2233 childLoc ? childLoc->get() 2234 : mlirLocationUnknownGet(context->get()))); 2235 }, 2236 py::arg("name"), py::arg("childLoc") = py::none(), 2237 py::arg("context") = py::none(), kContextGetNameLocationDocString) 2238 .def_property_readonly( 2239 "context", 2240 [](PyLocation &self) { return self.getContext().getObject(); }, 2241 "Context that owns the Location") 2242 .def("__repr__", [](PyLocation &self) { 2243 PyPrintAccumulator printAccum; 2244 mlirLocationPrint(self, printAccum.getCallback(), 2245 printAccum.getUserData()); 2246 return printAccum.join(); 2247 }); 2248 2249 //---------------------------------------------------------------------------- 2250 // Mapping of Module 2251 //---------------------------------------------------------------------------- 2252 py::class_<PyModule>(m, "Module", py::module_local()) 2253 .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyModule::getCapsule) 2254 .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyModule::createFromCapsule) 2255 .def_static( 2256 "parse", 2257 [](const std::string moduleAsm, DefaultingPyMlirContext context) { 2258 MlirModule module = mlirModuleCreateParse( 2259 context->get(), toMlirStringRef(moduleAsm)); 2260 // TODO: Rework error reporting once diagnostic engine is exposed 2261 // in C API. 2262 if (mlirModuleIsNull(module)) { 2263 throw SetPyError( 2264 PyExc_ValueError, 2265 "Unable to parse module assembly (see diagnostics)"); 2266 } 2267 return PyModule::forModule(module).releaseObject(); 2268 }, 2269 py::arg("asm"), py::arg("context") = py::none(), 2270 kModuleParseDocstring) 2271 .def_static( 2272 "create", 2273 [](DefaultingPyLocation loc) { 2274 MlirModule module = mlirModuleCreateEmpty(loc); 2275 return PyModule::forModule(module).releaseObject(); 2276 }, 2277 py::arg("loc") = py::none(), "Creates an empty module") 2278 .def_property_readonly( 2279 "context", 2280 [](PyModule &self) { return self.getContext().getObject(); }, 2281 "Context that created the Module") 2282 .def_property_readonly( 2283 "operation", 2284 [](PyModule &self) { 2285 return PyOperation::forOperation(self.getContext(), 2286 mlirModuleGetOperation(self.get()), 2287 self.getRef().releaseObject()) 2288 .releaseObject(); 2289 }, 2290 "Accesses the module as an operation") 2291 .def_property_readonly( 2292 "body", 2293 [](PyModule &self) { 2294 PyOperationRef moduleOp = PyOperation::forOperation( 2295 self.getContext(), mlirModuleGetOperation(self.get()), 2296 self.getRef().releaseObject()); 2297 PyBlock returnBlock(moduleOp, mlirModuleGetBody(self.get())); 2298 return returnBlock; 2299 }, 2300 "Return the block for this module") 2301 .def( 2302 "dump", 2303 [](PyModule &self) { 2304 mlirOperationDump(mlirModuleGetOperation(self.get())); 2305 }, 2306 kDumpDocstring) 2307 .def( 2308 "__str__", 2309 [](py::object self) { 2310 // Defer to the operation's __str__. 2311 return self.attr("operation").attr("__str__")(); 2312 }, 2313 kOperationStrDunderDocstring); 2314 2315 //---------------------------------------------------------------------------- 2316 // Mapping of Operation. 2317 //---------------------------------------------------------------------------- 2318 py::class_<PyOperationBase>(m, "_OperationBase", py::module_local()) 2319 .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, 2320 [](PyOperationBase &self) { 2321 return self.getOperation().getCapsule(); 2322 }) 2323 .def("__eq__", 2324 [](PyOperationBase &self, PyOperationBase &other) { 2325 return &self.getOperation() == &other.getOperation(); 2326 }) 2327 .def("__eq__", 2328 [](PyOperationBase &self, py::object other) { return false; }) 2329 .def("__hash__", 2330 [](PyOperationBase &self) { 2331 return static_cast<size_t>(llvm::hash_value(&self.getOperation())); 2332 }) 2333 .def_property_readonly("attributes", 2334 [](PyOperationBase &self) { 2335 return PyOpAttributeMap( 2336 self.getOperation().getRef()); 2337 }) 2338 .def_property_readonly("operands", 2339 [](PyOperationBase &self) { 2340 return PyOpOperandList( 2341 self.getOperation().getRef()); 2342 }) 2343 .def_property_readonly("regions", 2344 [](PyOperationBase &self) { 2345 return PyRegionList( 2346 self.getOperation().getRef()); 2347 }) 2348 .def_property_readonly( 2349 "results", 2350 [](PyOperationBase &self) { 2351 return PyOpResultList(self.getOperation().getRef()); 2352 }, 2353 "Returns the list of Operation results.") 2354 .def_property_readonly( 2355 "result", 2356 [](PyOperationBase &self) { 2357 auto &operation = self.getOperation(); 2358 auto numResults = mlirOperationGetNumResults(operation); 2359 if (numResults != 1) { 2360 auto name = mlirIdentifierStr(mlirOperationGetName(operation)); 2361 throw SetPyError( 2362 PyExc_ValueError, 2363 Twine("Cannot call .result on operation ") + 2364 StringRef(name.data, name.length) + " which has " + 2365 Twine(numResults) + 2366 " results (it is only valid for operations with a " 2367 "single result)"); 2368 } 2369 return PyOpResult(operation.getRef(), 2370 mlirOperationGetResult(operation, 0)); 2371 }, 2372 "Shortcut to get an op result if it has only one (throws an error " 2373 "otherwise).") 2374 .def_property_readonly( 2375 "location", 2376 [](PyOperationBase &self) { 2377 PyOperation &operation = self.getOperation(); 2378 return PyLocation(operation.getContext(), 2379 mlirOperationGetLocation(operation.get())); 2380 }, 2381 "Returns the source location the operation was defined or derived " 2382 "from.") 2383 .def( 2384 "__str__", 2385 [](PyOperationBase &self) { 2386 return self.getAsm(/*binary=*/false, 2387 /*largeElementsLimit=*/llvm::None, 2388 /*enableDebugInfo=*/false, 2389 /*prettyDebugInfo=*/false, 2390 /*printGenericOpForm=*/false, 2391 /*useLocalScope=*/false, 2392 /*assumeVerified=*/false); 2393 }, 2394 "Returns the assembly form of the operation.") 2395 .def("print", &PyOperationBase::print, 2396 // Careful: Lots of arguments must match up with print method. 2397 py::arg("file") = py::none(), py::arg("binary") = false, 2398 py::arg("large_elements_limit") = py::none(), 2399 py::arg("enable_debug_info") = false, 2400 py::arg("pretty_debug_info") = false, 2401 py::arg("print_generic_op_form") = false, 2402 py::arg("use_local_scope") = false, 2403 py::arg("assume_verified") = false, kOperationPrintDocstring) 2404 .def("get_asm", &PyOperationBase::getAsm, 2405 // Careful: Lots of arguments must match up with get_asm method. 2406 py::arg("binary") = false, 2407 py::arg("large_elements_limit") = py::none(), 2408 py::arg("enable_debug_info") = false, 2409 py::arg("pretty_debug_info") = false, 2410 py::arg("print_generic_op_form") = false, 2411 py::arg("use_local_scope") = false, 2412 py::arg("assume_verified") = false, kOperationGetAsmDocstring) 2413 .def( 2414 "verify", 2415 [](PyOperationBase &self) { 2416 return mlirOperationVerify(self.getOperation()); 2417 }, 2418 "Verify the operation and return true if it passes, false if it " 2419 "fails.") 2420 .def("move_after", &PyOperationBase::moveAfter, py::arg("other"), 2421 "Puts self immediately after the other operation in its parent " 2422 "block.") 2423 .def("move_before", &PyOperationBase::moveBefore, py::arg("other"), 2424 "Puts self immediately before the other operation in its parent " 2425 "block.") 2426 .def( 2427 "detach_from_parent", 2428 [](PyOperationBase &self) { 2429 PyOperation &operation = self.getOperation(); 2430 operation.checkValid(); 2431 if (!operation.isAttached()) 2432 throw py::value_error("Detached operation has no parent."); 2433 2434 operation.detachFromParent(); 2435 return operation.createOpView(); 2436 }, 2437 "Detaches the operation from its parent block."); 2438 2439 py::class_<PyOperation, PyOperationBase>(m, "Operation", py::module_local()) 2440 .def_static("create", &PyOperation::create, py::arg("name"), 2441 py::arg("results") = py::none(), 2442 py::arg("operands") = py::none(), 2443 py::arg("attributes") = py::none(), 2444 py::arg("successors") = py::none(), py::arg("regions") = 0, 2445 py::arg("loc") = py::none(), py::arg("ip") = py::none(), 2446 kOperationCreateDocstring) 2447 .def_property_readonly("parent", 2448 [](PyOperation &self) -> py::object { 2449 auto parent = self.getParentOperation(); 2450 if (parent) 2451 return parent->getObject(); 2452 return py::none(); 2453 }) 2454 .def("erase", &PyOperation::erase) 2455 .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, 2456 &PyOperation::getCapsule) 2457 .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyOperation::createFromCapsule) 2458 .def_property_readonly("name", 2459 [](PyOperation &self) { 2460 self.checkValid(); 2461 MlirOperation operation = self.get(); 2462 MlirStringRef name = mlirIdentifierStr( 2463 mlirOperationGetName(operation)); 2464 return py::str(name.data, name.length); 2465 }) 2466 .def_property_readonly( 2467 "context", 2468 [](PyOperation &self) { 2469 self.checkValid(); 2470 return self.getContext().getObject(); 2471 }, 2472 "Context that owns the Operation") 2473 .def_property_readonly("opview", &PyOperation::createOpView); 2474 2475 auto opViewClass = 2476 py::class_<PyOpView, PyOperationBase>(m, "OpView", py::module_local()) 2477 .def(py::init<py::object>(), py::arg("operation")) 2478 .def_property_readonly("operation", &PyOpView::getOperationObject) 2479 .def_property_readonly( 2480 "context", 2481 [](PyOpView &self) { 2482 return self.getOperation().getContext().getObject(); 2483 }, 2484 "Context that owns the Operation") 2485 .def("__str__", [](PyOpView &self) { 2486 return py::str(self.getOperationObject()); 2487 }); 2488 opViewClass.attr("_ODS_REGIONS") = py::make_tuple(0, true); 2489 opViewClass.attr("_ODS_OPERAND_SEGMENTS") = py::none(); 2490 opViewClass.attr("_ODS_RESULT_SEGMENTS") = py::none(); 2491 opViewClass.attr("build_generic") = classmethod( 2492 &PyOpView::buildGeneric, py::arg("cls"), py::arg("results") = py::none(), 2493 py::arg("operands") = py::none(), py::arg("attributes") = py::none(), 2494 py::arg("successors") = py::none(), py::arg("regions") = py::none(), 2495 py::arg("loc") = py::none(), py::arg("ip") = py::none(), 2496 "Builds a specific, generated OpView based on class level attributes."); 2497 2498 //---------------------------------------------------------------------------- 2499 // Mapping of PyRegion. 2500 //---------------------------------------------------------------------------- 2501 py::class_<PyRegion>(m, "Region", py::module_local()) 2502 .def_property_readonly( 2503 "blocks", 2504 [](PyRegion &self) { 2505 return PyBlockList(self.getParentOperation(), self.get()); 2506 }, 2507 "Returns a forward-optimized sequence of blocks.") 2508 .def_property_readonly( 2509 "owner", 2510 [](PyRegion &self) { 2511 return self.getParentOperation()->createOpView(); 2512 }, 2513 "Returns the operation owning this region.") 2514 .def( 2515 "__iter__", 2516 [](PyRegion &self) { 2517 self.checkValid(); 2518 MlirBlock firstBlock = mlirRegionGetFirstBlock(self.get()); 2519 return PyBlockIterator(self.getParentOperation(), firstBlock); 2520 }, 2521 "Iterates over blocks in the region.") 2522 .def("__eq__", 2523 [](PyRegion &self, PyRegion &other) { 2524 return self.get().ptr == other.get().ptr; 2525 }) 2526 .def("__eq__", [](PyRegion &self, py::object &other) { return false; }); 2527 2528 //---------------------------------------------------------------------------- 2529 // Mapping of PyBlock. 2530 //---------------------------------------------------------------------------- 2531 py::class_<PyBlock>(m, "Block", py::module_local()) 2532 .def_property_readonly( 2533 "owner", 2534 [](PyBlock &self) { 2535 return self.getParentOperation()->createOpView(); 2536 }, 2537 "Returns the owning operation of this block.") 2538 .def_property_readonly( 2539 "region", 2540 [](PyBlock &self) { 2541 MlirRegion region = mlirBlockGetParentRegion(self.get()); 2542 return PyRegion(self.getParentOperation(), region); 2543 }, 2544 "Returns the owning region of this block.") 2545 .def_property_readonly( 2546 "arguments", 2547 [](PyBlock &self) { 2548 return PyBlockArgumentList(self.getParentOperation(), self.get()); 2549 }, 2550 "Returns a list of block arguments.") 2551 .def_property_readonly( 2552 "operations", 2553 [](PyBlock &self) { 2554 return PyOperationList(self.getParentOperation(), self.get()); 2555 }, 2556 "Returns a forward-optimized sequence of operations.") 2557 .def_static( 2558 "create_at_start", 2559 [](PyRegion &parent, py::list pyArgTypes) { 2560 parent.checkValid(); 2561 llvm::SmallVector<MlirType, 4> argTypes; 2562 argTypes.reserve(pyArgTypes.size()); 2563 for (auto &pyArg : pyArgTypes) { 2564 argTypes.push_back(pyArg.cast<PyType &>()); 2565 } 2566 2567 MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data()); 2568 mlirRegionInsertOwnedBlock(parent, 0, block); 2569 return PyBlock(parent.getParentOperation(), block); 2570 }, 2571 py::arg("parent"), py::arg("arg_types") = py::list(), 2572 "Creates and returns a new Block at the beginning of the given " 2573 "region (with given argument types).") 2574 .def( 2575 "create_before", 2576 [](PyBlock &self, py::args pyArgTypes) { 2577 self.checkValid(); 2578 llvm::SmallVector<MlirType, 4> argTypes; 2579 argTypes.reserve(pyArgTypes.size()); 2580 for (auto &pyArg : pyArgTypes) { 2581 argTypes.push_back(pyArg.cast<PyType &>()); 2582 } 2583 2584 MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data()); 2585 MlirRegion region = mlirBlockGetParentRegion(self.get()); 2586 mlirRegionInsertOwnedBlockBefore(region, self.get(), block); 2587 return PyBlock(self.getParentOperation(), block); 2588 }, 2589 "Creates and returns a new Block before this block " 2590 "(with given argument types).") 2591 .def( 2592 "create_after", 2593 [](PyBlock &self, py::args pyArgTypes) { 2594 self.checkValid(); 2595 llvm::SmallVector<MlirType, 4> argTypes; 2596 argTypes.reserve(pyArgTypes.size()); 2597 for (auto &pyArg : pyArgTypes) { 2598 argTypes.push_back(pyArg.cast<PyType &>()); 2599 } 2600 2601 MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data()); 2602 MlirRegion region = mlirBlockGetParentRegion(self.get()); 2603 mlirRegionInsertOwnedBlockAfter(region, self.get(), block); 2604 return PyBlock(self.getParentOperation(), block); 2605 }, 2606 "Creates and returns a new Block after this block " 2607 "(with given argument types).") 2608 .def( 2609 "__iter__", 2610 [](PyBlock &self) { 2611 self.checkValid(); 2612 MlirOperation firstOperation = 2613 mlirBlockGetFirstOperation(self.get()); 2614 return PyOperationIterator(self.getParentOperation(), 2615 firstOperation); 2616 }, 2617 "Iterates over operations in the block.") 2618 .def("__eq__", 2619 [](PyBlock &self, PyBlock &other) { 2620 return self.get().ptr == other.get().ptr; 2621 }) 2622 .def("__eq__", [](PyBlock &self, py::object &other) { return false; }) 2623 .def( 2624 "__str__", 2625 [](PyBlock &self) { 2626 self.checkValid(); 2627 PyPrintAccumulator printAccum; 2628 mlirBlockPrint(self.get(), printAccum.getCallback(), 2629 printAccum.getUserData()); 2630 return printAccum.join(); 2631 }, 2632 "Returns the assembly form of the block.") 2633 .def( 2634 "append", 2635 [](PyBlock &self, PyOperationBase &operation) { 2636 if (operation.getOperation().isAttached()) 2637 operation.getOperation().detachFromParent(); 2638 2639 MlirOperation mlirOperation = operation.getOperation().get(); 2640 mlirBlockAppendOwnedOperation(self.get(), mlirOperation); 2641 operation.getOperation().setAttached( 2642 self.getParentOperation().getObject()); 2643 }, 2644 py::arg("operation"), 2645 "Appends an operation to this block. If the operation is currently " 2646 "in another block, it will be moved."); 2647 2648 //---------------------------------------------------------------------------- 2649 // Mapping of PyInsertionPoint. 2650 //---------------------------------------------------------------------------- 2651 2652 py::class_<PyInsertionPoint>(m, "InsertionPoint", py::module_local()) 2653 .def(py::init<PyBlock &>(), py::arg("block"), 2654 "Inserts after the last operation but still inside the block.") 2655 .def("__enter__", &PyInsertionPoint::contextEnter) 2656 .def("__exit__", &PyInsertionPoint::contextExit) 2657 .def_property_readonly_static( 2658 "current", 2659 [](py::object & /*class*/) { 2660 auto *ip = PyThreadContextEntry::getDefaultInsertionPoint(); 2661 if (!ip) 2662 throw SetPyError(PyExc_ValueError, "No current InsertionPoint"); 2663 return ip; 2664 }, 2665 "Gets the InsertionPoint bound to the current thread or raises " 2666 "ValueError if none has been set") 2667 .def(py::init<PyOperationBase &>(), py::arg("beforeOperation"), 2668 "Inserts before a referenced operation.") 2669 .def_static("at_block_begin", &PyInsertionPoint::atBlockBegin, 2670 py::arg("block"), "Inserts at the beginning of the block.") 2671 .def_static("at_block_terminator", &PyInsertionPoint::atBlockTerminator, 2672 py::arg("block"), "Inserts before the block terminator.") 2673 .def("insert", &PyInsertionPoint::insert, py::arg("operation"), 2674 "Inserts an operation.") 2675 .def_property_readonly( 2676 "block", [](PyInsertionPoint &self) { return self.getBlock(); }, 2677 "Returns the block that this InsertionPoint points to."); 2678 2679 //---------------------------------------------------------------------------- 2680 // Mapping of PyAttribute. 2681 //---------------------------------------------------------------------------- 2682 py::class_<PyAttribute>(m, "Attribute", py::module_local()) 2683 // Delegate to the PyAttribute copy constructor, which will also lifetime 2684 // extend the backing context which owns the MlirAttribute. 2685 .def(py::init<PyAttribute &>(), py::arg("cast_from_type"), 2686 "Casts the passed attribute to the generic Attribute") 2687 .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, 2688 &PyAttribute::getCapsule) 2689 .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyAttribute::createFromCapsule) 2690 .def_static( 2691 "parse", 2692 [](std::string attrSpec, DefaultingPyMlirContext context) { 2693 MlirAttribute type = mlirAttributeParseGet( 2694 context->get(), toMlirStringRef(attrSpec)); 2695 // TODO: Rework error reporting once diagnostic engine is exposed 2696 // in C API. 2697 if (mlirAttributeIsNull(type)) { 2698 throw SetPyError(PyExc_ValueError, 2699 Twine("Unable to parse attribute: '") + 2700 attrSpec + "'"); 2701 } 2702 return PyAttribute(context->getRef(), type); 2703 }, 2704 py::arg("asm"), py::arg("context") = py::none(), 2705 "Parses an attribute from an assembly form") 2706 .def_property_readonly( 2707 "context", 2708 [](PyAttribute &self) { return self.getContext().getObject(); }, 2709 "Context that owns the Attribute") 2710 .def_property_readonly("type", 2711 [](PyAttribute &self) { 2712 return PyType(self.getContext()->getRef(), 2713 mlirAttributeGetType(self)); 2714 }) 2715 .def( 2716 "get_named", 2717 [](PyAttribute &self, std::string name) { 2718 return PyNamedAttribute(self, std::move(name)); 2719 }, 2720 py::keep_alive<0, 1>(), "Binds a name to the attribute") 2721 .def("__eq__", 2722 [](PyAttribute &self, PyAttribute &other) { return self == other; }) 2723 .def("__eq__", [](PyAttribute &self, py::object &other) { return false; }) 2724 .def("__hash__", 2725 [](PyAttribute &self) { 2726 return static_cast<size_t>(llvm::hash_value(self.get().ptr)); 2727 }) 2728 .def( 2729 "dump", [](PyAttribute &self) { mlirAttributeDump(self); }, 2730 kDumpDocstring) 2731 .def( 2732 "__str__", 2733 [](PyAttribute &self) { 2734 PyPrintAccumulator printAccum; 2735 mlirAttributePrint(self, printAccum.getCallback(), 2736 printAccum.getUserData()); 2737 return printAccum.join(); 2738 }, 2739 "Returns the assembly form of the Attribute.") 2740 .def("__repr__", [](PyAttribute &self) { 2741 // Generally, assembly formats are not printed for __repr__ because 2742 // this can cause exceptionally long debug output and exceptions. 2743 // However, attribute values are generally considered useful and are 2744 // printed. This may need to be re-evaluated if debug dumps end up 2745 // being excessive. 2746 PyPrintAccumulator printAccum; 2747 printAccum.parts.append("Attribute("); 2748 mlirAttributePrint(self, printAccum.getCallback(), 2749 printAccum.getUserData()); 2750 printAccum.parts.append(")"); 2751 return printAccum.join(); 2752 }); 2753 2754 //---------------------------------------------------------------------------- 2755 // Mapping of PyNamedAttribute 2756 //---------------------------------------------------------------------------- 2757 py::class_<PyNamedAttribute>(m, "NamedAttribute", py::module_local()) 2758 .def("__repr__", 2759 [](PyNamedAttribute &self) { 2760 PyPrintAccumulator printAccum; 2761 printAccum.parts.append("NamedAttribute("); 2762 printAccum.parts.append( 2763 py::str(mlirIdentifierStr(self.namedAttr.name).data, 2764 mlirIdentifierStr(self.namedAttr.name).length)); 2765 printAccum.parts.append("="); 2766 mlirAttributePrint(self.namedAttr.attribute, 2767 printAccum.getCallback(), 2768 printAccum.getUserData()); 2769 printAccum.parts.append(")"); 2770 return printAccum.join(); 2771 }) 2772 .def_property_readonly( 2773 "name", 2774 [](PyNamedAttribute &self) { 2775 return py::str(mlirIdentifierStr(self.namedAttr.name).data, 2776 mlirIdentifierStr(self.namedAttr.name).length); 2777 }, 2778 "The name of the NamedAttribute binding") 2779 .def_property_readonly( 2780 "attr", 2781 [](PyNamedAttribute &self) { 2782 // TODO: When named attribute is removed/refactored, also remove 2783 // this constructor (it does an inefficient table lookup). 2784 auto contextRef = PyMlirContext::forContext( 2785 mlirAttributeGetContext(self.namedAttr.attribute)); 2786 return PyAttribute(std::move(contextRef), self.namedAttr.attribute); 2787 }, 2788 py::keep_alive<0, 1>(), 2789 "The underlying generic attribute of the NamedAttribute binding"); 2790 2791 //---------------------------------------------------------------------------- 2792 // Mapping of PyType. 2793 //---------------------------------------------------------------------------- 2794 py::class_<PyType>(m, "Type", py::module_local()) 2795 // Delegate to the PyType copy constructor, which will also lifetime 2796 // extend the backing context which owns the MlirType. 2797 .def(py::init<PyType &>(), py::arg("cast_from_type"), 2798 "Casts the passed type to the generic Type") 2799 .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyType::getCapsule) 2800 .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyType::createFromCapsule) 2801 .def_static( 2802 "parse", 2803 [](std::string typeSpec, DefaultingPyMlirContext context) { 2804 MlirType type = 2805 mlirTypeParseGet(context->get(), toMlirStringRef(typeSpec)); 2806 // TODO: Rework error reporting once diagnostic engine is exposed 2807 // in C API. 2808 if (mlirTypeIsNull(type)) { 2809 throw SetPyError(PyExc_ValueError, 2810 Twine("Unable to parse type: '") + typeSpec + 2811 "'"); 2812 } 2813 return PyType(context->getRef(), type); 2814 }, 2815 py::arg("asm"), py::arg("context") = py::none(), 2816 kContextParseTypeDocstring) 2817 .def_property_readonly( 2818 "context", [](PyType &self) { return self.getContext().getObject(); }, 2819 "Context that owns the Type") 2820 .def("__eq__", [](PyType &self, PyType &other) { return self == other; }) 2821 .def("__eq__", [](PyType &self, py::object &other) { return false; }) 2822 .def("__hash__", 2823 [](PyType &self) { 2824 return static_cast<size_t>(llvm::hash_value(self.get().ptr)); 2825 }) 2826 .def( 2827 "dump", [](PyType &self) { mlirTypeDump(self); }, kDumpDocstring) 2828 .def( 2829 "__str__", 2830 [](PyType &self) { 2831 PyPrintAccumulator printAccum; 2832 mlirTypePrint(self, printAccum.getCallback(), 2833 printAccum.getUserData()); 2834 return printAccum.join(); 2835 }, 2836 "Returns the assembly form of the type.") 2837 .def("__repr__", [](PyType &self) { 2838 // Generally, assembly formats are not printed for __repr__ because 2839 // this can cause exceptionally long debug output and exceptions. 2840 // However, types are an exception as they typically have compact 2841 // assembly forms and printing them is useful. 2842 PyPrintAccumulator printAccum; 2843 printAccum.parts.append("Type("); 2844 mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData()); 2845 printAccum.parts.append(")"); 2846 return printAccum.join(); 2847 }); 2848 2849 //---------------------------------------------------------------------------- 2850 // Mapping of Value. 2851 //---------------------------------------------------------------------------- 2852 py::class_<PyValue>(m, "Value", py::module_local()) 2853 .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyValue::getCapsule) 2854 .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyValue::createFromCapsule) 2855 .def_property_readonly( 2856 "context", 2857 [](PyValue &self) { return self.getParentOperation()->getContext(); }, 2858 "Context in which the value lives.") 2859 .def( 2860 "dump", [](PyValue &self) { mlirValueDump(self.get()); }, 2861 kDumpDocstring) 2862 .def_property_readonly( 2863 "owner", 2864 [](PyValue &self) { 2865 assert(mlirOperationEqual(self.getParentOperation()->get(), 2866 mlirOpResultGetOwner(self.get())) && 2867 "expected the owner of the value in Python to match that in " 2868 "the IR"); 2869 return self.getParentOperation().getObject(); 2870 }) 2871 .def("__eq__", 2872 [](PyValue &self, PyValue &other) { 2873 return self.get().ptr == other.get().ptr; 2874 }) 2875 .def("__eq__", [](PyValue &self, py::object other) { return false; }) 2876 .def("__hash__", 2877 [](PyValue &self) { 2878 return static_cast<size_t>(llvm::hash_value(self.get().ptr)); 2879 }) 2880 .def( 2881 "__str__", 2882 [](PyValue &self) { 2883 PyPrintAccumulator printAccum; 2884 printAccum.parts.append("Value("); 2885 mlirValuePrint(self.get(), printAccum.getCallback(), 2886 printAccum.getUserData()); 2887 printAccum.parts.append(")"); 2888 return printAccum.join(); 2889 }, 2890 kValueDunderStrDocstring) 2891 .def_property_readonly("type", [](PyValue &self) { 2892 return PyType(self.getParentOperation()->getContext(), 2893 mlirValueGetType(self.get())); 2894 }); 2895 PyBlockArgument::bind(m); 2896 PyOpResult::bind(m); 2897 2898 //---------------------------------------------------------------------------- 2899 // Mapping of SymbolTable. 2900 //---------------------------------------------------------------------------- 2901 py::class_<PySymbolTable>(m, "SymbolTable", py::module_local()) 2902 .def(py::init<PyOperationBase &>()) 2903 .def("__getitem__", &PySymbolTable::dunderGetItem) 2904 .def("insert", &PySymbolTable::insert, py::arg("operation")) 2905 .def("erase", &PySymbolTable::erase, py::arg("operation")) 2906 .def("__delitem__", &PySymbolTable::dunderDel) 2907 .def("__contains__", 2908 [](PySymbolTable &table, const std::string &name) { 2909 return !mlirOperationIsNull(mlirSymbolTableLookup( 2910 table, mlirStringRefCreate(name.data(), name.length()))); 2911 }) 2912 // Static helpers. 2913 .def_static("set_symbol_name", &PySymbolTable::setSymbolName, 2914 py::arg("symbol"), py::arg("name")) 2915 .def_static("get_symbol_name", &PySymbolTable::getSymbolName, 2916 py::arg("symbol")) 2917 .def_static("get_visibility", &PySymbolTable::getVisibility, 2918 py::arg("symbol")) 2919 .def_static("set_visibility", &PySymbolTable::setVisibility, 2920 py::arg("symbol"), py::arg("visibility")) 2921 .def_static("replace_all_symbol_uses", 2922 &PySymbolTable::replaceAllSymbolUses, py::arg("old_symbol"), 2923 py::arg("new_symbol"), py::arg("from_op")) 2924 .def_static("walk_symbol_tables", &PySymbolTable::walkSymbolTables, 2925 py::arg("from_op"), py::arg("all_sym_uses_visible"), 2926 py::arg("callback")); 2927 2928 // Container bindings. 2929 PyBlockArgumentList::bind(m); 2930 PyBlockIterator::bind(m); 2931 PyBlockList::bind(m); 2932 PyOperationIterator::bind(m); 2933 PyOperationList::bind(m); 2934 PyOpAttributeMap::bind(m); 2935 PyOpOperandList::bind(m); 2936 PyOpResultList::bind(m); 2937 PyRegionIterator::bind(m); 2938 PyRegionList::bind(m); 2939 2940 // Debug bindings. 2941 PyGlobalDebugFlag::bind(m); 2942 } 2943