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 &current = 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