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