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