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(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, maybeIp);
1366 }
1367 
1368 PyOpView::PyOpView(const py::object &operationObject)
1369     // Casting through the PyOperationBase base-class and then back to the
1370     // Operation lets us accept any PyOperationBase subclass.
1371     : operation(py::cast<PyOperationBase &>(operationObject).getOperation()),
1372       operationObject(operation.getRef().getObject()) {}
1373 
1374 py::object PyOpView::createRawSubclass(const py::object &userClass) {
1375   // This is... a little gross. The typical pattern is to have a pure python
1376   // class that extends OpView like:
1377   //   class AddFOp(_cext.ir.OpView):
1378   //     def __init__(self, loc, lhs, rhs):
1379   //       operation = loc.context.create_operation(
1380   //           "addf", lhs, rhs, results=[lhs.type])
1381   //       super().__init__(operation)
1382   //
1383   // I.e. The goal of the user facing type is to provide a nice constructor
1384   // that has complete freedom for the op under construction. This is at odds
1385   // with our other desire to sometimes create this object by just passing an
1386   // operation (to initialize the base class). We could do *arg and **kwargs
1387   // munging to try to make it work, but instead, we synthesize a new class
1388   // on the fly which extends this user class (AddFOp in this example) and
1389   // *give it* the base class's __init__ method, thus bypassing the
1390   // intermediate subclass's __init__ method entirely. While slightly,
1391   // underhanded, this is safe/legal because the type hierarchy has not changed
1392   // (we just added a new leaf) and we aren't mucking around with __new__.
1393   // Typically, this new class will be stored on the original as "_Raw" and will
1394   // be used for casts and other things that need a variant of the class that
1395   // is initialized purely from an operation.
1396   py::object parentMetaclass =
1397       py::reinterpret_borrow<py::object>((PyObject *)&PyType_Type);
1398   py::dict attributes;
1399   // TODO: pybind11 2.6 supports a more direct form. Upgrade many years from
1400   // now.
1401   //   auto opViewType = py::type::of<PyOpView>();
1402   auto opViewType = py::detail::get_type_handle(typeid(PyOpView), true);
1403   attributes["__init__"] = opViewType.attr("__init__");
1404   py::str origName = userClass.attr("__name__");
1405   py::str newName = py::str("_") + origName;
1406   return parentMetaclass(newName, py::make_tuple(userClass), attributes);
1407 }
1408 
1409 //------------------------------------------------------------------------------
1410 // PyInsertionPoint.
1411 //------------------------------------------------------------------------------
1412 
1413 PyInsertionPoint::PyInsertionPoint(PyBlock &block) : block(block) {}
1414 
1415 PyInsertionPoint::PyInsertionPoint(PyOperationBase &beforeOperationBase)
1416     : refOperation(beforeOperationBase.getOperation().getRef()),
1417       block((*refOperation)->getBlock()) {}
1418 
1419 void PyInsertionPoint::insert(PyOperationBase &operationBase) {
1420   PyOperation &operation = operationBase.getOperation();
1421   if (operation.isAttached())
1422     throw SetPyError(PyExc_ValueError,
1423                      "Attempt to insert operation that is already attached");
1424   block.getParentOperation()->checkValid();
1425   MlirOperation beforeOp = {nullptr};
1426   if (refOperation) {
1427     // Insert before operation.
1428     (*refOperation)->checkValid();
1429     beforeOp = (*refOperation)->get();
1430   } else {
1431     // Insert at end (before null) is only valid if the block does not
1432     // already end in a known terminator (violating this will cause assertion
1433     // failures later).
1434     if (!mlirOperationIsNull(mlirBlockGetTerminator(block.get()))) {
1435       throw py::index_error("Cannot insert operation at the end of a block "
1436                             "that already has a terminator. Did you mean to "
1437                             "use 'InsertionPoint.at_block_terminator(block)' "
1438                             "versus 'InsertionPoint(block)'?");
1439     }
1440   }
1441   mlirBlockInsertOwnedOperationBefore(block.get(), beforeOp, operation);
1442   operation.setAttached();
1443 }
1444 
1445 PyInsertionPoint PyInsertionPoint::atBlockBegin(PyBlock &block) {
1446   MlirOperation firstOp = mlirBlockGetFirstOperation(block.get());
1447   if (mlirOperationIsNull(firstOp)) {
1448     // Just insert at end.
1449     return PyInsertionPoint(block);
1450   }
1451 
1452   // Insert before first op.
1453   PyOperationRef firstOpRef = PyOperation::forOperation(
1454       block.getParentOperation()->getContext(), firstOp);
1455   return PyInsertionPoint{block, std::move(firstOpRef)};
1456 }
1457 
1458 PyInsertionPoint PyInsertionPoint::atBlockTerminator(PyBlock &block) {
1459   MlirOperation terminator = mlirBlockGetTerminator(block.get());
1460   if (mlirOperationIsNull(terminator))
1461     throw SetPyError(PyExc_ValueError, "Block has no terminator");
1462   PyOperationRef terminatorOpRef = PyOperation::forOperation(
1463       block.getParentOperation()->getContext(), terminator);
1464   return PyInsertionPoint{block, std::move(terminatorOpRef)};
1465 }
1466 
1467 py::object PyInsertionPoint::contextEnter() {
1468   return PyThreadContextEntry::pushInsertionPoint(*this);
1469 }
1470 
1471 void PyInsertionPoint::contextExit(const pybind11::object &excType,
1472                                    const pybind11::object &excVal,
1473                                    const pybind11::object &excTb) {
1474   PyThreadContextEntry::popInsertionPoint(*this);
1475 }
1476 
1477 //------------------------------------------------------------------------------
1478 // PyAttribute.
1479 //------------------------------------------------------------------------------
1480 
1481 bool PyAttribute::operator==(const PyAttribute &other) {
1482   return mlirAttributeEqual(attr, other.attr);
1483 }
1484 
1485 py::object PyAttribute::getCapsule() {
1486   return py::reinterpret_steal<py::object>(mlirPythonAttributeToCapsule(*this));
1487 }
1488 
1489 PyAttribute PyAttribute::createFromCapsule(py::object capsule) {
1490   MlirAttribute rawAttr = mlirPythonCapsuleToAttribute(capsule.ptr());
1491   if (mlirAttributeIsNull(rawAttr))
1492     throw py::error_already_set();
1493   return PyAttribute(
1494       PyMlirContext::forContext(mlirAttributeGetContext(rawAttr)), rawAttr);
1495 }
1496 
1497 //------------------------------------------------------------------------------
1498 // PyNamedAttribute.
1499 //------------------------------------------------------------------------------
1500 
1501 PyNamedAttribute::PyNamedAttribute(MlirAttribute attr, std::string ownedName)
1502     : ownedName(new std::string(std::move(ownedName))) {
1503   namedAttr = mlirNamedAttributeGet(
1504       mlirIdentifierGet(mlirAttributeGetContext(attr),
1505                         toMlirStringRef(*this->ownedName)),
1506       attr);
1507 }
1508 
1509 //------------------------------------------------------------------------------
1510 // PyType.
1511 //------------------------------------------------------------------------------
1512 
1513 bool PyType::operator==(const PyType &other) {
1514   return mlirTypeEqual(type, other.type);
1515 }
1516 
1517 py::object PyType::getCapsule() {
1518   return py::reinterpret_steal<py::object>(mlirPythonTypeToCapsule(*this));
1519 }
1520 
1521 PyType PyType::createFromCapsule(py::object capsule) {
1522   MlirType rawType = mlirPythonCapsuleToType(capsule.ptr());
1523   if (mlirTypeIsNull(rawType))
1524     throw py::error_already_set();
1525   return PyType(PyMlirContext::forContext(mlirTypeGetContext(rawType)),
1526                 rawType);
1527 }
1528 
1529 //------------------------------------------------------------------------------
1530 // PyValue and subclases.
1531 //------------------------------------------------------------------------------
1532 
1533 pybind11::object PyValue::getCapsule() {
1534   return py::reinterpret_steal<py::object>(mlirPythonValueToCapsule(get()));
1535 }
1536 
1537 PyValue PyValue::createFromCapsule(pybind11::object capsule) {
1538   MlirValue value = mlirPythonCapsuleToValue(capsule.ptr());
1539   if (mlirValueIsNull(value))
1540     throw py::error_already_set();
1541   MlirOperation owner;
1542   if (mlirValueIsAOpResult(value))
1543     owner = mlirOpResultGetOwner(value);
1544   if (mlirValueIsABlockArgument(value))
1545     owner = mlirBlockGetParentOperation(mlirBlockArgumentGetOwner(value));
1546   if (mlirOperationIsNull(owner))
1547     throw py::error_already_set();
1548   MlirContext ctx = mlirOperationGetContext(owner);
1549   PyOperationRef ownerRef =
1550       PyOperation::forOperation(PyMlirContext::forContext(ctx), owner);
1551   return PyValue(ownerRef, value);
1552 }
1553 
1554 //------------------------------------------------------------------------------
1555 // PySymbolTable.
1556 //------------------------------------------------------------------------------
1557 
1558 PySymbolTable::PySymbolTable(PyOperationBase &operation)
1559     : operation(operation.getOperation().getRef()) {
1560   symbolTable = mlirSymbolTableCreate(operation.getOperation().get());
1561   if (mlirSymbolTableIsNull(symbolTable)) {
1562     throw py::cast_error("Operation is not a Symbol Table.");
1563   }
1564 }
1565 
1566 py::object PySymbolTable::dunderGetItem(const std::string &name) {
1567   operation->checkValid();
1568   MlirOperation symbol = mlirSymbolTableLookup(
1569       symbolTable, mlirStringRefCreate(name.data(), name.length()));
1570   if (mlirOperationIsNull(symbol))
1571     throw py::key_error("Symbol '" + name + "' not in the symbol table.");
1572 
1573   return PyOperation::forOperation(operation->getContext(), symbol,
1574                                    operation.getObject())
1575       ->createOpView();
1576 }
1577 
1578 void PySymbolTable::erase(PyOperationBase &symbol) {
1579   operation->checkValid();
1580   symbol.getOperation().checkValid();
1581   mlirSymbolTableErase(symbolTable, symbol.getOperation().get());
1582   // The operation is also erased, so we must invalidate it. There may be Python
1583   // references to this operation so we don't want to delete it from the list of
1584   // live operations here.
1585   symbol.getOperation().valid = false;
1586 }
1587 
1588 void PySymbolTable::dunderDel(const std::string &name) {
1589   py::object operation = dunderGetItem(name);
1590   erase(py::cast<PyOperationBase &>(operation));
1591 }
1592 
1593 PyAttribute PySymbolTable::insert(PyOperationBase &symbol) {
1594   operation->checkValid();
1595   symbol.getOperation().checkValid();
1596   MlirAttribute symbolAttr = mlirOperationGetAttributeByName(
1597       symbol.getOperation().get(), mlirSymbolTableGetSymbolAttributeName());
1598   if (mlirAttributeIsNull(symbolAttr))
1599     throw py::value_error("Expected operation to have a symbol name.");
1600   return PyAttribute(
1601       symbol.getOperation().getContext(),
1602       mlirSymbolTableInsert(symbolTable, symbol.getOperation().get()));
1603 }
1604 
1605 PyAttribute PySymbolTable::getSymbolName(PyOperationBase &symbol) {
1606   // Op must already be a symbol.
1607   PyOperation &operation = symbol.getOperation();
1608   operation.checkValid();
1609   MlirStringRef attrName = mlirSymbolTableGetSymbolAttributeName();
1610   MlirAttribute existingNameAttr =
1611       mlirOperationGetAttributeByName(operation.get(), attrName);
1612   if (mlirAttributeIsNull(existingNameAttr))
1613     throw py::value_error("Expected operation to have a symbol name.");
1614   return PyAttribute(symbol.getOperation().getContext(), existingNameAttr);
1615 }
1616 
1617 void PySymbolTable::setSymbolName(PyOperationBase &symbol,
1618                                   const std::string &name) {
1619   // Op must already be a symbol.
1620   PyOperation &operation = symbol.getOperation();
1621   operation.checkValid();
1622   MlirStringRef attrName = mlirSymbolTableGetSymbolAttributeName();
1623   MlirAttribute existingNameAttr =
1624       mlirOperationGetAttributeByName(operation.get(), attrName);
1625   if (mlirAttributeIsNull(existingNameAttr))
1626     throw py::value_error("Expected operation to have a symbol name.");
1627   MlirAttribute newNameAttr =
1628       mlirStringAttrGet(operation.getContext()->get(), toMlirStringRef(name));
1629   mlirOperationSetAttributeByName(operation.get(), attrName, newNameAttr);
1630 }
1631 
1632 PyAttribute PySymbolTable::getVisibility(PyOperationBase &symbol) {
1633   PyOperation &operation = symbol.getOperation();
1634   operation.checkValid();
1635   MlirStringRef attrName = mlirSymbolTableGetVisibilityAttributeName();
1636   MlirAttribute existingVisAttr =
1637       mlirOperationGetAttributeByName(operation.get(), attrName);
1638   if (mlirAttributeIsNull(existingVisAttr))
1639     throw py::value_error("Expected operation to have a symbol visibility.");
1640   return PyAttribute(symbol.getOperation().getContext(), existingVisAttr);
1641 }
1642 
1643 void PySymbolTable::setVisibility(PyOperationBase &symbol,
1644                                   const std::string &visibility) {
1645   if (visibility != "public" && visibility != "private" &&
1646       visibility != "nested")
1647     throw py::value_error(
1648         "Expected visibility to be 'public', 'private' or 'nested'");
1649   PyOperation &operation = symbol.getOperation();
1650   operation.checkValid();
1651   MlirStringRef attrName = mlirSymbolTableGetVisibilityAttributeName();
1652   MlirAttribute existingVisAttr =
1653       mlirOperationGetAttributeByName(operation.get(), attrName);
1654   if (mlirAttributeIsNull(existingVisAttr))
1655     throw py::value_error("Expected operation to have a symbol visibility.");
1656   MlirAttribute newVisAttr = mlirStringAttrGet(operation.getContext()->get(),
1657                                                toMlirStringRef(visibility));
1658   mlirOperationSetAttributeByName(operation.get(), attrName, newVisAttr);
1659 }
1660 
1661 void PySymbolTable::replaceAllSymbolUses(const std::string &oldSymbol,
1662                                          const std::string &newSymbol,
1663                                          PyOperationBase &from) {
1664   PyOperation &fromOperation = from.getOperation();
1665   fromOperation.checkValid();
1666   if (mlirLogicalResultIsFailure(mlirSymbolTableReplaceAllSymbolUses(
1667           toMlirStringRef(oldSymbol), toMlirStringRef(newSymbol),
1668           from.getOperation())))
1669 
1670     throw py::value_error("Symbol rename failed");
1671 }
1672 
1673 void PySymbolTable::walkSymbolTables(PyOperationBase &from,
1674                                      bool allSymUsesVisible,
1675                                      py::object callback) {
1676   PyOperation &fromOperation = from.getOperation();
1677   fromOperation.checkValid();
1678   struct UserData {
1679     PyMlirContextRef context;
1680     py::object callback;
1681     bool gotException;
1682     std::string exceptionWhat;
1683     py::object exceptionType;
1684   };
1685   UserData userData{
1686       fromOperation.getContext(), std::move(callback), false, {}, {}};
1687   mlirSymbolTableWalkSymbolTables(
1688       fromOperation.get(), allSymUsesVisible,
1689       [](MlirOperation foundOp, bool isVisible, void *calleeUserDataVoid) {
1690         UserData *calleeUserData = static_cast<UserData *>(calleeUserDataVoid);
1691         auto pyFoundOp =
1692             PyOperation::forOperation(calleeUserData->context, foundOp);
1693         if (calleeUserData->gotException)
1694           return;
1695         try {
1696           calleeUserData->callback(pyFoundOp.getObject(), isVisible);
1697         } catch (py::error_already_set &e) {
1698           calleeUserData->gotException = true;
1699           calleeUserData->exceptionWhat = e.what();
1700           calleeUserData->exceptionType = e.type();
1701         }
1702       },
1703       static_cast<void *>(&userData));
1704   if (userData.gotException) {
1705     std::string message("Exception raised in callback: ");
1706     message.append(userData.exceptionWhat);
1707     throw std::runtime_error(message);
1708   }
1709 }
1710 
1711 namespace {
1712 /// CRTP base class for Python MLIR values that subclass Value and should be
1713 /// castable from it. The value hierarchy is one level deep and is not supposed
1714 /// to accommodate other levels unless core MLIR changes.
1715 template <typename DerivedTy>
1716 class PyConcreteValue : public PyValue {
1717 public:
1718   // Derived classes must define statics for:
1719   //   IsAFunctionTy isaFunction
1720   //   const char *pyClassName
1721   // and redefine bindDerived.
1722   using ClassTy = py::class_<DerivedTy, PyValue>;
1723   using IsAFunctionTy = bool (*)(MlirValue);
1724 
1725   PyConcreteValue() = default;
1726   PyConcreteValue(PyOperationRef operationRef, MlirValue value)
1727       : PyValue(operationRef, value) {}
1728   PyConcreteValue(PyValue &orig)
1729       : PyConcreteValue(orig.getParentOperation(), castFrom(orig)) {}
1730 
1731   /// Attempts to cast the original value to the derived type and throws on
1732   /// type mismatches.
1733   static MlirValue castFrom(PyValue &orig) {
1734     if (!DerivedTy::isaFunction(orig.get())) {
1735       auto origRepr = py::repr(py::cast(orig)).cast<std::string>();
1736       throw SetPyError(PyExc_ValueError, Twine("Cannot cast value to ") +
1737                                              DerivedTy::pyClassName +
1738                                              " (from " + origRepr + ")");
1739     }
1740     return orig.get();
1741   }
1742 
1743   /// Binds the Python module objects to functions of this class.
1744   static void bind(py::module &m) {
1745     auto cls = ClassTy(m, DerivedTy::pyClassName, py::module_local());
1746     cls.def(py::init<PyValue &>(), py::keep_alive<0, 1>(), py::arg("value"));
1747     cls.def_static(
1748         "isinstance",
1749         [](PyValue &otherValue) -> bool {
1750           return DerivedTy::isaFunction(otherValue);
1751         },
1752         py::arg("other_value"));
1753     DerivedTy::bindDerived(cls);
1754   }
1755 
1756   /// Implemented by derived classes to add methods to the Python subclass.
1757   static void bindDerived(ClassTy &m) {}
1758 };
1759 
1760 /// Python wrapper for MlirBlockArgument.
1761 class PyBlockArgument : public PyConcreteValue<PyBlockArgument> {
1762 public:
1763   static constexpr IsAFunctionTy isaFunction = mlirValueIsABlockArgument;
1764   static constexpr const char *pyClassName = "BlockArgument";
1765   using PyConcreteValue::PyConcreteValue;
1766 
1767   static void bindDerived(ClassTy &c) {
1768     c.def_property_readonly("owner", [](PyBlockArgument &self) {
1769       return PyBlock(self.getParentOperation(),
1770                      mlirBlockArgumentGetOwner(self.get()));
1771     });
1772     c.def_property_readonly("arg_number", [](PyBlockArgument &self) {
1773       return mlirBlockArgumentGetArgNumber(self.get());
1774     });
1775     c.def(
1776         "set_type",
1777         [](PyBlockArgument &self, PyType type) {
1778           return mlirBlockArgumentSetType(self.get(), type);
1779         },
1780         py::arg("type"));
1781   }
1782 };
1783 
1784 /// Python wrapper for MlirOpResult.
1785 class PyOpResult : public PyConcreteValue<PyOpResult> {
1786 public:
1787   static constexpr IsAFunctionTy isaFunction = mlirValueIsAOpResult;
1788   static constexpr const char *pyClassName = "OpResult";
1789   using PyConcreteValue::PyConcreteValue;
1790 
1791   static void bindDerived(ClassTy &c) {
1792     c.def_property_readonly("owner", [](PyOpResult &self) {
1793       assert(
1794           mlirOperationEqual(self.getParentOperation()->get(),
1795                              mlirOpResultGetOwner(self.get())) &&
1796           "expected the owner of the value in Python to match that in the IR");
1797       return self.getParentOperation().getObject();
1798     });
1799     c.def_property_readonly("result_number", [](PyOpResult &self) {
1800       return mlirOpResultGetResultNumber(self.get());
1801     });
1802   }
1803 };
1804 
1805 /// Returns the list of types of the values held by container.
1806 template <typename Container>
1807 static std::vector<PyType> getValueTypes(Container &container,
1808                                          PyMlirContextRef &context) {
1809   std::vector<PyType> result;
1810   result.reserve(container.getNumElements());
1811   for (int i = 0, e = container.getNumElements(); i < e; ++i) {
1812     result.push_back(
1813         PyType(context, mlirValueGetType(container.getElement(i).get())));
1814   }
1815   return result;
1816 }
1817 
1818 /// A list of block arguments. Internally, these are stored as consecutive
1819 /// elements, random access is cheap. The argument list is associated with the
1820 /// operation that contains the block (detached blocks are not allowed in
1821 /// Python bindings) and extends its lifetime.
1822 class PyBlockArgumentList
1823     : public Sliceable<PyBlockArgumentList, PyBlockArgument> {
1824 public:
1825   static constexpr const char *pyClassName = "BlockArgumentList";
1826 
1827   PyBlockArgumentList(PyOperationRef operation, MlirBlock block,
1828                       intptr_t startIndex = 0, intptr_t length = -1,
1829                       intptr_t step = 1)
1830       : Sliceable(startIndex,
1831                   length == -1 ? mlirBlockGetNumArguments(block) : length,
1832                   step),
1833         operation(std::move(operation)), block(block) {}
1834 
1835   /// Returns the number of arguments in the list.
1836   intptr_t getNumElements() {
1837     operation->checkValid();
1838     return mlirBlockGetNumArguments(block);
1839   }
1840 
1841   /// Returns `pos`-the element in the list. Asserts on out-of-bounds.
1842   PyBlockArgument getElement(intptr_t pos) {
1843     MlirValue argument = mlirBlockGetArgument(block, pos);
1844     return PyBlockArgument(operation, argument);
1845   }
1846 
1847   /// Returns a sublist of this list.
1848   PyBlockArgumentList slice(intptr_t startIndex, intptr_t length,
1849                             intptr_t step) {
1850     return PyBlockArgumentList(operation, block, startIndex, length, step);
1851   }
1852 
1853   static void bindDerived(ClassTy &c) {
1854     c.def_property_readonly("types", [](PyBlockArgumentList &self) {
1855       return getValueTypes(self, self.operation->getContext());
1856     });
1857   }
1858 
1859 private:
1860   PyOperationRef operation;
1861   MlirBlock block;
1862 };
1863 
1864 /// A list of operation operands. Internally, these are stored as consecutive
1865 /// elements, random access is cheap. The result list is associated with the
1866 /// operation whose results these are, and extends the lifetime of this
1867 /// operation.
1868 class PyOpOperandList : public Sliceable<PyOpOperandList, PyValue> {
1869 public:
1870   static constexpr const char *pyClassName = "OpOperandList";
1871 
1872   PyOpOperandList(PyOperationRef operation, intptr_t startIndex = 0,
1873                   intptr_t length = -1, intptr_t step = 1)
1874       : Sliceable(startIndex,
1875                   length == -1 ? mlirOperationGetNumOperands(operation->get())
1876                                : length,
1877                   step),
1878         operation(operation) {}
1879 
1880   intptr_t getNumElements() {
1881     operation->checkValid();
1882     return mlirOperationGetNumOperands(operation->get());
1883   }
1884 
1885   PyValue getElement(intptr_t pos) {
1886     MlirValue operand = mlirOperationGetOperand(operation->get(), pos);
1887     MlirOperation owner;
1888     if (mlirValueIsAOpResult(operand))
1889       owner = mlirOpResultGetOwner(operand);
1890     else if (mlirValueIsABlockArgument(operand))
1891       owner = mlirBlockGetParentOperation(mlirBlockArgumentGetOwner(operand));
1892     else
1893       assert(false && "Value must be an block arg or op result.");
1894     PyOperationRef pyOwner =
1895         PyOperation::forOperation(operation->getContext(), owner);
1896     return PyValue(pyOwner, operand);
1897   }
1898 
1899   PyOpOperandList slice(intptr_t startIndex, intptr_t length, intptr_t step) {
1900     return PyOpOperandList(operation, startIndex, length, step);
1901   }
1902 
1903   void dunderSetItem(intptr_t index, PyValue value) {
1904     index = wrapIndex(index);
1905     mlirOperationSetOperand(operation->get(), index, value.get());
1906   }
1907 
1908   static void bindDerived(ClassTy &c) {
1909     c.def("__setitem__", &PyOpOperandList::dunderSetItem);
1910   }
1911 
1912 private:
1913   PyOperationRef operation;
1914 };
1915 
1916 /// A list of operation results. Internally, these are stored as consecutive
1917 /// elements, random access is cheap. The result list is associated with the
1918 /// operation whose results these are, and extends the lifetime of this
1919 /// operation.
1920 class PyOpResultList : public Sliceable<PyOpResultList, PyOpResult> {
1921 public:
1922   static constexpr const char *pyClassName = "OpResultList";
1923 
1924   PyOpResultList(PyOperationRef operation, intptr_t startIndex = 0,
1925                  intptr_t length = -1, intptr_t step = 1)
1926       : Sliceable(startIndex,
1927                   length == -1 ? mlirOperationGetNumResults(operation->get())
1928                                : length,
1929                   step),
1930         operation(operation) {}
1931 
1932   intptr_t getNumElements() {
1933     operation->checkValid();
1934     return mlirOperationGetNumResults(operation->get());
1935   }
1936 
1937   PyOpResult getElement(intptr_t index) {
1938     PyValue value(operation, mlirOperationGetResult(operation->get(), index));
1939     return PyOpResult(value);
1940   }
1941 
1942   PyOpResultList slice(intptr_t startIndex, intptr_t length, intptr_t step) {
1943     return PyOpResultList(operation, startIndex, length, step);
1944   }
1945 
1946   static void bindDerived(ClassTy &c) {
1947     c.def_property_readonly("types", [](PyOpResultList &self) {
1948       return getValueTypes(self, self.operation->getContext());
1949     });
1950   }
1951 
1952 private:
1953   PyOperationRef operation;
1954 };
1955 
1956 /// A list of operation attributes. Can be indexed by name, producing
1957 /// attributes, or by index, producing named attributes.
1958 class PyOpAttributeMap {
1959 public:
1960   PyOpAttributeMap(PyOperationRef operation)
1961       : operation(std::move(operation)) {}
1962 
1963   PyAttribute dunderGetItemNamed(const std::string &name) {
1964     MlirAttribute attr = mlirOperationGetAttributeByName(operation->get(),
1965                                                          toMlirStringRef(name));
1966     if (mlirAttributeIsNull(attr)) {
1967       throw SetPyError(PyExc_KeyError,
1968                        "attempt to access a non-existent attribute");
1969     }
1970     return PyAttribute(operation->getContext(), attr);
1971   }
1972 
1973   PyNamedAttribute dunderGetItemIndexed(intptr_t index) {
1974     if (index < 0 || index >= dunderLen()) {
1975       throw SetPyError(PyExc_IndexError,
1976                        "attempt to access out of bounds attribute");
1977     }
1978     MlirNamedAttribute namedAttr =
1979         mlirOperationGetAttribute(operation->get(), index);
1980     return PyNamedAttribute(
1981         namedAttr.attribute,
1982         std::string(mlirIdentifierStr(namedAttr.name).data,
1983                     mlirIdentifierStr(namedAttr.name).length));
1984   }
1985 
1986   void dunderSetItem(const std::string &name, const PyAttribute &attr) {
1987     mlirOperationSetAttributeByName(operation->get(), toMlirStringRef(name),
1988                                     attr);
1989   }
1990 
1991   void dunderDelItem(const std::string &name) {
1992     int removed = mlirOperationRemoveAttributeByName(operation->get(),
1993                                                      toMlirStringRef(name));
1994     if (!removed)
1995       throw SetPyError(PyExc_KeyError,
1996                        "attempt to delete a non-existent attribute");
1997   }
1998 
1999   intptr_t dunderLen() {
2000     return mlirOperationGetNumAttributes(operation->get());
2001   }
2002 
2003   bool dunderContains(const std::string &name) {
2004     return !mlirAttributeIsNull(mlirOperationGetAttributeByName(
2005         operation->get(), toMlirStringRef(name)));
2006   }
2007 
2008   static void bind(py::module &m) {
2009     py::class_<PyOpAttributeMap>(m, "OpAttributeMap", py::module_local())
2010         .def("__contains__", &PyOpAttributeMap::dunderContains)
2011         .def("__len__", &PyOpAttributeMap::dunderLen)
2012         .def("__getitem__", &PyOpAttributeMap::dunderGetItemNamed)
2013         .def("__getitem__", &PyOpAttributeMap::dunderGetItemIndexed)
2014         .def("__setitem__", &PyOpAttributeMap::dunderSetItem)
2015         .def("__delitem__", &PyOpAttributeMap::dunderDelItem);
2016   }
2017 
2018 private:
2019   PyOperationRef operation;
2020 };
2021 
2022 } // namespace
2023 
2024 //------------------------------------------------------------------------------
2025 // Populates the core exports of the 'ir' submodule.
2026 //------------------------------------------------------------------------------
2027 
2028 void mlir::python::populateIRCore(py::module &m) {
2029   //----------------------------------------------------------------------------
2030   // Mapping of MlirContext.
2031   //----------------------------------------------------------------------------
2032   py::class_<PyMlirContext>(m, "Context", py::module_local())
2033       .def(py::init<>(&PyMlirContext::createNewContextForInit))
2034       .def_static("_get_live_count", &PyMlirContext::getLiveCount)
2035       .def("_get_context_again",
2036            [](PyMlirContext &self) {
2037              PyMlirContextRef ref = PyMlirContext::forContext(self.get());
2038              return ref.releaseObject();
2039            })
2040       .def("_get_live_operation_count", &PyMlirContext::getLiveOperationCount)
2041       .def("_get_live_module_count", &PyMlirContext::getLiveModuleCount)
2042       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
2043                              &PyMlirContext::getCapsule)
2044       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyMlirContext::createFromCapsule)
2045       .def("__enter__", &PyMlirContext::contextEnter)
2046       .def("__exit__", &PyMlirContext::contextExit)
2047       .def_property_readonly_static(
2048           "current",
2049           [](py::object & /*class*/) {
2050             auto *context = PyThreadContextEntry::getDefaultContext();
2051             if (!context)
2052               throw SetPyError(PyExc_ValueError, "No current Context");
2053             return context;
2054           },
2055           "Gets the Context bound to the current thread or raises ValueError")
2056       .def_property_readonly(
2057           "dialects",
2058           [](PyMlirContext &self) { return PyDialects(self.getRef()); },
2059           "Gets a container for accessing dialects by name")
2060       .def_property_readonly(
2061           "d", [](PyMlirContext &self) { return PyDialects(self.getRef()); },
2062           "Alias for 'dialect'")
2063       .def(
2064           "get_dialect_descriptor",
2065           [=](PyMlirContext &self, std::string &name) {
2066             MlirDialect dialect = mlirContextGetOrLoadDialect(
2067                 self.get(), {name.data(), name.size()});
2068             if (mlirDialectIsNull(dialect)) {
2069               throw SetPyError(PyExc_ValueError,
2070                                Twine("Dialect '") + name + "' not found");
2071             }
2072             return PyDialectDescriptor(self.getRef(), dialect);
2073           },
2074           py::arg("dialect_name"),
2075           "Gets or loads a dialect by name, returning its descriptor object")
2076       .def_property(
2077           "allow_unregistered_dialects",
2078           [](PyMlirContext &self) -> bool {
2079             return mlirContextGetAllowUnregisteredDialects(self.get());
2080           },
2081           [](PyMlirContext &self, bool value) {
2082             mlirContextSetAllowUnregisteredDialects(self.get(), value);
2083           })
2084       .def(
2085           "enable_multithreading",
2086           [](PyMlirContext &self, bool enable) {
2087             mlirContextEnableMultithreading(self.get(), enable);
2088           },
2089           py::arg("enable"))
2090       .def(
2091           "is_registered_operation",
2092           [](PyMlirContext &self, std::string &name) {
2093             return mlirContextIsRegisteredOperation(
2094                 self.get(), MlirStringRef{name.data(), name.size()});
2095           },
2096           py::arg("operation_name"));
2097 
2098   //----------------------------------------------------------------------------
2099   // Mapping of PyDialectDescriptor
2100   //----------------------------------------------------------------------------
2101   py::class_<PyDialectDescriptor>(m, "DialectDescriptor", py::module_local())
2102       .def_property_readonly("namespace",
2103                              [](PyDialectDescriptor &self) {
2104                                MlirStringRef ns =
2105                                    mlirDialectGetNamespace(self.get());
2106                                return py::str(ns.data, ns.length);
2107                              })
2108       .def("__repr__", [](PyDialectDescriptor &self) {
2109         MlirStringRef ns = mlirDialectGetNamespace(self.get());
2110         std::string repr("<DialectDescriptor ");
2111         repr.append(ns.data, ns.length);
2112         repr.append(">");
2113         return repr;
2114       });
2115 
2116   //----------------------------------------------------------------------------
2117   // Mapping of PyDialects
2118   //----------------------------------------------------------------------------
2119   py::class_<PyDialects>(m, "Dialects", py::module_local())
2120       .def("__getitem__",
2121            [=](PyDialects &self, std::string keyName) {
2122              MlirDialect dialect =
2123                  self.getDialectForKey(keyName, /*attrError=*/false);
2124              py::object descriptor =
2125                  py::cast(PyDialectDescriptor{self.getContext(), dialect});
2126              return createCustomDialectWrapper(keyName, std::move(descriptor));
2127            })
2128       .def("__getattr__", [=](PyDialects &self, std::string attrName) {
2129         MlirDialect dialect =
2130             self.getDialectForKey(attrName, /*attrError=*/true);
2131         py::object descriptor =
2132             py::cast(PyDialectDescriptor{self.getContext(), dialect});
2133         return createCustomDialectWrapper(attrName, std::move(descriptor));
2134       });
2135 
2136   //----------------------------------------------------------------------------
2137   // Mapping of PyDialect
2138   //----------------------------------------------------------------------------
2139   py::class_<PyDialect>(m, "Dialect", py::module_local())
2140       .def(py::init<py::object>(), py::arg("descriptor"))
2141       .def_property_readonly(
2142           "descriptor", [](PyDialect &self) { return self.getDescriptor(); })
2143       .def("__repr__", [](py::object self) {
2144         auto clazz = self.attr("__class__");
2145         return py::str("<Dialect ") +
2146                self.attr("descriptor").attr("namespace") + py::str(" (class ") +
2147                clazz.attr("__module__") + py::str(".") +
2148                clazz.attr("__name__") + py::str(")>");
2149       });
2150 
2151   //----------------------------------------------------------------------------
2152   // Mapping of Location
2153   //----------------------------------------------------------------------------
2154   py::class_<PyLocation>(m, "Location", py::module_local())
2155       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyLocation::getCapsule)
2156       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyLocation::createFromCapsule)
2157       .def("__enter__", &PyLocation::contextEnter)
2158       .def("__exit__", &PyLocation::contextExit)
2159       .def("__eq__",
2160            [](PyLocation &self, PyLocation &other) -> bool {
2161              return mlirLocationEqual(self, other);
2162            })
2163       .def("__eq__", [](PyLocation &self, py::object other) { return false; })
2164       .def_property_readonly_static(
2165           "current",
2166           [](py::object & /*class*/) {
2167             auto *loc = PyThreadContextEntry::getDefaultLocation();
2168             if (!loc)
2169               throw SetPyError(PyExc_ValueError, "No current Location");
2170             return loc;
2171           },
2172           "Gets the Location bound to the current thread or raises ValueError")
2173       .def_static(
2174           "unknown",
2175           [](DefaultingPyMlirContext context) {
2176             return PyLocation(context->getRef(),
2177                               mlirLocationUnknownGet(context->get()));
2178           },
2179           py::arg("context") = py::none(),
2180           "Gets a Location representing an unknown location")
2181       .def_static(
2182           "callsite",
2183           [](PyLocation callee, const std::vector<PyLocation> &frames,
2184              DefaultingPyMlirContext context) {
2185             if (frames.empty())
2186               throw py::value_error("No caller frames provided");
2187             MlirLocation caller = frames.back().get();
2188             for (const PyLocation &frame :
2189                  llvm::reverse(llvm::makeArrayRef(frames).drop_back()))
2190               caller = mlirLocationCallSiteGet(frame.get(), caller);
2191             return PyLocation(context->getRef(),
2192                               mlirLocationCallSiteGet(callee.get(), caller));
2193           },
2194           py::arg("callee"), py::arg("frames"), py::arg("context") = py::none(),
2195           kContextGetCallSiteLocationDocstring)
2196       .def_static(
2197           "file",
2198           [](std::string filename, int line, int col,
2199              DefaultingPyMlirContext context) {
2200             return PyLocation(
2201                 context->getRef(),
2202                 mlirLocationFileLineColGet(
2203                     context->get(), toMlirStringRef(filename), line, col));
2204           },
2205           py::arg("filename"), py::arg("line"), py::arg("col"),
2206           py::arg("context") = py::none(), kContextGetFileLocationDocstring)
2207       .def_static(
2208           "fused",
2209           [](const std::vector<PyLocation> &pyLocations, llvm::Optional<PyAttribute> metadata,
2210              DefaultingPyMlirContext context) {
2211             if (pyLocations.empty())
2212               throw py::value_error("No locations provided");
2213             llvm::SmallVector<MlirLocation, 4> locations;
2214             locations.reserve(pyLocations.size());
2215             for (auto &pyLocation : pyLocations)
2216               locations.push_back(pyLocation.get());
2217             MlirLocation location = mlirLocationFusedGet(
2218                 context->get(), locations.size(), locations.data(),
2219                 metadata ? metadata->get() : MlirAttribute{0});
2220             return PyLocation(context->getRef(), location);
2221           },
2222           py::arg("locations"), py::arg("metadata") = py::none(),
2223           py::arg("context") = py::none(), kContextGetFusedLocationDocstring)
2224       .def_static(
2225           "name",
2226           [](std::string name, llvm::Optional<PyLocation> childLoc,
2227              DefaultingPyMlirContext context) {
2228             return PyLocation(
2229                 context->getRef(),
2230                 mlirLocationNameGet(
2231                     context->get(), toMlirStringRef(name),
2232                     childLoc ? childLoc->get()
2233                              : mlirLocationUnknownGet(context->get())));
2234           },
2235           py::arg("name"), py::arg("childLoc") = py::none(),
2236           py::arg("context") = py::none(), kContextGetNameLocationDocString)
2237       .def_property_readonly(
2238           "context",
2239           [](PyLocation &self) { return self.getContext().getObject(); },
2240           "Context that owns the Location")
2241       .def("__repr__", [](PyLocation &self) {
2242         PyPrintAccumulator printAccum;
2243         mlirLocationPrint(self, printAccum.getCallback(),
2244                           printAccum.getUserData());
2245         return printAccum.join();
2246       });
2247 
2248   //----------------------------------------------------------------------------
2249   // Mapping of Module
2250   //----------------------------------------------------------------------------
2251   py::class_<PyModule>(m, "Module", py::module_local())
2252       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyModule::getCapsule)
2253       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyModule::createFromCapsule)
2254       .def_static(
2255           "parse",
2256           [](const std::string moduleAsm, DefaultingPyMlirContext context) {
2257             MlirModule module = mlirModuleCreateParse(
2258                 context->get(), toMlirStringRef(moduleAsm));
2259             // TODO: Rework error reporting once diagnostic engine is exposed
2260             // in C API.
2261             if (mlirModuleIsNull(module)) {
2262               throw SetPyError(
2263                   PyExc_ValueError,
2264                   "Unable to parse module assembly (see diagnostics)");
2265             }
2266             return PyModule::forModule(module).releaseObject();
2267           },
2268           py::arg("asm"), py::arg("context") = py::none(),
2269           kModuleParseDocstring)
2270       .def_static(
2271           "create",
2272           [](DefaultingPyLocation loc) {
2273             MlirModule module = mlirModuleCreateEmpty(loc);
2274             return PyModule::forModule(module).releaseObject();
2275           },
2276           py::arg("loc") = py::none(), "Creates an empty module")
2277       .def_property_readonly(
2278           "context",
2279           [](PyModule &self) { return self.getContext().getObject(); },
2280           "Context that created the Module")
2281       .def_property_readonly(
2282           "operation",
2283           [](PyModule &self) {
2284             return PyOperation::forOperation(self.getContext(),
2285                                              mlirModuleGetOperation(self.get()),
2286                                              self.getRef().releaseObject())
2287                 .releaseObject();
2288           },
2289           "Accesses the module as an operation")
2290       .def_property_readonly(
2291           "body",
2292           [](PyModule &self) {
2293             PyOperationRef moduleOp = PyOperation::forOperation(
2294                 self.getContext(), mlirModuleGetOperation(self.get()),
2295                 self.getRef().releaseObject());
2296             PyBlock returnBlock(moduleOp, mlirModuleGetBody(self.get()));
2297             return returnBlock;
2298           },
2299           "Return the block for this module")
2300       .def(
2301           "dump",
2302           [](PyModule &self) {
2303             mlirOperationDump(mlirModuleGetOperation(self.get()));
2304           },
2305           kDumpDocstring)
2306       .def(
2307           "__str__",
2308           [](py::object self) {
2309             // Defer to the operation's __str__.
2310             return self.attr("operation").attr("__str__")();
2311           },
2312           kOperationStrDunderDocstring);
2313 
2314   //----------------------------------------------------------------------------
2315   // Mapping of Operation.
2316   //----------------------------------------------------------------------------
2317   py::class_<PyOperationBase>(m, "_OperationBase", py::module_local())
2318       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
2319                              [](PyOperationBase &self) {
2320                                return self.getOperation().getCapsule();
2321                              })
2322       .def("__eq__",
2323            [](PyOperationBase &self, PyOperationBase &other) {
2324              return &self.getOperation() == &other.getOperation();
2325            })
2326       .def("__eq__",
2327            [](PyOperationBase &self, py::object other) { return false; })
2328       .def("__hash__",
2329            [](PyOperationBase &self) {
2330              return static_cast<size_t>(llvm::hash_value(&self.getOperation()));
2331            })
2332       .def_property_readonly("attributes",
2333                              [](PyOperationBase &self) {
2334                                return PyOpAttributeMap(
2335                                    self.getOperation().getRef());
2336                              })
2337       .def_property_readonly("operands",
2338                              [](PyOperationBase &self) {
2339                                return PyOpOperandList(
2340                                    self.getOperation().getRef());
2341                              })
2342       .def_property_readonly("regions",
2343                              [](PyOperationBase &self) {
2344                                return PyRegionList(
2345                                    self.getOperation().getRef());
2346                              })
2347       .def_property_readonly(
2348           "results",
2349           [](PyOperationBase &self) {
2350             return PyOpResultList(self.getOperation().getRef());
2351           },
2352           "Returns the list of Operation results.")
2353       .def_property_readonly(
2354           "result",
2355           [](PyOperationBase &self) {
2356             auto &operation = self.getOperation();
2357             auto numResults = mlirOperationGetNumResults(operation);
2358             if (numResults != 1) {
2359               auto name = mlirIdentifierStr(mlirOperationGetName(operation));
2360               throw SetPyError(
2361                   PyExc_ValueError,
2362                   Twine("Cannot call .result on operation ") +
2363                       StringRef(name.data, name.length) + " which has " +
2364                       Twine(numResults) +
2365                       " results (it is only valid for operations with a "
2366                       "single result)");
2367             }
2368             return PyOpResult(operation.getRef(),
2369                               mlirOperationGetResult(operation, 0));
2370           },
2371           "Shortcut to get an op result if it has only one (throws an error "
2372           "otherwise).")
2373       .def_property_readonly(
2374           "location",
2375           [](PyOperationBase &self) {
2376             PyOperation &operation = self.getOperation();
2377             return PyLocation(operation.getContext(),
2378                               mlirOperationGetLocation(operation.get()));
2379           },
2380           "Returns the source location the operation was defined or derived "
2381           "from.")
2382       .def(
2383           "__str__",
2384           [](PyOperationBase &self) {
2385             return self.getAsm(/*binary=*/false,
2386                                /*largeElementsLimit=*/llvm::None,
2387                                /*enableDebugInfo=*/false,
2388                                /*prettyDebugInfo=*/false,
2389                                /*printGenericOpForm=*/false,
2390                                /*useLocalScope=*/false,
2391                                /*assumeVerified=*/false);
2392           },
2393           "Returns the assembly form of the operation.")
2394       .def("print", &PyOperationBase::print,
2395            // Careful: Lots of arguments must match up with print method.
2396            py::arg("file") = py::none(), py::arg("binary") = false,
2397            py::arg("large_elements_limit") = py::none(),
2398            py::arg("enable_debug_info") = false,
2399            py::arg("pretty_debug_info") = false,
2400            py::arg("print_generic_op_form") = false,
2401            py::arg("use_local_scope") = false,
2402            py::arg("assume_verified") = false, kOperationPrintDocstring)
2403       .def("get_asm", &PyOperationBase::getAsm,
2404            // Careful: Lots of arguments must match up with get_asm method.
2405            py::arg("binary") = false,
2406            py::arg("large_elements_limit") = py::none(),
2407            py::arg("enable_debug_info") = false,
2408            py::arg("pretty_debug_info") = false,
2409            py::arg("print_generic_op_form") = false,
2410            py::arg("use_local_scope") = false,
2411            py::arg("assume_verified") = false, kOperationGetAsmDocstring)
2412       .def(
2413           "verify",
2414           [](PyOperationBase &self) {
2415             return mlirOperationVerify(self.getOperation());
2416           },
2417           "Verify the operation and return true if it passes, false if it "
2418           "fails.")
2419       .def("move_after", &PyOperationBase::moveAfter, py::arg("other"),
2420            "Puts self immediately after the other operation in its parent "
2421            "block.")
2422       .def("move_before", &PyOperationBase::moveBefore, py::arg("other"),
2423            "Puts self immediately before the other operation in its parent "
2424            "block.")
2425       .def(
2426           "detach_from_parent",
2427           [](PyOperationBase &self) {
2428             PyOperation &operation = self.getOperation();
2429             operation.checkValid();
2430             if (!operation.isAttached())
2431               throw py::value_error("Detached operation has no parent.");
2432 
2433             operation.detachFromParent();
2434             return operation.createOpView();
2435           },
2436           "Detaches the operation from its parent block.");
2437 
2438   py::class_<PyOperation, PyOperationBase>(m, "Operation", py::module_local())
2439       .def_static("create", &PyOperation::create, py::arg("name"),
2440                   py::arg("results") = py::none(),
2441                   py::arg("operands") = py::none(),
2442                   py::arg("attributes") = py::none(),
2443                   py::arg("successors") = py::none(), py::arg("regions") = 0,
2444                   py::arg("loc") = py::none(), py::arg("ip") = py::none(),
2445                   kOperationCreateDocstring)
2446       .def_property_readonly("parent",
2447                              [](PyOperation &self) -> py::object {
2448                                auto parent = self.getParentOperation();
2449                                if (parent)
2450                                  return parent->getObject();
2451                                return py::none();
2452                              })
2453       .def("erase", &PyOperation::erase)
2454       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
2455                              &PyOperation::getCapsule)
2456       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyOperation::createFromCapsule)
2457       .def_property_readonly("name",
2458                              [](PyOperation &self) {
2459                                self.checkValid();
2460                                MlirOperation operation = self.get();
2461                                MlirStringRef name = mlirIdentifierStr(
2462                                    mlirOperationGetName(operation));
2463                                return py::str(name.data, name.length);
2464                              })
2465       .def_property_readonly(
2466           "context",
2467           [](PyOperation &self) {
2468             self.checkValid();
2469             return self.getContext().getObject();
2470           },
2471           "Context that owns the Operation")
2472       .def_property_readonly("opview", &PyOperation::createOpView);
2473 
2474   auto opViewClass =
2475       py::class_<PyOpView, PyOperationBase>(m, "OpView", py::module_local())
2476           .def(py::init<py::object>(), py::arg("operation"))
2477           .def_property_readonly("operation", &PyOpView::getOperationObject)
2478           .def_property_readonly(
2479               "context",
2480               [](PyOpView &self) {
2481                 return self.getOperation().getContext().getObject();
2482               },
2483               "Context that owns the Operation")
2484           .def("__str__", [](PyOpView &self) {
2485             return py::str(self.getOperationObject());
2486           });
2487   opViewClass.attr("_ODS_REGIONS") = py::make_tuple(0, true);
2488   opViewClass.attr("_ODS_OPERAND_SEGMENTS") = py::none();
2489   opViewClass.attr("_ODS_RESULT_SEGMENTS") = py::none();
2490   opViewClass.attr("build_generic") = classmethod(
2491       &PyOpView::buildGeneric, py::arg("cls"), py::arg("results") = py::none(),
2492       py::arg("operands") = py::none(), py::arg("attributes") = py::none(),
2493       py::arg("successors") = py::none(), py::arg("regions") = py::none(),
2494       py::arg("loc") = py::none(), py::arg("ip") = py::none(),
2495       "Builds a specific, generated OpView based on class level attributes.");
2496 
2497   //----------------------------------------------------------------------------
2498   // Mapping of PyRegion.
2499   //----------------------------------------------------------------------------
2500   py::class_<PyRegion>(m, "Region", py::module_local())
2501       .def_property_readonly(
2502           "blocks",
2503           [](PyRegion &self) {
2504             return PyBlockList(self.getParentOperation(), self.get());
2505           },
2506           "Returns a forward-optimized sequence of blocks.")
2507       .def_property_readonly(
2508           "owner",
2509           [](PyRegion &self) {
2510             return self.getParentOperation()->createOpView();
2511           },
2512           "Returns the operation owning this region.")
2513       .def(
2514           "__iter__",
2515           [](PyRegion &self) {
2516             self.checkValid();
2517             MlirBlock firstBlock = mlirRegionGetFirstBlock(self.get());
2518             return PyBlockIterator(self.getParentOperation(), firstBlock);
2519           },
2520           "Iterates over blocks in the region.")
2521       .def("__eq__",
2522            [](PyRegion &self, PyRegion &other) {
2523              return self.get().ptr == other.get().ptr;
2524            })
2525       .def("__eq__", [](PyRegion &self, py::object &other) { return false; });
2526 
2527   //----------------------------------------------------------------------------
2528   // Mapping of PyBlock.
2529   //----------------------------------------------------------------------------
2530   py::class_<PyBlock>(m, "Block", py::module_local())
2531       .def_property_readonly(
2532           "owner",
2533           [](PyBlock &self) {
2534             return self.getParentOperation()->createOpView();
2535           },
2536           "Returns the owning operation of this block.")
2537       .def_property_readonly(
2538           "region",
2539           [](PyBlock &self) {
2540             MlirRegion region = mlirBlockGetParentRegion(self.get());
2541             return PyRegion(self.getParentOperation(), region);
2542           },
2543           "Returns the owning region of this block.")
2544       .def_property_readonly(
2545           "arguments",
2546           [](PyBlock &self) {
2547             return PyBlockArgumentList(self.getParentOperation(), self.get());
2548           },
2549           "Returns a list of block arguments.")
2550       .def_property_readonly(
2551           "operations",
2552           [](PyBlock &self) {
2553             return PyOperationList(self.getParentOperation(), self.get());
2554           },
2555           "Returns a forward-optimized sequence of operations.")
2556       .def_static(
2557           "create_at_start",
2558           [](PyRegion &parent, py::list pyArgTypes) {
2559             parent.checkValid();
2560             llvm::SmallVector<MlirType, 4> argTypes;
2561             argTypes.reserve(pyArgTypes.size());
2562             for (auto &pyArg : pyArgTypes) {
2563               argTypes.push_back(pyArg.cast<PyType &>());
2564             }
2565 
2566             MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
2567             mlirRegionInsertOwnedBlock(parent, 0, block);
2568             return PyBlock(parent.getParentOperation(), block);
2569           },
2570           py::arg("parent"), py::arg("arg_types") = py::list(),
2571           "Creates and returns a new Block at the beginning of the given "
2572           "region (with given argument types).")
2573       .def(
2574           "create_before",
2575           [](PyBlock &self, py::args pyArgTypes) {
2576             self.checkValid();
2577             llvm::SmallVector<MlirType, 4> argTypes;
2578             argTypes.reserve(pyArgTypes.size());
2579             for (auto &pyArg : pyArgTypes) {
2580               argTypes.push_back(pyArg.cast<PyType &>());
2581             }
2582 
2583             MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
2584             MlirRegion region = mlirBlockGetParentRegion(self.get());
2585             mlirRegionInsertOwnedBlockBefore(region, self.get(), block);
2586             return PyBlock(self.getParentOperation(), block);
2587           },
2588           "Creates and returns a new Block before this block "
2589           "(with given argument types).")
2590       .def(
2591           "create_after",
2592           [](PyBlock &self, py::args pyArgTypes) {
2593             self.checkValid();
2594             llvm::SmallVector<MlirType, 4> argTypes;
2595             argTypes.reserve(pyArgTypes.size());
2596             for (auto &pyArg : pyArgTypes) {
2597               argTypes.push_back(pyArg.cast<PyType &>());
2598             }
2599 
2600             MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
2601             MlirRegion region = mlirBlockGetParentRegion(self.get());
2602             mlirRegionInsertOwnedBlockAfter(region, self.get(), block);
2603             return PyBlock(self.getParentOperation(), block);
2604           },
2605           "Creates and returns a new Block after this block "
2606           "(with given argument types).")
2607       .def(
2608           "__iter__",
2609           [](PyBlock &self) {
2610             self.checkValid();
2611             MlirOperation firstOperation =
2612                 mlirBlockGetFirstOperation(self.get());
2613             return PyOperationIterator(self.getParentOperation(),
2614                                        firstOperation);
2615           },
2616           "Iterates over operations in the block.")
2617       .def("__eq__",
2618            [](PyBlock &self, PyBlock &other) {
2619              return self.get().ptr == other.get().ptr;
2620            })
2621       .def("__eq__", [](PyBlock &self, py::object &other) { return false; })
2622       .def(
2623           "__str__",
2624           [](PyBlock &self) {
2625             self.checkValid();
2626             PyPrintAccumulator printAccum;
2627             mlirBlockPrint(self.get(), printAccum.getCallback(),
2628                            printAccum.getUserData());
2629             return printAccum.join();
2630           },
2631           "Returns the assembly form of the block.")
2632       .def(
2633           "append",
2634           [](PyBlock &self, PyOperationBase &operation) {
2635             if (operation.getOperation().isAttached())
2636               operation.getOperation().detachFromParent();
2637 
2638             MlirOperation mlirOperation = operation.getOperation().get();
2639             mlirBlockAppendOwnedOperation(self.get(), mlirOperation);
2640             operation.getOperation().setAttached(
2641                 self.getParentOperation().getObject());
2642           },
2643           py::arg("operation"),
2644           "Appends an operation to this block. If the operation is currently "
2645           "in another block, it will be moved.");
2646 
2647   //----------------------------------------------------------------------------
2648   // Mapping of PyInsertionPoint.
2649   //----------------------------------------------------------------------------
2650 
2651   py::class_<PyInsertionPoint>(m, "InsertionPoint", py::module_local())
2652       .def(py::init<PyBlock &>(), py::arg("block"),
2653            "Inserts after the last operation but still inside the block.")
2654       .def("__enter__", &PyInsertionPoint::contextEnter)
2655       .def("__exit__", &PyInsertionPoint::contextExit)
2656       .def_property_readonly_static(
2657           "current",
2658           [](py::object & /*class*/) {
2659             auto *ip = PyThreadContextEntry::getDefaultInsertionPoint();
2660             if (!ip)
2661               throw SetPyError(PyExc_ValueError, "No current InsertionPoint");
2662             return ip;
2663           },
2664           "Gets the InsertionPoint bound to the current thread or raises "
2665           "ValueError if none has been set")
2666       .def(py::init<PyOperationBase &>(), py::arg("beforeOperation"),
2667            "Inserts before a referenced operation.")
2668       .def_static("at_block_begin", &PyInsertionPoint::atBlockBegin,
2669                   py::arg("block"), "Inserts at the beginning of the block.")
2670       .def_static("at_block_terminator", &PyInsertionPoint::atBlockTerminator,
2671                   py::arg("block"), "Inserts before the block terminator.")
2672       .def("insert", &PyInsertionPoint::insert, py::arg("operation"),
2673            "Inserts an operation.")
2674       .def_property_readonly(
2675           "block", [](PyInsertionPoint &self) { return self.getBlock(); },
2676           "Returns the block that this InsertionPoint points to.");
2677 
2678   //----------------------------------------------------------------------------
2679   // Mapping of PyAttribute.
2680   //----------------------------------------------------------------------------
2681   py::class_<PyAttribute>(m, "Attribute", py::module_local())
2682       // Delegate to the PyAttribute copy constructor, which will also lifetime
2683       // extend the backing context which owns the MlirAttribute.
2684       .def(py::init<PyAttribute &>(), py::arg("cast_from_type"),
2685            "Casts the passed attribute to the generic Attribute")
2686       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
2687                              &PyAttribute::getCapsule)
2688       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyAttribute::createFromCapsule)
2689       .def_static(
2690           "parse",
2691           [](std::string attrSpec, DefaultingPyMlirContext context) {
2692             MlirAttribute type = mlirAttributeParseGet(
2693                 context->get(), toMlirStringRef(attrSpec));
2694             // TODO: Rework error reporting once diagnostic engine is exposed
2695             // in C API.
2696             if (mlirAttributeIsNull(type)) {
2697               throw SetPyError(PyExc_ValueError,
2698                                Twine("Unable to parse attribute: '") +
2699                                    attrSpec + "'");
2700             }
2701             return PyAttribute(context->getRef(), type);
2702           },
2703           py::arg("asm"), py::arg("context") = py::none(),
2704           "Parses an attribute from an assembly form")
2705       .def_property_readonly(
2706           "context",
2707           [](PyAttribute &self) { return self.getContext().getObject(); },
2708           "Context that owns the Attribute")
2709       .def_property_readonly("type",
2710                              [](PyAttribute &self) {
2711                                return PyType(self.getContext()->getRef(),
2712                                              mlirAttributeGetType(self));
2713                              })
2714       .def(
2715           "get_named",
2716           [](PyAttribute &self, std::string name) {
2717             return PyNamedAttribute(self, std::move(name));
2718           },
2719           py::keep_alive<0, 1>(), "Binds a name to the attribute")
2720       .def("__eq__",
2721            [](PyAttribute &self, PyAttribute &other) { return self == other; })
2722       .def("__eq__", [](PyAttribute &self, py::object &other) { return false; })
2723       .def("__hash__",
2724            [](PyAttribute &self) {
2725              return static_cast<size_t>(llvm::hash_value(self.get().ptr));
2726            })
2727       .def(
2728           "dump", [](PyAttribute &self) { mlirAttributeDump(self); },
2729           kDumpDocstring)
2730       .def(
2731           "__str__",
2732           [](PyAttribute &self) {
2733             PyPrintAccumulator printAccum;
2734             mlirAttributePrint(self, printAccum.getCallback(),
2735                                printAccum.getUserData());
2736             return printAccum.join();
2737           },
2738           "Returns the assembly form of the Attribute.")
2739       .def("__repr__", [](PyAttribute &self) {
2740         // Generally, assembly formats are not printed for __repr__ because
2741         // this can cause exceptionally long debug output and exceptions.
2742         // However, attribute values are generally considered useful and are
2743         // printed. This may need to be re-evaluated if debug dumps end up
2744         // being excessive.
2745         PyPrintAccumulator printAccum;
2746         printAccum.parts.append("Attribute(");
2747         mlirAttributePrint(self, printAccum.getCallback(),
2748                            printAccum.getUserData());
2749         printAccum.parts.append(")");
2750         return printAccum.join();
2751       });
2752 
2753   //----------------------------------------------------------------------------
2754   // Mapping of PyNamedAttribute
2755   //----------------------------------------------------------------------------
2756   py::class_<PyNamedAttribute>(m, "NamedAttribute", py::module_local())
2757       .def("__repr__",
2758            [](PyNamedAttribute &self) {
2759              PyPrintAccumulator printAccum;
2760              printAccum.parts.append("NamedAttribute(");
2761              printAccum.parts.append(
2762                  py::str(mlirIdentifierStr(self.namedAttr.name).data,
2763                          mlirIdentifierStr(self.namedAttr.name).length));
2764              printAccum.parts.append("=");
2765              mlirAttributePrint(self.namedAttr.attribute,
2766                                 printAccum.getCallback(),
2767                                 printAccum.getUserData());
2768              printAccum.parts.append(")");
2769              return printAccum.join();
2770            })
2771       .def_property_readonly(
2772           "name",
2773           [](PyNamedAttribute &self) {
2774             return py::str(mlirIdentifierStr(self.namedAttr.name).data,
2775                            mlirIdentifierStr(self.namedAttr.name).length);
2776           },
2777           "The name of the NamedAttribute binding")
2778       .def_property_readonly(
2779           "attr",
2780           [](PyNamedAttribute &self) {
2781             // TODO: When named attribute is removed/refactored, also remove
2782             // this constructor (it does an inefficient table lookup).
2783             auto contextRef = PyMlirContext::forContext(
2784                 mlirAttributeGetContext(self.namedAttr.attribute));
2785             return PyAttribute(std::move(contextRef), self.namedAttr.attribute);
2786           },
2787           py::keep_alive<0, 1>(),
2788           "The underlying generic attribute of the NamedAttribute binding");
2789 
2790   //----------------------------------------------------------------------------
2791   // Mapping of PyType.
2792   //----------------------------------------------------------------------------
2793   py::class_<PyType>(m, "Type", py::module_local())
2794       // Delegate to the PyType copy constructor, which will also lifetime
2795       // extend the backing context which owns the MlirType.
2796       .def(py::init<PyType &>(), py::arg("cast_from_type"),
2797            "Casts the passed type to the generic Type")
2798       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyType::getCapsule)
2799       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyType::createFromCapsule)
2800       .def_static(
2801           "parse",
2802           [](std::string typeSpec, DefaultingPyMlirContext context) {
2803             MlirType type =
2804                 mlirTypeParseGet(context->get(), toMlirStringRef(typeSpec));
2805             // TODO: Rework error reporting once diagnostic engine is exposed
2806             // in C API.
2807             if (mlirTypeIsNull(type)) {
2808               throw SetPyError(PyExc_ValueError,
2809                                Twine("Unable to parse type: '") + typeSpec +
2810                                    "'");
2811             }
2812             return PyType(context->getRef(), type);
2813           },
2814           py::arg("asm"), py::arg("context") = py::none(),
2815           kContextParseTypeDocstring)
2816       .def_property_readonly(
2817           "context", [](PyType &self) { return self.getContext().getObject(); },
2818           "Context that owns the Type")
2819       .def("__eq__", [](PyType &self, PyType &other) { return self == other; })
2820       .def("__eq__", [](PyType &self, py::object &other) { return false; })
2821       .def("__hash__",
2822            [](PyType &self) {
2823              return static_cast<size_t>(llvm::hash_value(self.get().ptr));
2824            })
2825       .def(
2826           "dump", [](PyType &self) { mlirTypeDump(self); }, kDumpDocstring)
2827       .def(
2828           "__str__",
2829           [](PyType &self) {
2830             PyPrintAccumulator printAccum;
2831             mlirTypePrint(self, printAccum.getCallback(),
2832                           printAccum.getUserData());
2833             return printAccum.join();
2834           },
2835           "Returns the assembly form of the type.")
2836       .def("__repr__", [](PyType &self) {
2837         // Generally, assembly formats are not printed for __repr__ because
2838         // this can cause exceptionally long debug output and exceptions.
2839         // However, types are an exception as they typically have compact
2840         // assembly forms and printing them is useful.
2841         PyPrintAccumulator printAccum;
2842         printAccum.parts.append("Type(");
2843         mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData());
2844         printAccum.parts.append(")");
2845         return printAccum.join();
2846       });
2847 
2848   //----------------------------------------------------------------------------
2849   // Mapping of Value.
2850   //----------------------------------------------------------------------------
2851   py::class_<PyValue>(m, "Value", py::module_local())
2852       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyValue::getCapsule)
2853       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyValue::createFromCapsule)
2854       .def_property_readonly(
2855           "context",
2856           [](PyValue &self) { return self.getParentOperation()->getContext(); },
2857           "Context in which the value lives.")
2858       .def(
2859           "dump", [](PyValue &self) { mlirValueDump(self.get()); },
2860           kDumpDocstring)
2861       .def_property_readonly(
2862           "owner",
2863           [](PyValue &self) {
2864             assert(mlirOperationEqual(self.getParentOperation()->get(),
2865                                       mlirOpResultGetOwner(self.get())) &&
2866                    "expected the owner of the value in Python to match that in "
2867                    "the IR");
2868             return self.getParentOperation().getObject();
2869           })
2870       .def("__eq__",
2871            [](PyValue &self, PyValue &other) {
2872              return self.get().ptr == other.get().ptr;
2873            })
2874       .def("__eq__", [](PyValue &self, py::object other) { return false; })
2875       .def("__hash__",
2876            [](PyValue &self) {
2877              return static_cast<size_t>(llvm::hash_value(self.get().ptr));
2878            })
2879       .def(
2880           "__str__",
2881           [](PyValue &self) {
2882             PyPrintAccumulator printAccum;
2883             printAccum.parts.append("Value(");
2884             mlirValuePrint(self.get(), printAccum.getCallback(),
2885                            printAccum.getUserData());
2886             printAccum.parts.append(")");
2887             return printAccum.join();
2888           },
2889           kValueDunderStrDocstring)
2890       .def_property_readonly("type", [](PyValue &self) {
2891         return PyType(self.getParentOperation()->getContext(),
2892                       mlirValueGetType(self.get()));
2893       });
2894   PyBlockArgument::bind(m);
2895   PyOpResult::bind(m);
2896 
2897   //----------------------------------------------------------------------------
2898   // Mapping of SymbolTable.
2899   //----------------------------------------------------------------------------
2900   py::class_<PySymbolTable>(m, "SymbolTable", py::module_local())
2901       .def(py::init<PyOperationBase &>())
2902       .def("__getitem__", &PySymbolTable::dunderGetItem)
2903       .def("insert", &PySymbolTable::insert, py::arg("operation"))
2904       .def("erase", &PySymbolTable::erase, py::arg("operation"))
2905       .def("__delitem__", &PySymbolTable::dunderDel)
2906       .def("__contains__",
2907            [](PySymbolTable &table, const std::string &name) {
2908              return !mlirOperationIsNull(mlirSymbolTableLookup(
2909                  table, mlirStringRefCreate(name.data(), name.length())));
2910            })
2911       // Static helpers.
2912       .def_static("set_symbol_name", &PySymbolTable::setSymbolName,
2913                   py::arg("symbol"), py::arg("name"))
2914       .def_static("get_symbol_name", &PySymbolTable::getSymbolName,
2915                   py::arg("symbol"))
2916       .def_static("get_visibility", &PySymbolTable::getVisibility,
2917                   py::arg("symbol"))
2918       .def_static("set_visibility", &PySymbolTable::setVisibility,
2919                   py::arg("symbol"), py::arg("visibility"))
2920       .def_static("replace_all_symbol_uses",
2921                   &PySymbolTable::replaceAllSymbolUses, py::arg("old_symbol"),
2922                   py::arg("new_symbol"), py::arg("from_op"))
2923       .def_static("walk_symbol_tables", &PySymbolTable::walkSymbolTables,
2924                   py::arg("from_op"), py::arg("all_sym_uses_visible"),
2925                   py::arg("callback"));
2926 
2927   // Container bindings.
2928   PyBlockArgumentList::bind(m);
2929   PyBlockIterator::bind(m);
2930   PyBlockList::bind(m);
2931   PyOperationIterator::bind(m);
2932   PyOperationList::bind(m);
2933   PyOpAttributeMap::bind(m);
2934   PyOpOperandList::bind(m);
2935   PyOpResultList::bind(m);
2936   PyRegionIterator::bind(m);
2937   PyRegionList::bind(m);
2938 
2939   // Debug bindings.
2940   PyGlobalDebugFlag::bind(m);
2941 }
2942