1436c6c9cSStella Laurenzo //===- IRModules.cpp - IR Submodules of pybind module ---------------------===//
2436c6c9cSStella Laurenzo //
3436c6c9cSStella Laurenzo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4436c6c9cSStella Laurenzo // See https://llvm.org/LICENSE.txt for license information.
5436c6c9cSStella Laurenzo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6436c6c9cSStella Laurenzo //
7436c6c9cSStella Laurenzo //===----------------------------------------------------------------------===//
8436c6c9cSStella Laurenzo 
9436c6c9cSStella Laurenzo #include "IRModule.h"
10436c6c9cSStella Laurenzo 
11436c6c9cSStella Laurenzo #include "Globals.h"
12436c6c9cSStella Laurenzo #include "PybindUtils.h"
13436c6c9cSStella Laurenzo 
14436c6c9cSStella Laurenzo #include "mlir-c/Bindings/Python/Interop.h"
15436c6c9cSStella Laurenzo #include "mlir-c/BuiltinAttributes.h"
16436c6c9cSStella Laurenzo #include "mlir-c/BuiltinTypes.h"
174acd8457SAlex Zinenko #include "mlir-c/Debug.h"
183f3d1c90SMike Urbach #include "mlir-c/IR.h"
19436c6c9cSStella Laurenzo #include "mlir-c/Registration.h"
20e67cbbefSJacques Pienaar #include "llvm/ADT/ArrayRef.h"
21436c6c9cSStella Laurenzo #include "llvm/ADT/SmallVector.h"
22436c6c9cSStella Laurenzo #include <pybind11/stl.h>
23436c6c9cSStella Laurenzo 
241fc096afSMehdi Amini #include <utility>
251fc096afSMehdi Amini 
26436c6c9cSStella Laurenzo namespace py = pybind11;
27436c6c9cSStella Laurenzo using namespace mlir;
28436c6c9cSStella Laurenzo using namespace mlir::python;
29436c6c9cSStella Laurenzo 
30436c6c9cSStella Laurenzo using llvm::SmallVector;
31436c6c9cSStella Laurenzo using llvm::StringRef;
32436c6c9cSStella Laurenzo using llvm::Twine;
33436c6c9cSStella Laurenzo 
34436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
35436c6c9cSStella Laurenzo // Docstrings (trivial, non-duplicated docstrings are included inline).
36436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
37436c6c9cSStella Laurenzo 
38436c6c9cSStella Laurenzo static const char kContextParseTypeDocstring[] =
39436c6c9cSStella Laurenzo     R"(Parses the assembly form of a type.
40436c6c9cSStella Laurenzo 
41436c6c9cSStella Laurenzo Returns a Type object or raises a ValueError if the type cannot be parsed.
42436c6c9cSStella Laurenzo 
43436c6c9cSStella Laurenzo See also: https://mlir.llvm.org/docs/LangRef/#type-system
44436c6c9cSStella Laurenzo )";
45436c6c9cSStella Laurenzo 
46e67cbbefSJacques Pienaar static const char kContextGetCallSiteLocationDocstring[] =
47e67cbbefSJacques Pienaar     R"(Gets a Location representing a caller and callsite)";
48e67cbbefSJacques Pienaar 
49436c6c9cSStella Laurenzo static const char kContextGetFileLocationDocstring[] =
50436c6c9cSStella Laurenzo     R"(Gets a Location representing a file, line and column)";
51436c6c9cSStella Laurenzo 
521ab3efacSJacques Pienaar static const char kContextGetFusedLocationDocstring[] =
531ab3efacSJacques Pienaar     R"(Gets a Location representing a fused location with optional metadata)";
541ab3efacSJacques Pienaar 
5504d76d36SJacques Pienaar static const char kContextGetNameLocationDocString[] =
5604d76d36SJacques Pienaar     R"(Gets a Location representing a named location with optional child location)";
5704d76d36SJacques Pienaar 
58436c6c9cSStella Laurenzo static const char kModuleParseDocstring[] =
59436c6c9cSStella Laurenzo     R"(Parses a module's assembly format from a string.
60436c6c9cSStella Laurenzo 
61436c6c9cSStella Laurenzo Returns a new MlirModule or raises a ValueError if the parsing fails.
62436c6c9cSStella Laurenzo 
63436c6c9cSStella Laurenzo See also: https://mlir.llvm.org/docs/LangRef/
64436c6c9cSStella Laurenzo )";
65436c6c9cSStella Laurenzo 
66436c6c9cSStella Laurenzo static const char kOperationCreateDocstring[] =
67436c6c9cSStella Laurenzo     R"(Creates a new operation.
68436c6c9cSStella Laurenzo 
69436c6c9cSStella Laurenzo Args:
70436c6c9cSStella Laurenzo   name: Operation name (e.g. "dialect.operation").
71436c6c9cSStella Laurenzo   results: Sequence of Type representing op result types.
72436c6c9cSStella Laurenzo   attributes: Dict of str:Attribute.
73436c6c9cSStella Laurenzo   successors: List of Block for the operation's successors.
74436c6c9cSStella Laurenzo   regions: Number of regions to create.
75436c6c9cSStella Laurenzo   location: A Location object (defaults to resolve from context manager).
76436c6c9cSStella Laurenzo   ip: An InsertionPoint (defaults to resolve from context manager or set to
77436c6c9cSStella Laurenzo     False to disable insertion, even with an insertion point set in the
78436c6c9cSStella Laurenzo     context manager).
79436c6c9cSStella Laurenzo Returns:
80436c6c9cSStella Laurenzo   A new "detached" Operation object. Detached operations can be added
81436c6c9cSStella Laurenzo   to blocks, which causes them to become "attached."
82436c6c9cSStella Laurenzo )";
83436c6c9cSStella Laurenzo 
84436c6c9cSStella Laurenzo static const char kOperationPrintDocstring[] =
85436c6c9cSStella Laurenzo     R"(Prints the assembly form of the operation to a file like object.
86436c6c9cSStella Laurenzo 
87436c6c9cSStella Laurenzo Args:
88436c6c9cSStella Laurenzo   file: The file like object to write to. Defaults to sys.stdout.
89436c6c9cSStella Laurenzo   binary: Whether to write bytes (True) or str (False). Defaults to False.
90436c6c9cSStella Laurenzo   large_elements_limit: Whether to elide elements attributes above this
91436c6c9cSStella Laurenzo     number of elements. Defaults to None (no limit).
92436c6c9cSStella Laurenzo   enable_debug_info: Whether to print debug/location information. Defaults
93436c6c9cSStella Laurenzo     to False.
94436c6c9cSStella Laurenzo   pretty_debug_info: Whether to format debug information for easier reading
95436c6c9cSStella Laurenzo     by a human (warning: the result is unparseable).
96436c6c9cSStella Laurenzo   print_generic_op_form: Whether to print the generic assembly forms of all
97436c6c9cSStella Laurenzo     ops. Defaults to False.
98436c6c9cSStella Laurenzo   use_local_Scope: Whether to print in a way that is more optimized for
99436c6c9cSStella Laurenzo     multi-threaded access but may not be consistent with how the overall
100436c6c9cSStella Laurenzo     module prints.
101ace1d0adSStella Laurenzo   assume_verified: By default, if not printing generic form, the verifier
102ace1d0adSStella Laurenzo     will be run and if it fails, generic form will be printed with a comment
103ace1d0adSStella Laurenzo     about failed verification. While a reasonable default for interactive use,
104ace1d0adSStella Laurenzo     for systematic use, it is often better for the caller to verify explicitly
105ace1d0adSStella Laurenzo     and report failures in a more robust fashion. Set this to True if doing this
106ace1d0adSStella Laurenzo     in order to avoid running a redundant verification. If the IR is actually
107ace1d0adSStella Laurenzo     invalid, behavior is undefined.
108436c6c9cSStella Laurenzo )";
109436c6c9cSStella Laurenzo 
110436c6c9cSStella Laurenzo static const char kOperationGetAsmDocstring[] =
111436c6c9cSStella Laurenzo     R"(Gets the assembly form of the operation with all options available.
112436c6c9cSStella Laurenzo 
113436c6c9cSStella Laurenzo Args:
114436c6c9cSStella Laurenzo   binary: Whether to return a bytes (True) or str (False) object. Defaults to
115436c6c9cSStella Laurenzo     False.
116436c6c9cSStella Laurenzo   ... others ...: See the print() method for common keyword arguments for
117436c6c9cSStella Laurenzo     configuring the printout.
118436c6c9cSStella Laurenzo Returns:
119436c6c9cSStella Laurenzo   Either a bytes or str object, depending on the setting of the 'binary'
120436c6c9cSStella Laurenzo   argument.
121436c6c9cSStella Laurenzo )";
122436c6c9cSStella Laurenzo 
123436c6c9cSStella Laurenzo static const char kOperationStrDunderDocstring[] =
124436c6c9cSStella Laurenzo     R"(Gets the assembly form of the operation with default options.
125436c6c9cSStella Laurenzo 
126436c6c9cSStella Laurenzo If more advanced control over the assembly formatting or I/O options is needed,
127436c6c9cSStella Laurenzo use the dedicated print or get_asm method, which supports keyword arguments to
128436c6c9cSStella Laurenzo customize behavior.
129436c6c9cSStella Laurenzo )";
130436c6c9cSStella Laurenzo 
131436c6c9cSStella Laurenzo static const char kDumpDocstring[] =
132436c6c9cSStella Laurenzo     R"(Dumps a debug representation of the object to stderr.)";
133436c6c9cSStella Laurenzo 
134436c6c9cSStella Laurenzo static const char kAppendBlockDocstring[] =
135436c6c9cSStella Laurenzo     R"(Appends a new block, with argument types as positional args.
136436c6c9cSStella Laurenzo 
137436c6c9cSStella Laurenzo Returns:
138436c6c9cSStella Laurenzo   The created block.
139436c6c9cSStella Laurenzo )";
140436c6c9cSStella Laurenzo 
141436c6c9cSStella Laurenzo static const char kValueDunderStrDocstring[] =
142436c6c9cSStella Laurenzo     R"(Returns the string form of the value.
143436c6c9cSStella Laurenzo 
144436c6c9cSStella Laurenzo If the value is a block argument, this is the assembly form of its type and the
145436c6c9cSStella Laurenzo position in the argument list. If the value is an operation result, this is
146436c6c9cSStella Laurenzo equivalent to printing the operation that produced it.
147436c6c9cSStella Laurenzo )";
148436c6c9cSStella Laurenzo 
149436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
150436c6c9cSStella Laurenzo // Utilities.
151436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
152436c6c9cSStella Laurenzo 
1534acd8457SAlex Zinenko /// Helper for creating an @classmethod.
154436c6c9cSStella Laurenzo template <class Func, typename... Args>
155436c6c9cSStella Laurenzo py::object classmethod(Func f, Args... args) {
156436c6c9cSStella Laurenzo   py::object cf = py::cpp_function(f, args...);
157436c6c9cSStella Laurenzo   return py::reinterpret_borrow<py::object>((PyClassMethod_New(cf.ptr())));
158436c6c9cSStella Laurenzo }
159436c6c9cSStella Laurenzo 
160436c6c9cSStella Laurenzo static py::object
161436c6c9cSStella Laurenzo createCustomDialectWrapper(const std::string &dialectNamespace,
162436c6c9cSStella Laurenzo                            py::object dialectDescriptor) {
163436c6c9cSStella Laurenzo   auto dialectClass = PyGlobals::get().lookupDialectClass(dialectNamespace);
164436c6c9cSStella Laurenzo   if (!dialectClass) {
165436c6c9cSStella Laurenzo     // Use the base class.
166436c6c9cSStella Laurenzo     return py::cast(PyDialect(std::move(dialectDescriptor)));
167436c6c9cSStella Laurenzo   }
168436c6c9cSStella Laurenzo 
169436c6c9cSStella Laurenzo   // Create the custom implementation.
170436c6c9cSStella Laurenzo   return (*dialectClass)(std::move(dialectDescriptor));
171436c6c9cSStella Laurenzo }
172436c6c9cSStella Laurenzo 
173436c6c9cSStella Laurenzo static MlirStringRef toMlirStringRef(const std::string &s) {
174436c6c9cSStella Laurenzo   return mlirStringRefCreate(s.data(), s.size());
175436c6c9cSStella Laurenzo }
176436c6c9cSStella Laurenzo 
1774acd8457SAlex Zinenko /// Wrapper for the global LLVM debugging flag.
1784acd8457SAlex Zinenko struct PyGlobalDebugFlag {
1794acd8457SAlex Zinenko   static void set(py::object &o, bool enable) { mlirEnableGlobalDebug(enable); }
1804acd8457SAlex Zinenko 
1811fc096afSMehdi Amini   static bool get(const py::object &) { return mlirIsGlobalDebugEnabled(); }
1824acd8457SAlex Zinenko 
1834acd8457SAlex Zinenko   static void bind(py::module &m) {
1844acd8457SAlex Zinenko     // Debug flags.
185f05ff4f7SStella Laurenzo     py::class_<PyGlobalDebugFlag>(m, "_GlobalDebug", py::module_local())
1864acd8457SAlex Zinenko         .def_property_static("flag", &PyGlobalDebugFlag::get,
1874acd8457SAlex Zinenko                              &PyGlobalDebugFlag::set, "LLVM-wide debug flag");
1884acd8457SAlex Zinenko   }
1894acd8457SAlex Zinenko };
1904acd8457SAlex Zinenko 
191436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
192436c6c9cSStella Laurenzo // Collections.
193436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
194436c6c9cSStella Laurenzo 
195436c6c9cSStella Laurenzo namespace {
196436c6c9cSStella Laurenzo 
197436c6c9cSStella Laurenzo class PyRegionIterator {
198436c6c9cSStella Laurenzo public:
199436c6c9cSStella Laurenzo   PyRegionIterator(PyOperationRef operation)
200436c6c9cSStella Laurenzo       : operation(std::move(operation)) {}
201436c6c9cSStella Laurenzo 
202436c6c9cSStella Laurenzo   PyRegionIterator &dunderIter() { return *this; }
203436c6c9cSStella Laurenzo 
204436c6c9cSStella Laurenzo   PyRegion dunderNext() {
205436c6c9cSStella Laurenzo     operation->checkValid();
206436c6c9cSStella Laurenzo     if (nextIndex >= mlirOperationGetNumRegions(operation->get())) {
207436c6c9cSStella Laurenzo       throw py::stop_iteration();
208436c6c9cSStella Laurenzo     }
209436c6c9cSStella Laurenzo     MlirRegion region = mlirOperationGetRegion(operation->get(), nextIndex++);
210436c6c9cSStella Laurenzo     return PyRegion(operation, region);
211436c6c9cSStella Laurenzo   }
212436c6c9cSStella Laurenzo 
213436c6c9cSStella Laurenzo   static void bind(py::module &m) {
214f05ff4f7SStella Laurenzo     py::class_<PyRegionIterator>(m, "RegionIterator", py::module_local())
215436c6c9cSStella Laurenzo         .def("__iter__", &PyRegionIterator::dunderIter)
216436c6c9cSStella Laurenzo         .def("__next__", &PyRegionIterator::dunderNext);
217436c6c9cSStella Laurenzo   }
218436c6c9cSStella Laurenzo 
219436c6c9cSStella Laurenzo private:
220436c6c9cSStella Laurenzo   PyOperationRef operation;
221436c6c9cSStella Laurenzo   int nextIndex = 0;
222436c6c9cSStella Laurenzo };
223436c6c9cSStella Laurenzo 
224436c6c9cSStella Laurenzo /// Regions of an op are fixed length and indexed numerically so are represented
225436c6c9cSStella Laurenzo /// with a sequence-like container.
226436c6c9cSStella Laurenzo class PyRegionList {
227436c6c9cSStella Laurenzo public:
228436c6c9cSStella Laurenzo   PyRegionList(PyOperationRef operation) : operation(std::move(operation)) {}
229436c6c9cSStella Laurenzo 
230436c6c9cSStella Laurenzo   intptr_t dunderLen() {
231436c6c9cSStella Laurenzo     operation->checkValid();
232436c6c9cSStella Laurenzo     return mlirOperationGetNumRegions(operation->get());
233436c6c9cSStella Laurenzo   }
234436c6c9cSStella Laurenzo 
235436c6c9cSStella Laurenzo   PyRegion dunderGetItem(intptr_t index) {
236436c6c9cSStella Laurenzo     // dunderLen checks validity.
237436c6c9cSStella Laurenzo     if (index < 0 || index >= dunderLen()) {
238436c6c9cSStella Laurenzo       throw SetPyError(PyExc_IndexError,
239436c6c9cSStella Laurenzo                        "attempt to access out of bounds region");
240436c6c9cSStella Laurenzo     }
241436c6c9cSStella Laurenzo     MlirRegion region = mlirOperationGetRegion(operation->get(), index);
242436c6c9cSStella Laurenzo     return PyRegion(operation, region);
243436c6c9cSStella Laurenzo   }
244436c6c9cSStella Laurenzo 
245436c6c9cSStella Laurenzo   static void bind(py::module &m) {
246f05ff4f7SStella Laurenzo     py::class_<PyRegionList>(m, "RegionSequence", py::module_local())
247436c6c9cSStella Laurenzo         .def("__len__", &PyRegionList::dunderLen)
248436c6c9cSStella Laurenzo         .def("__getitem__", &PyRegionList::dunderGetItem);
249436c6c9cSStella Laurenzo   }
250436c6c9cSStella Laurenzo 
251436c6c9cSStella Laurenzo private:
252436c6c9cSStella Laurenzo   PyOperationRef operation;
253436c6c9cSStella Laurenzo };
254436c6c9cSStella Laurenzo 
255436c6c9cSStella Laurenzo class PyBlockIterator {
256436c6c9cSStella Laurenzo public:
257436c6c9cSStella Laurenzo   PyBlockIterator(PyOperationRef operation, MlirBlock next)
258436c6c9cSStella Laurenzo       : operation(std::move(operation)), next(next) {}
259436c6c9cSStella Laurenzo 
260436c6c9cSStella Laurenzo   PyBlockIterator &dunderIter() { return *this; }
261436c6c9cSStella Laurenzo 
262436c6c9cSStella Laurenzo   PyBlock dunderNext() {
263436c6c9cSStella Laurenzo     operation->checkValid();
264436c6c9cSStella Laurenzo     if (mlirBlockIsNull(next)) {
265436c6c9cSStella Laurenzo       throw py::stop_iteration();
266436c6c9cSStella Laurenzo     }
267436c6c9cSStella Laurenzo 
268436c6c9cSStella Laurenzo     PyBlock returnBlock(operation, next);
269436c6c9cSStella Laurenzo     next = mlirBlockGetNextInRegion(next);
270436c6c9cSStella Laurenzo     return returnBlock;
271436c6c9cSStella Laurenzo   }
272436c6c9cSStella Laurenzo 
273436c6c9cSStella Laurenzo   static void bind(py::module &m) {
274f05ff4f7SStella Laurenzo     py::class_<PyBlockIterator>(m, "BlockIterator", py::module_local())
275436c6c9cSStella Laurenzo         .def("__iter__", &PyBlockIterator::dunderIter)
276436c6c9cSStella Laurenzo         .def("__next__", &PyBlockIterator::dunderNext);
277436c6c9cSStella Laurenzo   }
278436c6c9cSStella Laurenzo 
279436c6c9cSStella Laurenzo private:
280436c6c9cSStella Laurenzo   PyOperationRef operation;
281436c6c9cSStella Laurenzo   MlirBlock next;
282436c6c9cSStella Laurenzo };
283436c6c9cSStella Laurenzo 
284436c6c9cSStella Laurenzo /// Blocks are exposed by the C-API as a forward-only linked list. In Python,
285436c6c9cSStella Laurenzo /// we present them as a more full-featured list-like container but optimize
286436c6c9cSStella Laurenzo /// it for forward iteration. Blocks are always owned by a region.
287436c6c9cSStella Laurenzo class PyBlockList {
288436c6c9cSStella Laurenzo public:
289436c6c9cSStella Laurenzo   PyBlockList(PyOperationRef operation, MlirRegion region)
290436c6c9cSStella Laurenzo       : operation(std::move(operation)), region(region) {}
291436c6c9cSStella Laurenzo 
292436c6c9cSStella Laurenzo   PyBlockIterator dunderIter() {
293436c6c9cSStella Laurenzo     operation->checkValid();
294436c6c9cSStella Laurenzo     return PyBlockIterator(operation, mlirRegionGetFirstBlock(region));
295436c6c9cSStella Laurenzo   }
296436c6c9cSStella Laurenzo 
297436c6c9cSStella Laurenzo   intptr_t dunderLen() {
298436c6c9cSStella Laurenzo     operation->checkValid();
299436c6c9cSStella Laurenzo     intptr_t count = 0;
300436c6c9cSStella Laurenzo     MlirBlock block = mlirRegionGetFirstBlock(region);
301436c6c9cSStella Laurenzo     while (!mlirBlockIsNull(block)) {
302436c6c9cSStella Laurenzo       count += 1;
303436c6c9cSStella Laurenzo       block = mlirBlockGetNextInRegion(block);
304436c6c9cSStella Laurenzo     }
305436c6c9cSStella Laurenzo     return count;
306436c6c9cSStella Laurenzo   }
307436c6c9cSStella Laurenzo 
308436c6c9cSStella Laurenzo   PyBlock dunderGetItem(intptr_t index) {
309436c6c9cSStella Laurenzo     operation->checkValid();
310436c6c9cSStella Laurenzo     if (index < 0) {
311436c6c9cSStella Laurenzo       throw SetPyError(PyExc_IndexError,
312436c6c9cSStella Laurenzo                        "attempt to access out of bounds block");
313436c6c9cSStella Laurenzo     }
314436c6c9cSStella Laurenzo     MlirBlock block = mlirRegionGetFirstBlock(region);
315436c6c9cSStella Laurenzo     while (!mlirBlockIsNull(block)) {
316436c6c9cSStella Laurenzo       if (index == 0) {
317436c6c9cSStella Laurenzo         return PyBlock(operation, block);
318436c6c9cSStella Laurenzo       }
319436c6c9cSStella Laurenzo       block = mlirBlockGetNextInRegion(block);
320436c6c9cSStella Laurenzo       index -= 1;
321436c6c9cSStella Laurenzo     }
322436c6c9cSStella Laurenzo     throw SetPyError(PyExc_IndexError, "attempt to access out of bounds block");
323436c6c9cSStella Laurenzo   }
324436c6c9cSStella Laurenzo 
3251fc096afSMehdi Amini   PyBlock appendBlock(const py::args &pyArgTypes) {
326436c6c9cSStella Laurenzo     operation->checkValid();
327436c6c9cSStella Laurenzo     llvm::SmallVector<MlirType, 4> argTypes;
328436c6c9cSStella Laurenzo     argTypes.reserve(pyArgTypes.size());
329436c6c9cSStella Laurenzo     for (auto &pyArg : pyArgTypes) {
330436c6c9cSStella Laurenzo       argTypes.push_back(pyArg.cast<PyType &>());
331436c6c9cSStella Laurenzo     }
332436c6c9cSStella Laurenzo 
333436c6c9cSStella Laurenzo     MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
334436c6c9cSStella Laurenzo     mlirRegionAppendOwnedBlock(region, block);
335436c6c9cSStella Laurenzo     return PyBlock(operation, block);
336436c6c9cSStella Laurenzo   }
337436c6c9cSStella Laurenzo 
338436c6c9cSStella Laurenzo   static void bind(py::module &m) {
339f05ff4f7SStella Laurenzo     py::class_<PyBlockList>(m, "BlockList", py::module_local())
340436c6c9cSStella Laurenzo         .def("__getitem__", &PyBlockList::dunderGetItem)
341436c6c9cSStella Laurenzo         .def("__iter__", &PyBlockList::dunderIter)
342436c6c9cSStella Laurenzo         .def("__len__", &PyBlockList::dunderLen)
343436c6c9cSStella Laurenzo         .def("append", &PyBlockList::appendBlock, kAppendBlockDocstring);
344436c6c9cSStella Laurenzo   }
345436c6c9cSStella Laurenzo 
346436c6c9cSStella Laurenzo private:
347436c6c9cSStella Laurenzo   PyOperationRef operation;
348436c6c9cSStella Laurenzo   MlirRegion region;
349436c6c9cSStella Laurenzo };
350436c6c9cSStella Laurenzo 
351436c6c9cSStella Laurenzo class PyOperationIterator {
352436c6c9cSStella Laurenzo public:
353436c6c9cSStella Laurenzo   PyOperationIterator(PyOperationRef parentOperation, MlirOperation next)
354436c6c9cSStella Laurenzo       : parentOperation(std::move(parentOperation)), next(next) {}
355436c6c9cSStella Laurenzo 
356436c6c9cSStella Laurenzo   PyOperationIterator &dunderIter() { return *this; }
357436c6c9cSStella Laurenzo 
358436c6c9cSStella Laurenzo   py::object dunderNext() {
359436c6c9cSStella Laurenzo     parentOperation->checkValid();
360436c6c9cSStella Laurenzo     if (mlirOperationIsNull(next)) {
361436c6c9cSStella Laurenzo       throw py::stop_iteration();
362436c6c9cSStella Laurenzo     }
363436c6c9cSStella Laurenzo 
364436c6c9cSStella Laurenzo     PyOperationRef returnOperation =
365436c6c9cSStella Laurenzo         PyOperation::forOperation(parentOperation->getContext(), next);
366436c6c9cSStella Laurenzo     next = mlirOperationGetNextInBlock(next);
367436c6c9cSStella Laurenzo     return returnOperation->createOpView();
368436c6c9cSStella Laurenzo   }
369436c6c9cSStella Laurenzo 
370436c6c9cSStella Laurenzo   static void bind(py::module &m) {
371f05ff4f7SStella Laurenzo     py::class_<PyOperationIterator>(m, "OperationIterator", py::module_local())
372436c6c9cSStella Laurenzo         .def("__iter__", &PyOperationIterator::dunderIter)
373436c6c9cSStella Laurenzo         .def("__next__", &PyOperationIterator::dunderNext);
374436c6c9cSStella Laurenzo   }
375436c6c9cSStella Laurenzo 
376436c6c9cSStella Laurenzo private:
377436c6c9cSStella Laurenzo   PyOperationRef parentOperation;
378436c6c9cSStella Laurenzo   MlirOperation next;
379436c6c9cSStella Laurenzo };
380436c6c9cSStella Laurenzo 
381436c6c9cSStella Laurenzo /// Operations are exposed by the C-API as a forward-only linked list. In
382436c6c9cSStella Laurenzo /// Python, we present them as a more full-featured list-like container but
383436c6c9cSStella Laurenzo /// optimize it for forward iteration. Iterable operations are always owned
384436c6c9cSStella Laurenzo /// by a block.
385436c6c9cSStella Laurenzo class PyOperationList {
386436c6c9cSStella Laurenzo public:
387436c6c9cSStella Laurenzo   PyOperationList(PyOperationRef parentOperation, MlirBlock block)
388436c6c9cSStella Laurenzo       : parentOperation(std::move(parentOperation)), block(block) {}
389436c6c9cSStella Laurenzo 
390436c6c9cSStella Laurenzo   PyOperationIterator dunderIter() {
391436c6c9cSStella Laurenzo     parentOperation->checkValid();
392436c6c9cSStella Laurenzo     return PyOperationIterator(parentOperation,
393436c6c9cSStella Laurenzo                                mlirBlockGetFirstOperation(block));
394436c6c9cSStella Laurenzo   }
395436c6c9cSStella Laurenzo 
396436c6c9cSStella Laurenzo   intptr_t dunderLen() {
397436c6c9cSStella Laurenzo     parentOperation->checkValid();
398436c6c9cSStella Laurenzo     intptr_t count = 0;
399436c6c9cSStella Laurenzo     MlirOperation childOp = mlirBlockGetFirstOperation(block);
400436c6c9cSStella Laurenzo     while (!mlirOperationIsNull(childOp)) {
401436c6c9cSStella Laurenzo       count += 1;
402436c6c9cSStella Laurenzo       childOp = mlirOperationGetNextInBlock(childOp);
403436c6c9cSStella Laurenzo     }
404436c6c9cSStella Laurenzo     return count;
405436c6c9cSStella Laurenzo   }
406436c6c9cSStella Laurenzo 
407436c6c9cSStella Laurenzo   py::object dunderGetItem(intptr_t index) {
408436c6c9cSStella Laurenzo     parentOperation->checkValid();
409436c6c9cSStella Laurenzo     if (index < 0) {
410436c6c9cSStella Laurenzo       throw SetPyError(PyExc_IndexError,
411436c6c9cSStella Laurenzo                        "attempt to access out of bounds operation");
412436c6c9cSStella Laurenzo     }
413436c6c9cSStella Laurenzo     MlirOperation childOp = mlirBlockGetFirstOperation(block);
414436c6c9cSStella Laurenzo     while (!mlirOperationIsNull(childOp)) {
415436c6c9cSStella Laurenzo       if (index == 0) {
416436c6c9cSStella Laurenzo         return PyOperation::forOperation(parentOperation->getContext(), childOp)
417436c6c9cSStella Laurenzo             ->createOpView();
418436c6c9cSStella Laurenzo       }
419436c6c9cSStella Laurenzo       childOp = mlirOperationGetNextInBlock(childOp);
420436c6c9cSStella Laurenzo       index -= 1;
421436c6c9cSStella Laurenzo     }
422436c6c9cSStella Laurenzo     throw SetPyError(PyExc_IndexError,
423436c6c9cSStella Laurenzo                      "attempt to access out of bounds operation");
424436c6c9cSStella Laurenzo   }
425436c6c9cSStella Laurenzo 
426436c6c9cSStella Laurenzo   static void bind(py::module &m) {
427f05ff4f7SStella Laurenzo     py::class_<PyOperationList>(m, "OperationList", py::module_local())
428436c6c9cSStella Laurenzo         .def("__getitem__", &PyOperationList::dunderGetItem)
429436c6c9cSStella Laurenzo         .def("__iter__", &PyOperationList::dunderIter)
430436c6c9cSStella Laurenzo         .def("__len__", &PyOperationList::dunderLen);
431436c6c9cSStella Laurenzo   }
432436c6c9cSStella Laurenzo 
433436c6c9cSStella Laurenzo private:
434436c6c9cSStella Laurenzo   PyOperationRef parentOperation;
435436c6c9cSStella Laurenzo   MlirBlock block;
436436c6c9cSStella Laurenzo };
437436c6c9cSStella Laurenzo 
438436c6c9cSStella Laurenzo } // namespace
439436c6c9cSStella Laurenzo 
440436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
441436c6c9cSStella Laurenzo // PyMlirContext
442436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
443436c6c9cSStella Laurenzo 
444436c6c9cSStella Laurenzo PyMlirContext::PyMlirContext(MlirContext context) : context(context) {
445436c6c9cSStella Laurenzo   py::gil_scoped_acquire acquire;
446436c6c9cSStella Laurenzo   auto &liveContexts = getLiveContexts();
447436c6c9cSStella Laurenzo   liveContexts[context.ptr] = this;
448436c6c9cSStella Laurenzo }
449436c6c9cSStella Laurenzo 
450436c6c9cSStella Laurenzo PyMlirContext::~PyMlirContext() {
451436c6c9cSStella Laurenzo   // Note that the only public way to construct an instance is via the
452436c6c9cSStella Laurenzo   // forContext method, which always puts the associated handle into
453436c6c9cSStella Laurenzo   // liveContexts.
454436c6c9cSStella Laurenzo   py::gil_scoped_acquire acquire;
455436c6c9cSStella Laurenzo   getLiveContexts().erase(context.ptr);
456436c6c9cSStella Laurenzo   mlirContextDestroy(context);
457436c6c9cSStella Laurenzo }
458436c6c9cSStella Laurenzo 
459436c6c9cSStella Laurenzo py::object PyMlirContext::getCapsule() {
460436c6c9cSStella Laurenzo   return py::reinterpret_steal<py::object>(mlirPythonContextToCapsule(get()));
461436c6c9cSStella Laurenzo }
462436c6c9cSStella Laurenzo 
463436c6c9cSStella Laurenzo py::object PyMlirContext::createFromCapsule(py::object capsule) {
464436c6c9cSStella Laurenzo   MlirContext rawContext = mlirPythonCapsuleToContext(capsule.ptr());
465436c6c9cSStella Laurenzo   if (mlirContextIsNull(rawContext))
466436c6c9cSStella Laurenzo     throw py::error_already_set();
467436c6c9cSStella Laurenzo   return forContext(rawContext).releaseObject();
468436c6c9cSStella Laurenzo }
469436c6c9cSStella Laurenzo 
470436c6c9cSStella Laurenzo PyMlirContext *PyMlirContext::createNewContextForInit() {
471436c6c9cSStella Laurenzo   MlirContext context = mlirContextCreate();
472436c6c9cSStella Laurenzo   mlirRegisterAllDialects(context);
473436c6c9cSStella Laurenzo   return new PyMlirContext(context);
474436c6c9cSStella Laurenzo }
475436c6c9cSStella Laurenzo 
476436c6c9cSStella Laurenzo PyMlirContextRef PyMlirContext::forContext(MlirContext context) {
477436c6c9cSStella Laurenzo   py::gil_scoped_acquire acquire;
478436c6c9cSStella Laurenzo   auto &liveContexts = getLiveContexts();
479436c6c9cSStella Laurenzo   auto it = liveContexts.find(context.ptr);
480436c6c9cSStella Laurenzo   if (it == liveContexts.end()) {
481436c6c9cSStella Laurenzo     // Create.
482436c6c9cSStella Laurenzo     PyMlirContext *unownedContextWrapper = new PyMlirContext(context);
483436c6c9cSStella Laurenzo     py::object pyRef = py::cast(unownedContextWrapper);
484436c6c9cSStella Laurenzo     assert(pyRef && "cast to py::object failed");
485436c6c9cSStella Laurenzo     liveContexts[context.ptr] = unownedContextWrapper;
486436c6c9cSStella Laurenzo     return PyMlirContextRef(unownedContextWrapper, std::move(pyRef));
487436c6c9cSStella Laurenzo   }
488436c6c9cSStella Laurenzo   // Use existing.
489436c6c9cSStella Laurenzo   py::object pyRef = py::cast(it->second);
490436c6c9cSStella Laurenzo   return PyMlirContextRef(it->second, std::move(pyRef));
491436c6c9cSStella Laurenzo }
492436c6c9cSStella Laurenzo 
493436c6c9cSStella Laurenzo PyMlirContext::LiveContextMap &PyMlirContext::getLiveContexts() {
494436c6c9cSStella Laurenzo   static LiveContextMap liveContexts;
495436c6c9cSStella Laurenzo   return liveContexts;
496436c6c9cSStella Laurenzo }
497436c6c9cSStella Laurenzo 
498436c6c9cSStella Laurenzo size_t PyMlirContext::getLiveCount() { return getLiveContexts().size(); }
499436c6c9cSStella Laurenzo 
500436c6c9cSStella Laurenzo size_t PyMlirContext::getLiveOperationCount() { return liveOperations.size(); }
501436c6c9cSStella Laurenzo 
502436c6c9cSStella Laurenzo size_t PyMlirContext::getLiveModuleCount() { return liveModules.size(); }
503436c6c9cSStella Laurenzo 
504436c6c9cSStella Laurenzo pybind11::object PyMlirContext::contextEnter() {
505436c6c9cSStella Laurenzo   return PyThreadContextEntry::pushContext(*this);
506436c6c9cSStella Laurenzo }
507436c6c9cSStella Laurenzo 
5081fc096afSMehdi Amini void PyMlirContext::contextExit(const pybind11::object &excType,
5091fc096afSMehdi Amini                                 const pybind11::object &excVal,
5101fc096afSMehdi Amini                                 const pybind11::object &excTb) {
511436c6c9cSStella Laurenzo   PyThreadContextEntry::popContext(*this);
512436c6c9cSStella Laurenzo }
513436c6c9cSStella Laurenzo 
514436c6c9cSStella Laurenzo PyMlirContext &DefaultingPyMlirContext::resolve() {
515436c6c9cSStella Laurenzo   PyMlirContext *context = PyThreadContextEntry::getDefaultContext();
516436c6c9cSStella Laurenzo   if (!context) {
517436c6c9cSStella Laurenzo     throw SetPyError(
518436c6c9cSStella Laurenzo         PyExc_RuntimeError,
519436c6c9cSStella Laurenzo         "An MLIR function requires a Context but none was provided in the call "
520436c6c9cSStella Laurenzo         "or from the surrounding environment. Either pass to the function with "
521436c6c9cSStella Laurenzo         "a 'context=' argument or establish a default using 'with Context():'");
522436c6c9cSStella Laurenzo   }
523436c6c9cSStella Laurenzo   return *context;
524436c6c9cSStella Laurenzo }
525436c6c9cSStella Laurenzo 
526436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
527436c6c9cSStella Laurenzo // PyThreadContextEntry management
528436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
529436c6c9cSStella Laurenzo 
530436c6c9cSStella Laurenzo std::vector<PyThreadContextEntry> &PyThreadContextEntry::getStack() {
531436c6c9cSStella Laurenzo   static thread_local std::vector<PyThreadContextEntry> stack;
532436c6c9cSStella Laurenzo   return stack;
533436c6c9cSStella Laurenzo }
534436c6c9cSStella Laurenzo 
535436c6c9cSStella Laurenzo PyThreadContextEntry *PyThreadContextEntry::getTopOfStack() {
536436c6c9cSStella Laurenzo   auto &stack = getStack();
537436c6c9cSStella Laurenzo   if (stack.empty())
538436c6c9cSStella Laurenzo     return nullptr;
539436c6c9cSStella Laurenzo   return &stack.back();
540436c6c9cSStella Laurenzo }
541436c6c9cSStella Laurenzo 
542436c6c9cSStella Laurenzo void PyThreadContextEntry::push(FrameKind frameKind, py::object context,
543436c6c9cSStella Laurenzo                                 py::object insertionPoint,
544436c6c9cSStella Laurenzo                                 py::object location) {
545436c6c9cSStella Laurenzo   auto &stack = getStack();
546436c6c9cSStella Laurenzo   stack.emplace_back(frameKind, std::move(context), std::move(insertionPoint),
547436c6c9cSStella Laurenzo                      std::move(location));
548436c6c9cSStella Laurenzo   // If the new stack has more than one entry and the context of the new top
549436c6c9cSStella Laurenzo   // entry matches the previous, copy the insertionPoint and location from the
550436c6c9cSStella Laurenzo   // previous entry if missing from the new top entry.
551436c6c9cSStella Laurenzo   if (stack.size() > 1) {
552436c6c9cSStella Laurenzo     auto &prev = *(stack.rbegin() + 1);
553436c6c9cSStella Laurenzo     auto &current = stack.back();
554436c6c9cSStella Laurenzo     if (current.context.is(prev.context)) {
555436c6c9cSStella Laurenzo       // Default non-context objects from the previous entry.
556436c6c9cSStella Laurenzo       if (!current.insertionPoint)
557436c6c9cSStella Laurenzo         current.insertionPoint = prev.insertionPoint;
558436c6c9cSStella Laurenzo       if (!current.location)
559436c6c9cSStella Laurenzo         current.location = prev.location;
560436c6c9cSStella Laurenzo     }
561436c6c9cSStella Laurenzo   }
562436c6c9cSStella Laurenzo }
563436c6c9cSStella Laurenzo 
564436c6c9cSStella Laurenzo PyMlirContext *PyThreadContextEntry::getContext() {
565436c6c9cSStella Laurenzo   if (!context)
566436c6c9cSStella Laurenzo     return nullptr;
567436c6c9cSStella Laurenzo   return py::cast<PyMlirContext *>(context);
568436c6c9cSStella Laurenzo }
569436c6c9cSStella Laurenzo 
570436c6c9cSStella Laurenzo PyInsertionPoint *PyThreadContextEntry::getInsertionPoint() {
571436c6c9cSStella Laurenzo   if (!insertionPoint)
572436c6c9cSStella Laurenzo     return nullptr;
573436c6c9cSStella Laurenzo   return py::cast<PyInsertionPoint *>(insertionPoint);
574436c6c9cSStella Laurenzo }
575436c6c9cSStella Laurenzo 
576436c6c9cSStella Laurenzo PyLocation *PyThreadContextEntry::getLocation() {
577436c6c9cSStella Laurenzo   if (!location)
578436c6c9cSStella Laurenzo     return nullptr;
579436c6c9cSStella Laurenzo   return py::cast<PyLocation *>(location);
580436c6c9cSStella Laurenzo }
581436c6c9cSStella Laurenzo 
582436c6c9cSStella Laurenzo PyMlirContext *PyThreadContextEntry::getDefaultContext() {
583436c6c9cSStella Laurenzo   auto *tos = getTopOfStack();
584436c6c9cSStella Laurenzo   return tos ? tos->getContext() : nullptr;
585436c6c9cSStella Laurenzo }
586436c6c9cSStella Laurenzo 
587436c6c9cSStella Laurenzo PyInsertionPoint *PyThreadContextEntry::getDefaultInsertionPoint() {
588436c6c9cSStella Laurenzo   auto *tos = getTopOfStack();
589436c6c9cSStella Laurenzo   return tos ? tos->getInsertionPoint() : nullptr;
590436c6c9cSStella Laurenzo }
591436c6c9cSStella Laurenzo 
592436c6c9cSStella Laurenzo PyLocation *PyThreadContextEntry::getDefaultLocation() {
593436c6c9cSStella Laurenzo   auto *tos = getTopOfStack();
594436c6c9cSStella Laurenzo   return tos ? tos->getLocation() : nullptr;
595436c6c9cSStella Laurenzo }
596436c6c9cSStella Laurenzo 
597436c6c9cSStella Laurenzo py::object PyThreadContextEntry::pushContext(PyMlirContext &context) {
598436c6c9cSStella Laurenzo   py::object contextObj = py::cast(context);
599436c6c9cSStella Laurenzo   push(FrameKind::Context, /*context=*/contextObj,
600436c6c9cSStella Laurenzo        /*insertionPoint=*/py::object(),
601436c6c9cSStella Laurenzo        /*location=*/py::object());
602436c6c9cSStella Laurenzo   return contextObj;
603436c6c9cSStella Laurenzo }
604436c6c9cSStella Laurenzo 
605436c6c9cSStella Laurenzo void PyThreadContextEntry::popContext(PyMlirContext &context) {
606436c6c9cSStella Laurenzo   auto &stack = getStack();
607436c6c9cSStella Laurenzo   if (stack.empty())
608436c6c9cSStella Laurenzo     throw SetPyError(PyExc_RuntimeError, "Unbalanced Context enter/exit");
609436c6c9cSStella Laurenzo   auto &tos = stack.back();
610436c6c9cSStella Laurenzo   if (tos.frameKind != FrameKind::Context && tos.getContext() != &context)
611436c6c9cSStella Laurenzo     throw SetPyError(PyExc_RuntimeError, "Unbalanced Context enter/exit");
612436c6c9cSStella Laurenzo   stack.pop_back();
613436c6c9cSStella Laurenzo }
614436c6c9cSStella Laurenzo 
615436c6c9cSStella Laurenzo py::object
616436c6c9cSStella Laurenzo PyThreadContextEntry::pushInsertionPoint(PyInsertionPoint &insertionPoint) {
617436c6c9cSStella Laurenzo   py::object contextObj =
618436c6c9cSStella Laurenzo       insertionPoint.getBlock().getParentOperation()->getContext().getObject();
619436c6c9cSStella Laurenzo   py::object insertionPointObj = py::cast(insertionPoint);
620436c6c9cSStella Laurenzo   push(FrameKind::InsertionPoint,
621436c6c9cSStella Laurenzo        /*context=*/contextObj,
622436c6c9cSStella Laurenzo        /*insertionPoint=*/insertionPointObj,
623436c6c9cSStella Laurenzo        /*location=*/py::object());
624436c6c9cSStella Laurenzo   return insertionPointObj;
625436c6c9cSStella Laurenzo }
626436c6c9cSStella Laurenzo 
627436c6c9cSStella Laurenzo void PyThreadContextEntry::popInsertionPoint(PyInsertionPoint &insertionPoint) {
628436c6c9cSStella Laurenzo   auto &stack = getStack();
629436c6c9cSStella Laurenzo   if (stack.empty())
630436c6c9cSStella Laurenzo     throw SetPyError(PyExc_RuntimeError,
631436c6c9cSStella Laurenzo                      "Unbalanced InsertionPoint enter/exit");
632436c6c9cSStella Laurenzo   auto &tos = stack.back();
633436c6c9cSStella Laurenzo   if (tos.frameKind != FrameKind::InsertionPoint &&
634436c6c9cSStella Laurenzo       tos.getInsertionPoint() != &insertionPoint)
635436c6c9cSStella Laurenzo     throw SetPyError(PyExc_RuntimeError,
636436c6c9cSStella Laurenzo                      "Unbalanced InsertionPoint enter/exit");
637436c6c9cSStella Laurenzo   stack.pop_back();
638436c6c9cSStella Laurenzo }
639436c6c9cSStella Laurenzo 
640436c6c9cSStella Laurenzo py::object PyThreadContextEntry::pushLocation(PyLocation &location) {
641436c6c9cSStella Laurenzo   py::object contextObj = location.getContext().getObject();
642436c6c9cSStella Laurenzo   py::object locationObj = py::cast(location);
643436c6c9cSStella Laurenzo   push(FrameKind::Location, /*context=*/contextObj,
644436c6c9cSStella Laurenzo        /*insertionPoint=*/py::object(),
645436c6c9cSStella Laurenzo        /*location=*/locationObj);
646436c6c9cSStella Laurenzo   return locationObj;
647436c6c9cSStella Laurenzo }
648436c6c9cSStella Laurenzo 
649436c6c9cSStella Laurenzo void PyThreadContextEntry::popLocation(PyLocation &location) {
650436c6c9cSStella Laurenzo   auto &stack = getStack();
651436c6c9cSStella Laurenzo   if (stack.empty())
652436c6c9cSStella Laurenzo     throw SetPyError(PyExc_RuntimeError, "Unbalanced Location enter/exit");
653436c6c9cSStella Laurenzo   auto &tos = stack.back();
654436c6c9cSStella Laurenzo   if (tos.frameKind != FrameKind::Location && tos.getLocation() != &location)
655436c6c9cSStella Laurenzo     throw SetPyError(PyExc_RuntimeError, "Unbalanced Location enter/exit");
656436c6c9cSStella Laurenzo   stack.pop_back();
657436c6c9cSStella Laurenzo }
658436c6c9cSStella Laurenzo 
659436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
660436c6c9cSStella Laurenzo // PyDialect, PyDialectDescriptor, PyDialects
661436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
662436c6c9cSStella Laurenzo 
663436c6c9cSStella Laurenzo MlirDialect PyDialects::getDialectForKey(const std::string &key,
664436c6c9cSStella Laurenzo                                          bool attrError) {
665f8479d9dSRiver Riddle   MlirDialect dialect = mlirContextGetOrLoadDialect(getContext()->get(),
666f8479d9dSRiver Riddle                                                     {key.data(), key.size()});
667436c6c9cSStella Laurenzo   if (mlirDialectIsNull(dialect)) {
668436c6c9cSStella Laurenzo     throw SetPyError(attrError ? PyExc_AttributeError : PyExc_IndexError,
669436c6c9cSStella Laurenzo                      Twine("Dialect '") + key + "' not found");
670436c6c9cSStella Laurenzo   }
671436c6c9cSStella Laurenzo   return dialect;
672436c6c9cSStella Laurenzo }
673436c6c9cSStella Laurenzo 
674436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
675436c6c9cSStella Laurenzo // PyLocation
676436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
677436c6c9cSStella Laurenzo 
678436c6c9cSStella Laurenzo py::object PyLocation::getCapsule() {
679436c6c9cSStella Laurenzo   return py::reinterpret_steal<py::object>(mlirPythonLocationToCapsule(*this));
680436c6c9cSStella Laurenzo }
681436c6c9cSStella Laurenzo 
682436c6c9cSStella Laurenzo PyLocation PyLocation::createFromCapsule(py::object capsule) {
683436c6c9cSStella Laurenzo   MlirLocation rawLoc = mlirPythonCapsuleToLocation(capsule.ptr());
684436c6c9cSStella Laurenzo   if (mlirLocationIsNull(rawLoc))
685436c6c9cSStella Laurenzo     throw py::error_already_set();
686436c6c9cSStella Laurenzo   return PyLocation(PyMlirContext::forContext(mlirLocationGetContext(rawLoc)),
687436c6c9cSStella Laurenzo                     rawLoc);
688436c6c9cSStella Laurenzo }
689436c6c9cSStella Laurenzo 
690436c6c9cSStella Laurenzo py::object PyLocation::contextEnter() {
691436c6c9cSStella Laurenzo   return PyThreadContextEntry::pushLocation(*this);
692436c6c9cSStella Laurenzo }
693436c6c9cSStella Laurenzo 
6941fc096afSMehdi Amini void PyLocation::contextExit(const pybind11::object &excType,
6951fc096afSMehdi Amini                              const pybind11::object &excVal,
6961fc096afSMehdi Amini                              const pybind11::object &excTb) {
697436c6c9cSStella Laurenzo   PyThreadContextEntry::popLocation(*this);
698436c6c9cSStella Laurenzo }
699436c6c9cSStella Laurenzo 
700436c6c9cSStella Laurenzo PyLocation &DefaultingPyLocation::resolve() {
701436c6c9cSStella Laurenzo   auto *location = PyThreadContextEntry::getDefaultLocation();
702436c6c9cSStella Laurenzo   if (!location) {
703436c6c9cSStella Laurenzo     throw SetPyError(
704436c6c9cSStella Laurenzo         PyExc_RuntimeError,
705436c6c9cSStella Laurenzo         "An MLIR function requires a Location but none was provided in the "
706436c6c9cSStella Laurenzo         "call or from the surrounding environment. Either pass to the function "
707436c6c9cSStella Laurenzo         "with a 'loc=' argument or establish a default using 'with loc:'");
708436c6c9cSStella Laurenzo   }
709436c6c9cSStella Laurenzo   return *location;
710436c6c9cSStella Laurenzo }
711436c6c9cSStella Laurenzo 
712436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
713436c6c9cSStella Laurenzo // PyModule
714436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
715436c6c9cSStella Laurenzo 
716436c6c9cSStella Laurenzo PyModule::PyModule(PyMlirContextRef contextRef, MlirModule module)
717436c6c9cSStella Laurenzo     : BaseContextObject(std::move(contextRef)), module(module) {}
718436c6c9cSStella Laurenzo 
719436c6c9cSStella Laurenzo PyModule::~PyModule() {
720436c6c9cSStella Laurenzo   py::gil_scoped_acquire acquire;
721436c6c9cSStella Laurenzo   auto &liveModules = getContext()->liveModules;
722436c6c9cSStella Laurenzo   assert(liveModules.count(module.ptr) == 1 &&
723436c6c9cSStella Laurenzo          "destroying module not in live map");
724436c6c9cSStella Laurenzo   liveModules.erase(module.ptr);
725436c6c9cSStella Laurenzo   mlirModuleDestroy(module);
726436c6c9cSStella Laurenzo }
727436c6c9cSStella Laurenzo 
728436c6c9cSStella Laurenzo PyModuleRef PyModule::forModule(MlirModule module) {
729436c6c9cSStella Laurenzo   MlirContext context = mlirModuleGetContext(module);
730436c6c9cSStella Laurenzo   PyMlirContextRef contextRef = PyMlirContext::forContext(context);
731436c6c9cSStella Laurenzo 
732436c6c9cSStella Laurenzo   py::gil_scoped_acquire acquire;
733436c6c9cSStella Laurenzo   auto &liveModules = contextRef->liveModules;
734436c6c9cSStella Laurenzo   auto it = liveModules.find(module.ptr);
735436c6c9cSStella Laurenzo   if (it == liveModules.end()) {
736436c6c9cSStella Laurenzo     // Create.
737436c6c9cSStella Laurenzo     PyModule *unownedModule = new PyModule(std::move(contextRef), module);
738436c6c9cSStella Laurenzo     // Note that the default return value policy on cast is automatic_reference,
739436c6c9cSStella Laurenzo     // which does not take ownership (delete will not be called).
740436c6c9cSStella Laurenzo     // Just be explicit.
741436c6c9cSStella Laurenzo     py::object pyRef =
742436c6c9cSStella Laurenzo         py::cast(unownedModule, py::return_value_policy::take_ownership);
743436c6c9cSStella Laurenzo     unownedModule->handle = pyRef;
744436c6c9cSStella Laurenzo     liveModules[module.ptr] =
745436c6c9cSStella Laurenzo         std::make_pair(unownedModule->handle, unownedModule);
746436c6c9cSStella Laurenzo     return PyModuleRef(unownedModule, std::move(pyRef));
747436c6c9cSStella Laurenzo   }
748436c6c9cSStella Laurenzo   // Use existing.
749436c6c9cSStella Laurenzo   PyModule *existing = it->second.second;
750436c6c9cSStella Laurenzo   py::object pyRef = py::reinterpret_borrow<py::object>(it->second.first);
751436c6c9cSStella Laurenzo   return PyModuleRef(existing, std::move(pyRef));
752436c6c9cSStella Laurenzo }
753436c6c9cSStella Laurenzo 
754436c6c9cSStella Laurenzo py::object PyModule::createFromCapsule(py::object capsule) {
755436c6c9cSStella Laurenzo   MlirModule rawModule = mlirPythonCapsuleToModule(capsule.ptr());
756436c6c9cSStella Laurenzo   if (mlirModuleIsNull(rawModule))
757436c6c9cSStella Laurenzo     throw py::error_already_set();
758436c6c9cSStella Laurenzo   return forModule(rawModule).releaseObject();
759436c6c9cSStella Laurenzo }
760436c6c9cSStella Laurenzo 
761436c6c9cSStella Laurenzo py::object PyModule::getCapsule() {
762436c6c9cSStella Laurenzo   return py::reinterpret_steal<py::object>(mlirPythonModuleToCapsule(get()));
763436c6c9cSStella Laurenzo }
764436c6c9cSStella Laurenzo 
765436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
766436c6c9cSStella Laurenzo // PyOperation
767436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
768436c6c9cSStella Laurenzo 
769436c6c9cSStella Laurenzo PyOperation::PyOperation(PyMlirContextRef contextRef, MlirOperation operation)
770436c6c9cSStella Laurenzo     : BaseContextObject(std::move(contextRef)), operation(operation) {}
771436c6c9cSStella Laurenzo 
772436c6c9cSStella Laurenzo PyOperation::~PyOperation() {
77349745f87SMike Urbach   // If the operation has already been invalidated there is nothing to do.
77449745f87SMike Urbach   if (!valid)
77549745f87SMike Urbach     return;
776436c6c9cSStella Laurenzo   auto &liveOperations = getContext()->liveOperations;
777436c6c9cSStella Laurenzo   assert(liveOperations.count(operation.ptr) == 1 &&
778436c6c9cSStella Laurenzo          "destroying operation not in live map");
779436c6c9cSStella Laurenzo   liveOperations.erase(operation.ptr);
780436c6c9cSStella Laurenzo   if (!isAttached()) {
781436c6c9cSStella Laurenzo     mlirOperationDestroy(operation);
782436c6c9cSStella Laurenzo   }
783436c6c9cSStella Laurenzo }
784436c6c9cSStella Laurenzo 
785436c6c9cSStella Laurenzo PyOperationRef PyOperation::createInstance(PyMlirContextRef contextRef,
786436c6c9cSStella Laurenzo                                            MlirOperation operation,
787436c6c9cSStella Laurenzo                                            py::object parentKeepAlive) {
788436c6c9cSStella Laurenzo   auto &liveOperations = contextRef->liveOperations;
789436c6c9cSStella Laurenzo   // Create.
790436c6c9cSStella Laurenzo   PyOperation *unownedOperation =
791436c6c9cSStella Laurenzo       new PyOperation(std::move(contextRef), operation);
792436c6c9cSStella Laurenzo   // Note that the default return value policy on cast is automatic_reference,
793436c6c9cSStella Laurenzo   // which does not take ownership (delete will not be called).
794436c6c9cSStella Laurenzo   // Just be explicit.
795436c6c9cSStella Laurenzo   py::object pyRef =
796436c6c9cSStella Laurenzo       py::cast(unownedOperation, py::return_value_policy::take_ownership);
797436c6c9cSStella Laurenzo   unownedOperation->handle = pyRef;
798436c6c9cSStella Laurenzo   if (parentKeepAlive) {
799436c6c9cSStella Laurenzo     unownedOperation->parentKeepAlive = std::move(parentKeepAlive);
800436c6c9cSStella Laurenzo   }
801436c6c9cSStella Laurenzo   liveOperations[operation.ptr] = std::make_pair(pyRef, unownedOperation);
802436c6c9cSStella Laurenzo   return PyOperationRef(unownedOperation, std::move(pyRef));
803436c6c9cSStella Laurenzo }
804436c6c9cSStella Laurenzo 
805436c6c9cSStella Laurenzo PyOperationRef PyOperation::forOperation(PyMlirContextRef contextRef,
806436c6c9cSStella Laurenzo                                          MlirOperation operation,
807436c6c9cSStella Laurenzo                                          py::object parentKeepAlive) {
808436c6c9cSStella Laurenzo   auto &liveOperations = contextRef->liveOperations;
809436c6c9cSStella Laurenzo   auto it = liveOperations.find(operation.ptr);
810436c6c9cSStella Laurenzo   if (it == liveOperations.end()) {
811436c6c9cSStella Laurenzo     // Create.
812436c6c9cSStella Laurenzo     return createInstance(std::move(contextRef), operation,
813436c6c9cSStella Laurenzo                           std::move(parentKeepAlive));
814436c6c9cSStella Laurenzo   }
815436c6c9cSStella Laurenzo   // Use existing.
816436c6c9cSStella Laurenzo   PyOperation *existing = it->second.second;
817436c6c9cSStella Laurenzo   py::object pyRef = py::reinterpret_borrow<py::object>(it->second.first);
818436c6c9cSStella Laurenzo   return PyOperationRef(existing, std::move(pyRef));
819436c6c9cSStella Laurenzo }
820436c6c9cSStella Laurenzo 
821436c6c9cSStella Laurenzo PyOperationRef PyOperation::createDetached(PyMlirContextRef contextRef,
822436c6c9cSStella Laurenzo                                            MlirOperation operation,
823436c6c9cSStella Laurenzo                                            py::object parentKeepAlive) {
824436c6c9cSStella Laurenzo   auto &liveOperations = contextRef->liveOperations;
825436c6c9cSStella Laurenzo   assert(liveOperations.count(operation.ptr) == 0 &&
826436c6c9cSStella Laurenzo          "cannot create detached operation that already exists");
827436c6c9cSStella Laurenzo   (void)liveOperations;
828436c6c9cSStella Laurenzo 
829436c6c9cSStella Laurenzo   PyOperationRef created = createInstance(std::move(contextRef), operation,
830436c6c9cSStella Laurenzo                                           std::move(parentKeepAlive));
831436c6c9cSStella Laurenzo   created->attached = false;
832436c6c9cSStella Laurenzo   return created;
833436c6c9cSStella Laurenzo }
834436c6c9cSStella Laurenzo 
835436c6c9cSStella Laurenzo void PyOperation::checkValid() const {
836436c6c9cSStella Laurenzo   if (!valid) {
837436c6c9cSStella Laurenzo     throw SetPyError(PyExc_RuntimeError, "the operation has been invalidated");
838436c6c9cSStella Laurenzo   }
839436c6c9cSStella Laurenzo }
840436c6c9cSStella Laurenzo 
841436c6c9cSStella Laurenzo void PyOperationBase::print(py::object fileObject, bool binary,
842436c6c9cSStella Laurenzo                             llvm::Optional<int64_t> largeElementsLimit,
843436c6c9cSStella Laurenzo                             bool enableDebugInfo, bool prettyDebugInfo,
844ace1d0adSStella Laurenzo                             bool printGenericOpForm, bool useLocalScope,
845ace1d0adSStella Laurenzo                             bool assumeVerified) {
846436c6c9cSStella Laurenzo   PyOperation &operation = getOperation();
847436c6c9cSStella Laurenzo   operation.checkValid();
848436c6c9cSStella Laurenzo   if (fileObject.is_none())
849436c6c9cSStella Laurenzo     fileObject = py::module::import("sys").attr("stdout");
850436c6c9cSStella Laurenzo 
851ace1d0adSStella Laurenzo   if (!assumeVerified && !printGenericOpForm &&
852ace1d0adSStella Laurenzo       !mlirOperationVerify(operation)) {
853ace1d0adSStella Laurenzo     std::string message("// Verification failed, printing generic form\n");
854ace1d0adSStella Laurenzo     if (binary) {
855ace1d0adSStella Laurenzo       fileObject.attr("write")(py::bytes(message));
856ace1d0adSStella Laurenzo     } else {
857ace1d0adSStella Laurenzo       fileObject.attr("write")(py::str(message));
858ace1d0adSStella Laurenzo     }
859436c6c9cSStella Laurenzo     printGenericOpForm = true;
860436c6c9cSStella Laurenzo   }
861436c6c9cSStella Laurenzo 
862436c6c9cSStella Laurenzo   MlirOpPrintingFlags flags = mlirOpPrintingFlagsCreate();
863436c6c9cSStella Laurenzo   if (largeElementsLimit)
864436c6c9cSStella Laurenzo     mlirOpPrintingFlagsElideLargeElementsAttrs(flags, *largeElementsLimit);
865436c6c9cSStella Laurenzo   if (enableDebugInfo)
866436c6c9cSStella Laurenzo     mlirOpPrintingFlagsEnableDebugInfo(flags, /*prettyForm=*/prettyDebugInfo);
867436c6c9cSStella Laurenzo   if (printGenericOpForm)
868436c6c9cSStella Laurenzo     mlirOpPrintingFlagsPrintGenericOpForm(flags);
869436c6c9cSStella Laurenzo 
870436c6c9cSStella Laurenzo   PyFileAccumulator accum(fileObject, binary);
871436c6c9cSStella Laurenzo   py::gil_scoped_release();
872436c6c9cSStella Laurenzo   mlirOperationPrintWithFlags(operation, flags, accum.getCallback(),
873436c6c9cSStella Laurenzo                               accum.getUserData());
874436c6c9cSStella Laurenzo   mlirOpPrintingFlagsDestroy(flags);
875436c6c9cSStella Laurenzo }
876436c6c9cSStella Laurenzo 
877436c6c9cSStella Laurenzo py::object PyOperationBase::getAsm(bool binary,
878436c6c9cSStella Laurenzo                                    llvm::Optional<int64_t> largeElementsLimit,
879436c6c9cSStella Laurenzo                                    bool enableDebugInfo, bool prettyDebugInfo,
880ace1d0adSStella Laurenzo                                    bool printGenericOpForm, bool useLocalScope,
881ace1d0adSStella Laurenzo                                    bool assumeVerified) {
882436c6c9cSStella Laurenzo   py::object fileObject;
883436c6c9cSStella Laurenzo   if (binary) {
884436c6c9cSStella Laurenzo     fileObject = py::module::import("io").attr("BytesIO")();
885436c6c9cSStella Laurenzo   } else {
886436c6c9cSStella Laurenzo     fileObject = py::module::import("io").attr("StringIO")();
887436c6c9cSStella Laurenzo   }
888436c6c9cSStella Laurenzo   print(fileObject, /*binary=*/binary,
889436c6c9cSStella Laurenzo         /*largeElementsLimit=*/largeElementsLimit,
890436c6c9cSStella Laurenzo         /*enableDebugInfo=*/enableDebugInfo,
891436c6c9cSStella Laurenzo         /*prettyDebugInfo=*/prettyDebugInfo,
892436c6c9cSStella Laurenzo         /*printGenericOpForm=*/printGenericOpForm,
893ace1d0adSStella Laurenzo         /*useLocalScope=*/useLocalScope,
894ace1d0adSStella Laurenzo         /*assumeVerified=*/assumeVerified);
895436c6c9cSStella Laurenzo 
896436c6c9cSStella Laurenzo   return fileObject.attr("getvalue")();
897436c6c9cSStella Laurenzo }
898436c6c9cSStella Laurenzo 
89924685aaeSAlex Zinenko void PyOperationBase::moveAfter(PyOperationBase &other) {
90024685aaeSAlex Zinenko   PyOperation &operation = getOperation();
90124685aaeSAlex Zinenko   PyOperation &otherOp = other.getOperation();
90224685aaeSAlex Zinenko   operation.checkValid();
90324685aaeSAlex Zinenko   otherOp.checkValid();
90424685aaeSAlex Zinenko   mlirOperationMoveAfter(operation, otherOp);
90524685aaeSAlex Zinenko   operation.parentKeepAlive = otherOp.parentKeepAlive;
90624685aaeSAlex Zinenko }
90724685aaeSAlex Zinenko 
90824685aaeSAlex Zinenko void PyOperationBase::moveBefore(PyOperationBase &other) {
90924685aaeSAlex Zinenko   PyOperation &operation = getOperation();
91024685aaeSAlex Zinenko   PyOperation &otherOp = other.getOperation();
91124685aaeSAlex Zinenko   operation.checkValid();
91224685aaeSAlex Zinenko   otherOp.checkValid();
91324685aaeSAlex Zinenko   mlirOperationMoveBefore(operation, otherOp);
91424685aaeSAlex Zinenko   operation.parentKeepAlive = otherOp.parentKeepAlive;
91524685aaeSAlex Zinenko }
91624685aaeSAlex Zinenko 
9171689dadeSJohn Demme llvm::Optional<PyOperationRef> PyOperation::getParentOperation() {
91849745f87SMike Urbach   checkValid();
919436c6c9cSStella Laurenzo   if (!isAttached())
920436c6c9cSStella Laurenzo     throw SetPyError(PyExc_ValueError, "Detached operations have no parent");
921436c6c9cSStella Laurenzo   MlirOperation operation = mlirOperationGetParentOperation(get());
922436c6c9cSStella Laurenzo   if (mlirOperationIsNull(operation))
9231689dadeSJohn Demme     return {};
924436c6c9cSStella Laurenzo   return PyOperation::forOperation(getContext(), operation);
925436c6c9cSStella Laurenzo }
926436c6c9cSStella Laurenzo 
927436c6c9cSStella Laurenzo PyBlock PyOperation::getBlock() {
92849745f87SMike Urbach   checkValid();
9291689dadeSJohn Demme   llvm::Optional<PyOperationRef> parentOperation = getParentOperation();
930436c6c9cSStella Laurenzo   MlirBlock block = mlirOperationGetBlock(get());
931436c6c9cSStella Laurenzo   assert(!mlirBlockIsNull(block) && "Attached operation has null parent");
9321689dadeSJohn Demme   assert(parentOperation && "Operation has no parent");
9331689dadeSJohn Demme   return PyBlock{std::move(*parentOperation), block};
934436c6c9cSStella Laurenzo }
935436c6c9cSStella Laurenzo 
9360126e906SJohn Demme py::object PyOperation::getCapsule() {
93749745f87SMike Urbach   checkValid();
9380126e906SJohn Demme   return py::reinterpret_steal<py::object>(mlirPythonOperationToCapsule(get()));
9390126e906SJohn Demme }
9400126e906SJohn Demme 
9410126e906SJohn Demme py::object PyOperation::createFromCapsule(py::object capsule) {
9420126e906SJohn Demme   MlirOperation rawOperation = mlirPythonCapsuleToOperation(capsule.ptr());
9430126e906SJohn Demme   if (mlirOperationIsNull(rawOperation))
9440126e906SJohn Demme     throw py::error_already_set();
9450126e906SJohn Demme   MlirContext rawCtxt = mlirOperationGetContext(rawOperation);
9460126e906SJohn Demme   return forOperation(PyMlirContext::forContext(rawCtxt), rawOperation)
9470126e906SJohn Demme       .releaseObject();
9480126e906SJohn Demme }
9490126e906SJohn Demme 
950436c6c9cSStella Laurenzo py::object PyOperation::create(
9511fc096afSMehdi Amini     const std::string &name, llvm::Optional<std::vector<PyType *>> results,
952436c6c9cSStella Laurenzo     llvm::Optional<std::vector<PyValue *>> operands,
953436c6c9cSStella Laurenzo     llvm::Optional<py::dict> attributes,
954436c6c9cSStella Laurenzo     llvm::Optional<std::vector<PyBlock *>> successors, int regions,
9551fc096afSMehdi Amini     DefaultingPyLocation location, const py::object &maybeIp) {
956436c6c9cSStella Laurenzo   llvm::SmallVector<MlirValue, 4> mlirOperands;
957436c6c9cSStella Laurenzo   llvm::SmallVector<MlirType, 4> mlirResults;
958436c6c9cSStella Laurenzo   llvm::SmallVector<MlirBlock, 4> mlirSuccessors;
959436c6c9cSStella Laurenzo   llvm::SmallVector<std::pair<std::string, MlirAttribute>, 4> mlirAttributes;
960436c6c9cSStella Laurenzo 
961436c6c9cSStella Laurenzo   // General parameter validation.
962436c6c9cSStella Laurenzo   if (regions < 0)
963436c6c9cSStella Laurenzo     throw SetPyError(PyExc_ValueError, "number of regions must be >= 0");
964436c6c9cSStella Laurenzo 
965436c6c9cSStella Laurenzo   // Unpack/validate operands.
966436c6c9cSStella Laurenzo   if (operands) {
967436c6c9cSStella Laurenzo     mlirOperands.reserve(operands->size());
968436c6c9cSStella Laurenzo     for (PyValue *operand : *operands) {
969436c6c9cSStella Laurenzo       if (!operand)
970436c6c9cSStella Laurenzo         throw SetPyError(PyExc_ValueError, "operand value cannot be None");
971436c6c9cSStella Laurenzo       mlirOperands.push_back(operand->get());
972436c6c9cSStella Laurenzo     }
973436c6c9cSStella Laurenzo   }
974436c6c9cSStella Laurenzo 
975436c6c9cSStella Laurenzo   // Unpack/validate results.
976436c6c9cSStella Laurenzo   if (results) {
977436c6c9cSStella Laurenzo     mlirResults.reserve(results->size());
978436c6c9cSStella Laurenzo     for (PyType *result : *results) {
979436c6c9cSStella Laurenzo       // TODO: Verify result type originate from the same context.
980436c6c9cSStella Laurenzo       if (!result)
981436c6c9cSStella Laurenzo         throw SetPyError(PyExc_ValueError, "result type cannot be None");
982436c6c9cSStella Laurenzo       mlirResults.push_back(*result);
983436c6c9cSStella Laurenzo     }
984436c6c9cSStella Laurenzo   }
985436c6c9cSStella Laurenzo   // Unpack/validate attributes.
986436c6c9cSStella Laurenzo   if (attributes) {
987436c6c9cSStella Laurenzo     mlirAttributes.reserve(attributes->size());
988436c6c9cSStella Laurenzo     for (auto &it : *attributes) {
989436c6c9cSStella Laurenzo       std::string key;
990436c6c9cSStella Laurenzo       try {
991436c6c9cSStella Laurenzo         key = it.first.cast<std::string>();
992436c6c9cSStella Laurenzo       } catch (py::cast_error &err) {
993436c6c9cSStella Laurenzo         std::string msg = "Invalid attribute key (not a string) when "
994436c6c9cSStella Laurenzo                           "attempting to create the operation \"" +
995436c6c9cSStella Laurenzo                           name + "\" (" + err.what() + ")";
996436c6c9cSStella Laurenzo         throw py::cast_error(msg);
997436c6c9cSStella Laurenzo       }
998436c6c9cSStella Laurenzo       try {
999436c6c9cSStella Laurenzo         auto &attribute = it.second.cast<PyAttribute &>();
1000436c6c9cSStella Laurenzo         // TODO: Verify attribute originates from the same context.
1001436c6c9cSStella Laurenzo         mlirAttributes.emplace_back(std::move(key), attribute);
1002436c6c9cSStella Laurenzo       } catch (py::reference_cast_error &) {
1003436c6c9cSStella Laurenzo         // This exception seems thrown when the value is "None".
1004436c6c9cSStella Laurenzo         std::string msg =
1005436c6c9cSStella Laurenzo             "Found an invalid (`None`?) attribute value for the key \"" + key +
1006436c6c9cSStella Laurenzo             "\" when attempting to create the operation \"" + name + "\"";
1007436c6c9cSStella Laurenzo         throw py::cast_error(msg);
1008436c6c9cSStella Laurenzo       } catch (py::cast_error &err) {
1009436c6c9cSStella Laurenzo         std::string msg = "Invalid attribute value for the key \"" + key +
1010436c6c9cSStella Laurenzo                           "\" when attempting to create the operation \"" +
1011436c6c9cSStella Laurenzo                           name + "\" (" + err.what() + ")";
1012436c6c9cSStella Laurenzo         throw py::cast_error(msg);
1013436c6c9cSStella Laurenzo       }
1014436c6c9cSStella Laurenzo     }
1015436c6c9cSStella Laurenzo   }
1016436c6c9cSStella Laurenzo   // Unpack/validate successors.
1017436c6c9cSStella Laurenzo   if (successors) {
1018436c6c9cSStella Laurenzo     mlirSuccessors.reserve(successors->size());
1019436c6c9cSStella Laurenzo     for (auto *successor : *successors) {
1020436c6c9cSStella Laurenzo       // TODO: Verify successor originate from the same context.
1021436c6c9cSStella Laurenzo       if (!successor)
1022436c6c9cSStella Laurenzo         throw SetPyError(PyExc_ValueError, "successor block cannot be None");
1023436c6c9cSStella Laurenzo       mlirSuccessors.push_back(successor->get());
1024436c6c9cSStella Laurenzo     }
1025436c6c9cSStella Laurenzo   }
1026436c6c9cSStella Laurenzo 
1027436c6c9cSStella Laurenzo   // Apply unpacked/validated to the operation state. Beyond this
1028436c6c9cSStella Laurenzo   // point, exceptions cannot be thrown or else the state will leak.
1029436c6c9cSStella Laurenzo   MlirOperationState state =
1030436c6c9cSStella Laurenzo       mlirOperationStateGet(toMlirStringRef(name), location);
1031436c6c9cSStella Laurenzo   if (!mlirOperands.empty())
1032436c6c9cSStella Laurenzo     mlirOperationStateAddOperands(&state, mlirOperands.size(),
1033436c6c9cSStella Laurenzo                                   mlirOperands.data());
1034436c6c9cSStella Laurenzo   if (!mlirResults.empty())
1035436c6c9cSStella Laurenzo     mlirOperationStateAddResults(&state, mlirResults.size(),
1036436c6c9cSStella Laurenzo                                  mlirResults.data());
1037436c6c9cSStella Laurenzo   if (!mlirAttributes.empty()) {
1038436c6c9cSStella Laurenzo     // Note that the attribute names directly reference bytes in
1039436c6c9cSStella Laurenzo     // mlirAttributes, so that vector must not be changed from here
1040436c6c9cSStella Laurenzo     // on.
1041436c6c9cSStella Laurenzo     llvm::SmallVector<MlirNamedAttribute, 4> mlirNamedAttributes;
1042436c6c9cSStella Laurenzo     mlirNamedAttributes.reserve(mlirAttributes.size());
1043436c6c9cSStella Laurenzo     for (auto &it : mlirAttributes)
1044436c6c9cSStella Laurenzo       mlirNamedAttributes.push_back(mlirNamedAttributeGet(
1045436c6c9cSStella Laurenzo           mlirIdentifierGet(mlirAttributeGetContext(it.second),
1046436c6c9cSStella Laurenzo                             toMlirStringRef(it.first)),
1047436c6c9cSStella Laurenzo           it.second));
1048436c6c9cSStella Laurenzo     mlirOperationStateAddAttributes(&state, mlirNamedAttributes.size(),
1049436c6c9cSStella Laurenzo                                     mlirNamedAttributes.data());
1050436c6c9cSStella Laurenzo   }
1051436c6c9cSStella Laurenzo   if (!mlirSuccessors.empty())
1052436c6c9cSStella Laurenzo     mlirOperationStateAddSuccessors(&state, mlirSuccessors.size(),
1053436c6c9cSStella Laurenzo                                     mlirSuccessors.data());
1054436c6c9cSStella Laurenzo   if (regions) {
1055436c6c9cSStella Laurenzo     llvm::SmallVector<MlirRegion, 4> mlirRegions;
1056436c6c9cSStella Laurenzo     mlirRegions.resize(regions);
1057436c6c9cSStella Laurenzo     for (int i = 0; i < regions; ++i)
1058436c6c9cSStella Laurenzo       mlirRegions[i] = mlirRegionCreate();
1059436c6c9cSStella Laurenzo     mlirOperationStateAddOwnedRegions(&state, mlirRegions.size(),
1060436c6c9cSStella Laurenzo                                       mlirRegions.data());
1061436c6c9cSStella Laurenzo   }
1062436c6c9cSStella Laurenzo 
1063436c6c9cSStella Laurenzo   // Construct the operation.
1064436c6c9cSStella Laurenzo   MlirOperation operation = mlirOperationCreate(&state);
1065436c6c9cSStella Laurenzo   PyOperationRef created =
1066436c6c9cSStella Laurenzo       PyOperation::createDetached(location->getContext(), operation);
1067436c6c9cSStella Laurenzo 
1068436c6c9cSStella Laurenzo   // InsertPoint active?
1069436c6c9cSStella Laurenzo   if (!maybeIp.is(py::cast(false))) {
1070436c6c9cSStella Laurenzo     PyInsertionPoint *ip;
1071436c6c9cSStella Laurenzo     if (maybeIp.is_none()) {
1072436c6c9cSStella Laurenzo       ip = PyThreadContextEntry::getDefaultInsertionPoint();
1073436c6c9cSStella Laurenzo     } else {
1074436c6c9cSStella Laurenzo       ip = py::cast<PyInsertionPoint *>(maybeIp);
1075436c6c9cSStella Laurenzo     }
1076436c6c9cSStella Laurenzo     if (ip)
1077436c6c9cSStella Laurenzo       ip->insert(*created.get());
1078436c6c9cSStella Laurenzo   }
1079436c6c9cSStella Laurenzo 
1080436c6c9cSStella Laurenzo   return created->createOpView();
1081436c6c9cSStella Laurenzo }
1082436c6c9cSStella Laurenzo 
1083436c6c9cSStella Laurenzo py::object PyOperation::createOpView() {
108449745f87SMike Urbach   checkValid();
1085436c6c9cSStella Laurenzo   MlirIdentifier ident = mlirOperationGetName(get());
1086436c6c9cSStella Laurenzo   MlirStringRef identStr = mlirIdentifierStr(ident);
1087436c6c9cSStella Laurenzo   auto opViewClass = PyGlobals::get().lookupRawOpViewClass(
1088436c6c9cSStella Laurenzo       StringRef(identStr.data, identStr.length));
1089436c6c9cSStella Laurenzo   if (opViewClass)
1090436c6c9cSStella Laurenzo     return (*opViewClass)(getRef().getObject());
1091436c6c9cSStella Laurenzo   return py::cast(PyOpView(getRef().getObject()));
1092436c6c9cSStella Laurenzo }
1093436c6c9cSStella Laurenzo 
109449745f87SMike Urbach void PyOperation::erase() {
109549745f87SMike Urbach   checkValid();
109649745f87SMike Urbach   // TODO: Fix memory hazards when erasing a tree of operations for which a deep
109749745f87SMike Urbach   // Python reference to a child operation is live. All children should also
109849745f87SMike Urbach   // have their `valid` bit set to false.
109949745f87SMike Urbach   auto &liveOperations = getContext()->liveOperations;
110049745f87SMike Urbach   if (liveOperations.count(operation.ptr))
110149745f87SMike Urbach     liveOperations.erase(operation.ptr);
110249745f87SMike Urbach   mlirOperationDestroy(operation);
110349745f87SMike Urbach   valid = false;
110449745f87SMike Urbach }
110549745f87SMike Urbach 
1106436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1107436c6c9cSStella Laurenzo // PyOpView
1108436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1109436c6c9cSStella Laurenzo 
1110436c6c9cSStella Laurenzo py::object
11111fc096afSMehdi Amini PyOpView::buildGeneric(const py::object &cls, py::list resultTypeList,
1112436c6c9cSStella Laurenzo                        py::list operandList,
1113436c6c9cSStella Laurenzo                        llvm::Optional<py::dict> attributes,
1114436c6c9cSStella Laurenzo                        llvm::Optional<std::vector<PyBlock *>> successors,
1115436c6c9cSStella Laurenzo                        llvm::Optional<int> regions,
1116436c6c9cSStella Laurenzo                        DefaultingPyLocation location, py::object maybeIp) {
1117436c6c9cSStella Laurenzo   PyMlirContextRef context = location->getContext();
1118436c6c9cSStella Laurenzo   // Class level operation construction metadata.
1119436c6c9cSStella Laurenzo   std::string name = py::cast<std::string>(cls.attr("OPERATION_NAME"));
1120436c6c9cSStella Laurenzo   // Operand and result segment specs are either none, which does no
1121436c6c9cSStella Laurenzo   // variadic unpacking, or a list of ints with segment sizes, where each
1122436c6c9cSStella Laurenzo   // element is either a positive number (typically 1 for a scalar) or -1 to
1123436c6c9cSStella Laurenzo   // indicate that it is derived from the length of the same-indexed operand
1124436c6c9cSStella Laurenzo   // or result (implying that it is a list at that position).
1125436c6c9cSStella Laurenzo   py::object operandSegmentSpecObj = cls.attr("_ODS_OPERAND_SEGMENTS");
1126436c6c9cSStella Laurenzo   py::object resultSegmentSpecObj = cls.attr("_ODS_RESULT_SEGMENTS");
1127436c6c9cSStella Laurenzo 
11288d05a288SStella Laurenzo   std::vector<uint32_t> operandSegmentLengths;
11298d05a288SStella Laurenzo   std::vector<uint32_t> resultSegmentLengths;
1130436c6c9cSStella Laurenzo 
1131436c6c9cSStella Laurenzo   // Validate/determine region count.
1132436c6c9cSStella Laurenzo   auto opRegionSpec = py::cast<std::tuple<int, bool>>(cls.attr("_ODS_REGIONS"));
1133436c6c9cSStella Laurenzo   int opMinRegionCount = std::get<0>(opRegionSpec);
1134436c6c9cSStella Laurenzo   bool opHasNoVariadicRegions = std::get<1>(opRegionSpec);
1135436c6c9cSStella Laurenzo   if (!regions) {
1136436c6c9cSStella Laurenzo     regions = opMinRegionCount;
1137436c6c9cSStella Laurenzo   }
1138436c6c9cSStella Laurenzo   if (*regions < opMinRegionCount) {
1139436c6c9cSStella Laurenzo     throw py::value_error(
1140436c6c9cSStella Laurenzo         (llvm::Twine("Operation \"") + name + "\" requires a minimum of " +
1141436c6c9cSStella Laurenzo          llvm::Twine(opMinRegionCount) +
1142436c6c9cSStella Laurenzo          " regions but was built with regions=" + llvm::Twine(*regions))
1143436c6c9cSStella Laurenzo             .str());
1144436c6c9cSStella Laurenzo   }
1145436c6c9cSStella Laurenzo   if (opHasNoVariadicRegions && *regions > opMinRegionCount) {
1146436c6c9cSStella Laurenzo     throw py::value_error(
1147436c6c9cSStella Laurenzo         (llvm::Twine("Operation \"") + name + "\" requires a maximum of " +
1148436c6c9cSStella Laurenzo          llvm::Twine(opMinRegionCount) +
1149436c6c9cSStella Laurenzo          " regions but was built with regions=" + llvm::Twine(*regions))
1150436c6c9cSStella Laurenzo             .str());
1151436c6c9cSStella Laurenzo   }
1152436c6c9cSStella Laurenzo 
1153436c6c9cSStella Laurenzo   // Unpack results.
1154436c6c9cSStella Laurenzo   std::vector<PyType *> resultTypes;
1155436c6c9cSStella Laurenzo   resultTypes.reserve(resultTypeList.size());
1156436c6c9cSStella Laurenzo   if (resultSegmentSpecObj.is_none()) {
1157436c6c9cSStella Laurenzo     // Non-variadic result unpacking.
1158*e4853be2SMehdi Amini     for (const auto &it : llvm::enumerate(resultTypeList)) {
1159436c6c9cSStella Laurenzo       try {
1160436c6c9cSStella Laurenzo         resultTypes.push_back(py::cast<PyType *>(it.value()));
1161436c6c9cSStella Laurenzo         if (!resultTypes.back())
1162436c6c9cSStella Laurenzo           throw py::cast_error();
1163436c6c9cSStella Laurenzo       } catch (py::cast_error &err) {
1164436c6c9cSStella Laurenzo         throw py::value_error((llvm::Twine("Result ") +
1165436c6c9cSStella Laurenzo                                llvm::Twine(it.index()) + " of operation \"" +
1166436c6c9cSStella Laurenzo                                name + "\" must be a Type (" + err.what() + ")")
1167436c6c9cSStella Laurenzo                                   .str());
1168436c6c9cSStella Laurenzo       }
1169436c6c9cSStella Laurenzo     }
1170436c6c9cSStella Laurenzo   } else {
1171436c6c9cSStella Laurenzo     // Sized result unpacking.
1172436c6c9cSStella Laurenzo     auto resultSegmentSpec = py::cast<std::vector<int>>(resultSegmentSpecObj);
1173436c6c9cSStella Laurenzo     if (resultSegmentSpec.size() != resultTypeList.size()) {
1174436c6c9cSStella Laurenzo       throw py::value_error((llvm::Twine("Operation \"") + name +
1175436c6c9cSStella Laurenzo                              "\" requires " +
1176436c6c9cSStella Laurenzo                              llvm::Twine(resultSegmentSpec.size()) +
1177436c6c9cSStella Laurenzo                              " result segments but was provided " +
1178436c6c9cSStella Laurenzo                              llvm::Twine(resultTypeList.size()))
1179436c6c9cSStella Laurenzo                                 .str());
1180436c6c9cSStella Laurenzo     }
1181436c6c9cSStella Laurenzo     resultSegmentLengths.reserve(resultTypeList.size());
1182*e4853be2SMehdi Amini     for (const auto &it :
1183436c6c9cSStella Laurenzo          llvm::enumerate(llvm::zip(resultTypeList, resultSegmentSpec))) {
1184436c6c9cSStella Laurenzo       int segmentSpec = std::get<1>(it.value());
1185436c6c9cSStella Laurenzo       if (segmentSpec == 1 || segmentSpec == 0) {
1186436c6c9cSStella Laurenzo         // Unpack unary element.
1187436c6c9cSStella Laurenzo         try {
11886981e5ecSAlex Zinenko           auto *resultType = py::cast<PyType *>(std::get<0>(it.value()));
1189436c6c9cSStella Laurenzo           if (resultType) {
1190436c6c9cSStella Laurenzo             resultTypes.push_back(resultType);
1191436c6c9cSStella Laurenzo             resultSegmentLengths.push_back(1);
1192436c6c9cSStella Laurenzo           } else if (segmentSpec == 0) {
1193436c6c9cSStella Laurenzo             // Allowed to be optional.
1194436c6c9cSStella Laurenzo             resultSegmentLengths.push_back(0);
1195436c6c9cSStella Laurenzo           } else {
1196436c6c9cSStella Laurenzo             throw py::cast_error("was None and result is not optional");
1197436c6c9cSStella Laurenzo           }
1198436c6c9cSStella Laurenzo         } catch (py::cast_error &err) {
1199436c6c9cSStella Laurenzo           throw py::value_error((llvm::Twine("Result ") +
1200436c6c9cSStella Laurenzo                                  llvm::Twine(it.index()) + " of operation \"" +
1201436c6c9cSStella Laurenzo                                  name + "\" must be a Type (" + err.what() +
1202436c6c9cSStella Laurenzo                                  ")")
1203436c6c9cSStella Laurenzo                                     .str());
1204436c6c9cSStella Laurenzo         }
1205436c6c9cSStella Laurenzo       } else if (segmentSpec == -1) {
1206436c6c9cSStella Laurenzo         // Unpack sequence by appending.
1207436c6c9cSStella Laurenzo         try {
1208436c6c9cSStella Laurenzo           if (std::get<0>(it.value()).is_none()) {
1209436c6c9cSStella Laurenzo             // Treat it as an empty list.
1210436c6c9cSStella Laurenzo             resultSegmentLengths.push_back(0);
1211436c6c9cSStella Laurenzo           } else {
1212436c6c9cSStella Laurenzo             // Unpack the list.
1213436c6c9cSStella Laurenzo             auto segment = py::cast<py::sequence>(std::get<0>(it.value()));
1214436c6c9cSStella Laurenzo             for (py::object segmentItem : segment) {
1215436c6c9cSStella Laurenzo               resultTypes.push_back(py::cast<PyType *>(segmentItem));
1216436c6c9cSStella Laurenzo               if (!resultTypes.back()) {
1217436c6c9cSStella Laurenzo                 throw py::cast_error("contained a None item");
1218436c6c9cSStella Laurenzo               }
1219436c6c9cSStella Laurenzo             }
1220436c6c9cSStella Laurenzo             resultSegmentLengths.push_back(segment.size());
1221436c6c9cSStella Laurenzo           }
1222436c6c9cSStella Laurenzo         } catch (std::exception &err) {
1223436c6c9cSStella Laurenzo           // NOTE: Sloppy to be using a catch-all here, but there are at least
1224436c6c9cSStella Laurenzo           // three different unrelated exceptions that can be thrown in the
1225436c6c9cSStella Laurenzo           // above "casts". Just keep the scope above small and catch them all.
1226436c6c9cSStella Laurenzo           throw py::value_error((llvm::Twine("Result ") +
1227436c6c9cSStella Laurenzo                                  llvm::Twine(it.index()) + " of operation \"" +
1228436c6c9cSStella Laurenzo                                  name + "\" must be a Sequence of Types (" +
1229436c6c9cSStella Laurenzo                                  err.what() + ")")
1230436c6c9cSStella Laurenzo                                     .str());
1231436c6c9cSStella Laurenzo         }
1232436c6c9cSStella Laurenzo       } else {
1233436c6c9cSStella Laurenzo         throw py::value_error("Unexpected segment spec");
1234436c6c9cSStella Laurenzo       }
1235436c6c9cSStella Laurenzo     }
1236436c6c9cSStella Laurenzo   }
1237436c6c9cSStella Laurenzo 
1238436c6c9cSStella Laurenzo   // Unpack operands.
1239436c6c9cSStella Laurenzo   std::vector<PyValue *> operands;
1240436c6c9cSStella Laurenzo   operands.reserve(operands.size());
1241436c6c9cSStella Laurenzo   if (operandSegmentSpecObj.is_none()) {
1242436c6c9cSStella Laurenzo     // Non-sized operand unpacking.
1243*e4853be2SMehdi Amini     for (const auto &it : llvm::enumerate(operandList)) {
1244436c6c9cSStella Laurenzo       try {
1245436c6c9cSStella Laurenzo         operands.push_back(py::cast<PyValue *>(it.value()));
1246436c6c9cSStella Laurenzo         if (!operands.back())
1247436c6c9cSStella Laurenzo           throw py::cast_error();
1248436c6c9cSStella Laurenzo       } catch (py::cast_error &err) {
1249436c6c9cSStella Laurenzo         throw py::value_error((llvm::Twine("Operand ") +
1250436c6c9cSStella Laurenzo                                llvm::Twine(it.index()) + " of operation \"" +
1251436c6c9cSStella Laurenzo                                name + "\" must be a Value (" + err.what() + ")")
1252436c6c9cSStella Laurenzo                                   .str());
1253436c6c9cSStella Laurenzo       }
1254436c6c9cSStella Laurenzo     }
1255436c6c9cSStella Laurenzo   } else {
1256436c6c9cSStella Laurenzo     // Sized operand unpacking.
1257436c6c9cSStella Laurenzo     auto operandSegmentSpec = py::cast<std::vector<int>>(operandSegmentSpecObj);
1258436c6c9cSStella Laurenzo     if (operandSegmentSpec.size() != operandList.size()) {
1259436c6c9cSStella Laurenzo       throw py::value_error((llvm::Twine("Operation \"") + name +
1260436c6c9cSStella Laurenzo                              "\" requires " +
1261436c6c9cSStella Laurenzo                              llvm::Twine(operandSegmentSpec.size()) +
1262436c6c9cSStella Laurenzo                              "operand segments but was provided " +
1263436c6c9cSStella Laurenzo                              llvm::Twine(operandList.size()))
1264436c6c9cSStella Laurenzo                                 .str());
1265436c6c9cSStella Laurenzo     }
1266436c6c9cSStella Laurenzo     operandSegmentLengths.reserve(operandList.size());
1267*e4853be2SMehdi Amini     for (const auto &it :
1268436c6c9cSStella Laurenzo          llvm::enumerate(llvm::zip(operandList, operandSegmentSpec))) {
1269436c6c9cSStella Laurenzo       int segmentSpec = std::get<1>(it.value());
1270436c6c9cSStella Laurenzo       if (segmentSpec == 1 || segmentSpec == 0) {
1271436c6c9cSStella Laurenzo         // Unpack unary element.
1272436c6c9cSStella Laurenzo         try {
127302b6fb21SMehdi Amini           auto *operandValue = py::cast<PyValue *>(std::get<0>(it.value()));
1274436c6c9cSStella Laurenzo           if (operandValue) {
1275436c6c9cSStella Laurenzo             operands.push_back(operandValue);
1276436c6c9cSStella Laurenzo             operandSegmentLengths.push_back(1);
1277436c6c9cSStella Laurenzo           } else if (segmentSpec == 0) {
1278436c6c9cSStella Laurenzo             // Allowed to be optional.
1279436c6c9cSStella Laurenzo             operandSegmentLengths.push_back(0);
1280436c6c9cSStella Laurenzo           } else {
1281436c6c9cSStella Laurenzo             throw py::cast_error("was None and operand is not optional");
1282436c6c9cSStella Laurenzo           }
1283436c6c9cSStella Laurenzo         } catch (py::cast_error &err) {
1284436c6c9cSStella Laurenzo           throw py::value_error((llvm::Twine("Operand ") +
1285436c6c9cSStella Laurenzo                                  llvm::Twine(it.index()) + " of operation \"" +
1286436c6c9cSStella Laurenzo                                  name + "\" must be a Value (" + err.what() +
1287436c6c9cSStella Laurenzo                                  ")")
1288436c6c9cSStella Laurenzo                                     .str());
1289436c6c9cSStella Laurenzo         }
1290436c6c9cSStella Laurenzo       } else if (segmentSpec == -1) {
1291436c6c9cSStella Laurenzo         // Unpack sequence by appending.
1292436c6c9cSStella Laurenzo         try {
1293436c6c9cSStella Laurenzo           if (std::get<0>(it.value()).is_none()) {
1294436c6c9cSStella Laurenzo             // Treat it as an empty list.
1295436c6c9cSStella Laurenzo             operandSegmentLengths.push_back(0);
1296436c6c9cSStella Laurenzo           } else {
1297436c6c9cSStella Laurenzo             // Unpack the list.
1298436c6c9cSStella Laurenzo             auto segment = py::cast<py::sequence>(std::get<0>(it.value()));
1299436c6c9cSStella Laurenzo             for (py::object segmentItem : segment) {
1300436c6c9cSStella Laurenzo               operands.push_back(py::cast<PyValue *>(segmentItem));
1301436c6c9cSStella Laurenzo               if (!operands.back()) {
1302436c6c9cSStella Laurenzo                 throw py::cast_error("contained a None item");
1303436c6c9cSStella Laurenzo               }
1304436c6c9cSStella Laurenzo             }
1305436c6c9cSStella Laurenzo             operandSegmentLengths.push_back(segment.size());
1306436c6c9cSStella Laurenzo           }
1307436c6c9cSStella Laurenzo         } catch (std::exception &err) {
1308436c6c9cSStella Laurenzo           // NOTE: Sloppy to be using a catch-all here, but there are at least
1309436c6c9cSStella Laurenzo           // three different unrelated exceptions that can be thrown in the
1310436c6c9cSStella Laurenzo           // above "casts". Just keep the scope above small and catch them all.
1311436c6c9cSStella Laurenzo           throw py::value_error((llvm::Twine("Operand ") +
1312436c6c9cSStella Laurenzo                                  llvm::Twine(it.index()) + " of operation \"" +
1313436c6c9cSStella Laurenzo                                  name + "\" must be a Sequence of Values (" +
1314436c6c9cSStella Laurenzo                                  err.what() + ")")
1315436c6c9cSStella Laurenzo                                     .str());
1316436c6c9cSStella Laurenzo         }
1317436c6c9cSStella Laurenzo       } else {
1318436c6c9cSStella Laurenzo         throw py::value_error("Unexpected segment spec");
1319436c6c9cSStella Laurenzo       }
1320436c6c9cSStella Laurenzo     }
1321436c6c9cSStella Laurenzo   }
1322436c6c9cSStella Laurenzo 
1323436c6c9cSStella Laurenzo   // Merge operand/result segment lengths into attributes if needed.
1324436c6c9cSStella Laurenzo   if (!operandSegmentLengths.empty() || !resultSegmentLengths.empty()) {
1325436c6c9cSStella Laurenzo     // Dup.
1326436c6c9cSStella Laurenzo     if (attributes) {
1327436c6c9cSStella Laurenzo       attributes = py::dict(*attributes);
1328436c6c9cSStella Laurenzo     } else {
1329436c6c9cSStella Laurenzo       attributes = py::dict();
1330436c6c9cSStella Laurenzo     }
1331436c6c9cSStella Laurenzo     if (attributes->contains("result_segment_sizes") ||
1332436c6c9cSStella Laurenzo         attributes->contains("operand_segment_sizes")) {
1333436c6c9cSStella Laurenzo       throw py::value_error("Manually setting a 'result_segment_sizes' or "
1334436c6c9cSStella Laurenzo                             "'operand_segment_sizes' attribute is unsupported. "
1335436c6c9cSStella Laurenzo                             "Use Operation.create for such low-level access.");
1336436c6c9cSStella Laurenzo     }
1337436c6c9cSStella Laurenzo 
1338436c6c9cSStella Laurenzo     // Add result_segment_sizes attribute.
1339436c6c9cSStella Laurenzo     if (!resultSegmentLengths.empty()) {
1340436c6c9cSStella Laurenzo       int64_t size = resultSegmentLengths.size();
13418d05a288SStella Laurenzo       MlirAttribute segmentLengthAttr = mlirDenseElementsAttrUInt32Get(
13428d05a288SStella Laurenzo           mlirVectorTypeGet(1, &size, mlirIntegerTypeGet(context->get(), 32)),
1343436c6c9cSStella Laurenzo           resultSegmentLengths.size(), resultSegmentLengths.data());
1344436c6c9cSStella Laurenzo       (*attributes)["result_segment_sizes"] =
1345436c6c9cSStella Laurenzo           PyAttribute(context, segmentLengthAttr);
1346436c6c9cSStella Laurenzo     }
1347436c6c9cSStella Laurenzo 
1348436c6c9cSStella Laurenzo     // Add operand_segment_sizes attribute.
1349436c6c9cSStella Laurenzo     if (!operandSegmentLengths.empty()) {
1350436c6c9cSStella Laurenzo       int64_t size = operandSegmentLengths.size();
13518d05a288SStella Laurenzo       MlirAttribute segmentLengthAttr = mlirDenseElementsAttrUInt32Get(
13528d05a288SStella Laurenzo           mlirVectorTypeGet(1, &size, mlirIntegerTypeGet(context->get(), 32)),
1353436c6c9cSStella Laurenzo           operandSegmentLengths.size(), operandSegmentLengths.data());
1354436c6c9cSStella Laurenzo       (*attributes)["operand_segment_sizes"] =
1355436c6c9cSStella Laurenzo           PyAttribute(context, segmentLengthAttr);
1356436c6c9cSStella Laurenzo     }
1357436c6c9cSStella Laurenzo   }
1358436c6c9cSStella Laurenzo 
1359436c6c9cSStella Laurenzo   // Delegate to create.
1360436c6c9cSStella Laurenzo   return PyOperation::create(std::move(name),
1361436c6c9cSStella Laurenzo                              /*results=*/std::move(resultTypes),
1362436c6c9cSStella Laurenzo                              /*operands=*/std::move(operands),
1363436c6c9cSStella Laurenzo                              /*attributes=*/std::move(attributes),
1364436c6c9cSStella Laurenzo                              /*successors=*/std::move(successors),
13651fc096afSMehdi Amini                              /*regions=*/*regions, location,
13661fc096afSMehdi Amini                              std::move(maybeIp));
1367436c6c9cSStella Laurenzo }
1368436c6c9cSStella Laurenzo 
13691fc096afSMehdi Amini PyOpView::PyOpView(const py::object &operationObject)
1370436c6c9cSStella Laurenzo     // Casting through the PyOperationBase base-class and then back to the
1371436c6c9cSStella Laurenzo     // Operation lets us accept any PyOperationBase subclass.
1372436c6c9cSStella Laurenzo     : operation(py::cast<PyOperationBase &>(operationObject).getOperation()),
1373436c6c9cSStella Laurenzo       operationObject(operation.getRef().getObject()) {}
1374436c6c9cSStella Laurenzo 
13751fc096afSMehdi Amini py::object PyOpView::createRawSubclass(const py::object &userClass) {
1376436c6c9cSStella Laurenzo   // This is... a little gross. The typical pattern is to have a pure python
1377436c6c9cSStella Laurenzo   // class that extends OpView like:
1378436c6c9cSStella Laurenzo   //   class AddFOp(_cext.ir.OpView):
1379436c6c9cSStella Laurenzo   //     def __init__(self, loc, lhs, rhs):
1380436c6c9cSStella Laurenzo   //       operation = loc.context.create_operation(
1381436c6c9cSStella Laurenzo   //           "addf", lhs, rhs, results=[lhs.type])
1382436c6c9cSStella Laurenzo   //       super().__init__(operation)
1383436c6c9cSStella Laurenzo   //
1384436c6c9cSStella Laurenzo   // I.e. The goal of the user facing type is to provide a nice constructor
1385436c6c9cSStella Laurenzo   // that has complete freedom for the op under construction. This is at odds
1386436c6c9cSStella Laurenzo   // with our other desire to sometimes create this object by just passing an
1387436c6c9cSStella Laurenzo   // operation (to initialize the base class). We could do *arg and **kwargs
1388436c6c9cSStella Laurenzo   // munging to try to make it work, but instead, we synthesize a new class
1389436c6c9cSStella Laurenzo   // on the fly which extends this user class (AddFOp in this example) and
1390436c6c9cSStella Laurenzo   // *give it* the base class's __init__ method, thus bypassing the
1391436c6c9cSStella Laurenzo   // intermediate subclass's __init__ method entirely. While slightly,
1392436c6c9cSStella Laurenzo   // underhanded, this is safe/legal because the type hierarchy has not changed
1393436c6c9cSStella Laurenzo   // (we just added a new leaf) and we aren't mucking around with __new__.
1394436c6c9cSStella Laurenzo   // Typically, this new class will be stored on the original as "_Raw" and will
1395436c6c9cSStella Laurenzo   // be used for casts and other things that need a variant of the class that
1396436c6c9cSStella Laurenzo   // is initialized purely from an operation.
1397436c6c9cSStella Laurenzo   py::object parentMetaclass =
1398436c6c9cSStella Laurenzo       py::reinterpret_borrow<py::object>((PyObject *)&PyType_Type);
1399436c6c9cSStella Laurenzo   py::dict attributes;
1400436c6c9cSStella Laurenzo   // TODO: pybind11 2.6 supports a more direct form. Upgrade many years from
1401436c6c9cSStella Laurenzo   // now.
1402436c6c9cSStella Laurenzo   //   auto opViewType = py::type::of<PyOpView>();
1403436c6c9cSStella Laurenzo   auto opViewType = py::detail::get_type_handle(typeid(PyOpView), true);
1404436c6c9cSStella Laurenzo   attributes["__init__"] = opViewType.attr("__init__");
1405436c6c9cSStella Laurenzo   py::str origName = userClass.attr("__name__");
1406436c6c9cSStella Laurenzo   py::str newName = py::str("_") + origName;
1407436c6c9cSStella Laurenzo   return parentMetaclass(newName, py::make_tuple(userClass), attributes);
1408436c6c9cSStella Laurenzo }
1409436c6c9cSStella Laurenzo 
1410436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1411436c6c9cSStella Laurenzo // PyInsertionPoint.
1412436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1413436c6c9cSStella Laurenzo 
1414436c6c9cSStella Laurenzo PyInsertionPoint::PyInsertionPoint(PyBlock &block) : block(block) {}
1415436c6c9cSStella Laurenzo 
1416436c6c9cSStella Laurenzo PyInsertionPoint::PyInsertionPoint(PyOperationBase &beforeOperationBase)
1417436c6c9cSStella Laurenzo     : refOperation(beforeOperationBase.getOperation().getRef()),
1418436c6c9cSStella Laurenzo       block((*refOperation)->getBlock()) {}
1419436c6c9cSStella Laurenzo 
1420436c6c9cSStella Laurenzo void PyInsertionPoint::insert(PyOperationBase &operationBase) {
1421436c6c9cSStella Laurenzo   PyOperation &operation = operationBase.getOperation();
1422436c6c9cSStella Laurenzo   if (operation.isAttached())
1423436c6c9cSStella Laurenzo     throw SetPyError(PyExc_ValueError,
1424436c6c9cSStella Laurenzo                      "Attempt to insert operation that is already attached");
1425436c6c9cSStella Laurenzo   block.getParentOperation()->checkValid();
1426436c6c9cSStella Laurenzo   MlirOperation beforeOp = {nullptr};
1427436c6c9cSStella Laurenzo   if (refOperation) {
1428436c6c9cSStella Laurenzo     // Insert before operation.
1429436c6c9cSStella Laurenzo     (*refOperation)->checkValid();
1430436c6c9cSStella Laurenzo     beforeOp = (*refOperation)->get();
1431436c6c9cSStella Laurenzo   } else {
1432436c6c9cSStella Laurenzo     // Insert at end (before null) is only valid if the block does not
1433436c6c9cSStella Laurenzo     // already end in a known terminator (violating this will cause assertion
1434436c6c9cSStella Laurenzo     // failures later).
1435436c6c9cSStella Laurenzo     if (!mlirOperationIsNull(mlirBlockGetTerminator(block.get()))) {
1436436c6c9cSStella Laurenzo       throw py::index_error("Cannot insert operation at the end of a block "
1437436c6c9cSStella Laurenzo                             "that already has a terminator. Did you mean to "
1438436c6c9cSStella Laurenzo                             "use 'InsertionPoint.at_block_terminator(block)' "
1439436c6c9cSStella Laurenzo                             "versus 'InsertionPoint(block)'?");
1440436c6c9cSStella Laurenzo     }
1441436c6c9cSStella Laurenzo   }
1442436c6c9cSStella Laurenzo   mlirBlockInsertOwnedOperationBefore(block.get(), beforeOp, operation);
1443436c6c9cSStella Laurenzo   operation.setAttached();
1444436c6c9cSStella Laurenzo }
1445436c6c9cSStella Laurenzo 
1446436c6c9cSStella Laurenzo PyInsertionPoint PyInsertionPoint::atBlockBegin(PyBlock &block) {
1447436c6c9cSStella Laurenzo   MlirOperation firstOp = mlirBlockGetFirstOperation(block.get());
1448436c6c9cSStella Laurenzo   if (mlirOperationIsNull(firstOp)) {
1449436c6c9cSStella Laurenzo     // Just insert at end.
1450436c6c9cSStella Laurenzo     return PyInsertionPoint(block);
1451436c6c9cSStella Laurenzo   }
1452436c6c9cSStella Laurenzo 
1453436c6c9cSStella Laurenzo   // Insert before first op.
1454436c6c9cSStella Laurenzo   PyOperationRef firstOpRef = PyOperation::forOperation(
1455436c6c9cSStella Laurenzo       block.getParentOperation()->getContext(), firstOp);
1456436c6c9cSStella Laurenzo   return PyInsertionPoint{block, std::move(firstOpRef)};
1457436c6c9cSStella Laurenzo }
1458436c6c9cSStella Laurenzo 
1459436c6c9cSStella Laurenzo PyInsertionPoint PyInsertionPoint::atBlockTerminator(PyBlock &block) {
1460436c6c9cSStella Laurenzo   MlirOperation terminator = mlirBlockGetTerminator(block.get());
1461436c6c9cSStella Laurenzo   if (mlirOperationIsNull(terminator))
1462436c6c9cSStella Laurenzo     throw SetPyError(PyExc_ValueError, "Block has no terminator");
1463436c6c9cSStella Laurenzo   PyOperationRef terminatorOpRef = PyOperation::forOperation(
1464436c6c9cSStella Laurenzo       block.getParentOperation()->getContext(), terminator);
1465436c6c9cSStella Laurenzo   return PyInsertionPoint{block, std::move(terminatorOpRef)};
1466436c6c9cSStella Laurenzo }
1467436c6c9cSStella Laurenzo 
1468436c6c9cSStella Laurenzo py::object PyInsertionPoint::contextEnter() {
1469436c6c9cSStella Laurenzo   return PyThreadContextEntry::pushInsertionPoint(*this);
1470436c6c9cSStella Laurenzo }
1471436c6c9cSStella Laurenzo 
14721fc096afSMehdi Amini void PyInsertionPoint::contextExit(const pybind11::object &excType,
14731fc096afSMehdi Amini                                    const pybind11::object &excVal,
14741fc096afSMehdi Amini                                    const pybind11::object &excTb) {
1475436c6c9cSStella Laurenzo   PyThreadContextEntry::popInsertionPoint(*this);
1476436c6c9cSStella Laurenzo }
1477436c6c9cSStella Laurenzo 
1478436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1479436c6c9cSStella Laurenzo // PyAttribute.
1480436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1481436c6c9cSStella Laurenzo 
1482436c6c9cSStella Laurenzo bool PyAttribute::operator==(const PyAttribute &other) {
1483436c6c9cSStella Laurenzo   return mlirAttributeEqual(attr, other.attr);
1484436c6c9cSStella Laurenzo }
1485436c6c9cSStella Laurenzo 
1486436c6c9cSStella Laurenzo py::object PyAttribute::getCapsule() {
1487436c6c9cSStella Laurenzo   return py::reinterpret_steal<py::object>(mlirPythonAttributeToCapsule(*this));
1488436c6c9cSStella Laurenzo }
1489436c6c9cSStella Laurenzo 
1490436c6c9cSStella Laurenzo PyAttribute PyAttribute::createFromCapsule(py::object capsule) {
1491436c6c9cSStella Laurenzo   MlirAttribute rawAttr = mlirPythonCapsuleToAttribute(capsule.ptr());
1492436c6c9cSStella Laurenzo   if (mlirAttributeIsNull(rawAttr))
1493436c6c9cSStella Laurenzo     throw py::error_already_set();
1494436c6c9cSStella Laurenzo   return PyAttribute(
1495436c6c9cSStella Laurenzo       PyMlirContext::forContext(mlirAttributeGetContext(rawAttr)), rawAttr);
1496436c6c9cSStella Laurenzo }
1497436c6c9cSStella Laurenzo 
1498436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1499436c6c9cSStella Laurenzo // PyNamedAttribute.
1500436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1501436c6c9cSStella Laurenzo 
1502436c6c9cSStella Laurenzo PyNamedAttribute::PyNamedAttribute(MlirAttribute attr, std::string ownedName)
1503436c6c9cSStella Laurenzo     : ownedName(new std::string(std::move(ownedName))) {
1504436c6c9cSStella Laurenzo   namedAttr = mlirNamedAttributeGet(
1505436c6c9cSStella Laurenzo       mlirIdentifierGet(mlirAttributeGetContext(attr),
1506436c6c9cSStella Laurenzo                         toMlirStringRef(*this->ownedName)),
1507436c6c9cSStella Laurenzo       attr);
1508436c6c9cSStella Laurenzo }
1509436c6c9cSStella Laurenzo 
1510436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1511436c6c9cSStella Laurenzo // PyType.
1512436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1513436c6c9cSStella Laurenzo 
1514436c6c9cSStella Laurenzo bool PyType::operator==(const PyType &other) {
1515436c6c9cSStella Laurenzo   return mlirTypeEqual(type, other.type);
1516436c6c9cSStella Laurenzo }
1517436c6c9cSStella Laurenzo 
1518436c6c9cSStella Laurenzo py::object PyType::getCapsule() {
1519436c6c9cSStella Laurenzo   return py::reinterpret_steal<py::object>(mlirPythonTypeToCapsule(*this));
1520436c6c9cSStella Laurenzo }
1521436c6c9cSStella Laurenzo 
1522436c6c9cSStella Laurenzo PyType PyType::createFromCapsule(py::object capsule) {
1523436c6c9cSStella Laurenzo   MlirType rawType = mlirPythonCapsuleToType(capsule.ptr());
1524436c6c9cSStella Laurenzo   if (mlirTypeIsNull(rawType))
1525436c6c9cSStella Laurenzo     throw py::error_already_set();
1526436c6c9cSStella Laurenzo   return PyType(PyMlirContext::forContext(mlirTypeGetContext(rawType)),
1527436c6c9cSStella Laurenzo                 rawType);
1528436c6c9cSStella Laurenzo }
1529436c6c9cSStella Laurenzo 
1530436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1531436c6c9cSStella Laurenzo // PyValue and subclases.
1532436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
1533436c6c9cSStella Laurenzo 
15343f3d1c90SMike Urbach pybind11::object PyValue::getCapsule() {
15353f3d1c90SMike Urbach   return py::reinterpret_steal<py::object>(mlirPythonValueToCapsule(get()));
15363f3d1c90SMike Urbach }
15373f3d1c90SMike Urbach 
15383f3d1c90SMike Urbach PyValue PyValue::createFromCapsule(pybind11::object capsule) {
15393f3d1c90SMike Urbach   MlirValue value = mlirPythonCapsuleToValue(capsule.ptr());
15403f3d1c90SMike Urbach   if (mlirValueIsNull(value))
15413f3d1c90SMike Urbach     throw py::error_already_set();
15423f3d1c90SMike Urbach   MlirOperation owner;
15433f3d1c90SMike Urbach   if (mlirValueIsAOpResult(value))
15443f3d1c90SMike Urbach     owner = mlirOpResultGetOwner(value);
15453f3d1c90SMike Urbach   if (mlirValueIsABlockArgument(value))
15463f3d1c90SMike Urbach     owner = mlirBlockGetParentOperation(mlirBlockArgumentGetOwner(value));
15473f3d1c90SMike Urbach   if (mlirOperationIsNull(owner))
15483f3d1c90SMike Urbach     throw py::error_already_set();
15493f3d1c90SMike Urbach   MlirContext ctx = mlirOperationGetContext(owner);
15503f3d1c90SMike Urbach   PyOperationRef ownerRef =
15513f3d1c90SMike Urbach       PyOperation::forOperation(PyMlirContext::forContext(ctx), owner);
15523f3d1c90SMike Urbach   return PyValue(ownerRef, value);
15533f3d1c90SMike Urbach }
15543f3d1c90SMike Urbach 
155530d61893SAlex Zinenko //------------------------------------------------------------------------------
155630d61893SAlex Zinenko // PySymbolTable.
155730d61893SAlex Zinenko //------------------------------------------------------------------------------
155830d61893SAlex Zinenko 
155930d61893SAlex Zinenko PySymbolTable::PySymbolTable(PyOperationBase &operation)
156030d61893SAlex Zinenko     : operation(operation.getOperation().getRef()) {
156130d61893SAlex Zinenko   symbolTable = mlirSymbolTableCreate(operation.getOperation().get());
156230d61893SAlex Zinenko   if (mlirSymbolTableIsNull(symbolTable)) {
156330d61893SAlex Zinenko     throw py::cast_error("Operation is not a Symbol Table.");
156430d61893SAlex Zinenko   }
156530d61893SAlex Zinenko }
156630d61893SAlex Zinenko 
156730d61893SAlex Zinenko py::object PySymbolTable::dunderGetItem(const std::string &name) {
156830d61893SAlex Zinenko   operation->checkValid();
156930d61893SAlex Zinenko   MlirOperation symbol = mlirSymbolTableLookup(
157030d61893SAlex Zinenko       symbolTable, mlirStringRefCreate(name.data(), name.length()));
157130d61893SAlex Zinenko   if (mlirOperationIsNull(symbol))
157230d61893SAlex Zinenko     throw py::key_error("Symbol '" + name + "' not in the symbol table.");
157330d61893SAlex Zinenko 
157430d61893SAlex Zinenko   return PyOperation::forOperation(operation->getContext(), symbol,
157530d61893SAlex Zinenko                                    operation.getObject())
157630d61893SAlex Zinenko       ->createOpView();
157730d61893SAlex Zinenko }
157830d61893SAlex Zinenko 
157930d61893SAlex Zinenko void PySymbolTable::erase(PyOperationBase &symbol) {
158030d61893SAlex Zinenko   operation->checkValid();
158130d61893SAlex Zinenko   symbol.getOperation().checkValid();
158230d61893SAlex Zinenko   mlirSymbolTableErase(symbolTable, symbol.getOperation().get());
158330d61893SAlex Zinenko   // The operation is also erased, so we must invalidate it. There may be Python
158430d61893SAlex Zinenko   // references to this operation so we don't want to delete it from the list of
158530d61893SAlex Zinenko   // live operations here.
158630d61893SAlex Zinenko   symbol.getOperation().valid = false;
158730d61893SAlex Zinenko }
158830d61893SAlex Zinenko 
158930d61893SAlex Zinenko void PySymbolTable::dunderDel(const std::string &name) {
159030d61893SAlex Zinenko   py::object operation = dunderGetItem(name);
159130d61893SAlex Zinenko   erase(py::cast<PyOperationBase &>(operation));
159230d61893SAlex Zinenko }
159330d61893SAlex Zinenko 
159430d61893SAlex Zinenko PyAttribute PySymbolTable::insert(PyOperationBase &symbol) {
159530d61893SAlex Zinenko   operation->checkValid();
159630d61893SAlex Zinenko   symbol.getOperation().checkValid();
159730d61893SAlex Zinenko   MlirAttribute symbolAttr = mlirOperationGetAttributeByName(
159830d61893SAlex Zinenko       symbol.getOperation().get(), mlirSymbolTableGetSymbolAttributeName());
159930d61893SAlex Zinenko   if (mlirAttributeIsNull(symbolAttr))
160030d61893SAlex Zinenko     throw py::value_error("Expected operation to have a symbol name.");
160130d61893SAlex Zinenko   return PyAttribute(
160230d61893SAlex Zinenko       symbol.getOperation().getContext(),
160330d61893SAlex Zinenko       mlirSymbolTableInsert(symbolTable, symbol.getOperation().get()));
160430d61893SAlex Zinenko }
160530d61893SAlex Zinenko 
1606bdc31837SStella Laurenzo PyAttribute PySymbolTable::getSymbolName(PyOperationBase &symbol) {
1607bdc31837SStella Laurenzo   // Op must already be a symbol.
1608bdc31837SStella Laurenzo   PyOperation &operation = symbol.getOperation();
1609bdc31837SStella Laurenzo   operation.checkValid();
1610bdc31837SStella Laurenzo   MlirStringRef attrName = mlirSymbolTableGetSymbolAttributeName();
1611bdc31837SStella Laurenzo   MlirAttribute existingNameAttr =
1612bdc31837SStella Laurenzo       mlirOperationGetAttributeByName(operation.get(), attrName);
1613bdc31837SStella Laurenzo   if (mlirAttributeIsNull(existingNameAttr))
1614bdc31837SStella Laurenzo     throw py::value_error("Expected operation to have a symbol name.");
1615bdc31837SStella Laurenzo   return PyAttribute(symbol.getOperation().getContext(), existingNameAttr);
1616bdc31837SStella Laurenzo }
1617bdc31837SStella Laurenzo 
1618bdc31837SStella Laurenzo void PySymbolTable::setSymbolName(PyOperationBase &symbol,
1619bdc31837SStella Laurenzo                                   const std::string &name) {
1620bdc31837SStella Laurenzo   // Op must already be a symbol.
1621bdc31837SStella Laurenzo   PyOperation &operation = symbol.getOperation();
1622bdc31837SStella Laurenzo   operation.checkValid();
1623bdc31837SStella Laurenzo   MlirStringRef attrName = mlirSymbolTableGetSymbolAttributeName();
1624bdc31837SStella Laurenzo   MlirAttribute existingNameAttr =
1625bdc31837SStella Laurenzo       mlirOperationGetAttributeByName(operation.get(), attrName);
1626bdc31837SStella Laurenzo   if (mlirAttributeIsNull(existingNameAttr))
1627bdc31837SStella Laurenzo     throw py::value_error("Expected operation to have a symbol name.");
1628bdc31837SStella Laurenzo   MlirAttribute newNameAttr =
1629bdc31837SStella Laurenzo       mlirStringAttrGet(operation.getContext()->get(), toMlirStringRef(name));
1630bdc31837SStella Laurenzo   mlirOperationSetAttributeByName(operation.get(), attrName, newNameAttr);
1631bdc31837SStella Laurenzo }
1632bdc31837SStella Laurenzo 
1633bdc31837SStella Laurenzo PyAttribute PySymbolTable::getVisibility(PyOperationBase &symbol) {
1634bdc31837SStella Laurenzo   PyOperation &operation = symbol.getOperation();
1635bdc31837SStella Laurenzo   operation.checkValid();
1636bdc31837SStella Laurenzo   MlirStringRef attrName = mlirSymbolTableGetVisibilityAttributeName();
1637bdc31837SStella Laurenzo   MlirAttribute existingVisAttr =
1638bdc31837SStella Laurenzo       mlirOperationGetAttributeByName(operation.get(), attrName);
1639bdc31837SStella Laurenzo   if (mlirAttributeIsNull(existingVisAttr))
1640bdc31837SStella Laurenzo     throw py::value_error("Expected operation to have a symbol visibility.");
1641bdc31837SStella Laurenzo   return PyAttribute(symbol.getOperation().getContext(), existingVisAttr);
1642bdc31837SStella Laurenzo }
1643bdc31837SStella Laurenzo 
1644bdc31837SStella Laurenzo void PySymbolTable::setVisibility(PyOperationBase &symbol,
1645bdc31837SStella Laurenzo                                   const std::string &visibility) {
1646bdc31837SStella Laurenzo   if (visibility != "public" && visibility != "private" &&
1647bdc31837SStella Laurenzo       visibility != "nested")
1648bdc31837SStella Laurenzo     throw py::value_error(
1649bdc31837SStella Laurenzo         "Expected visibility to be 'public', 'private' or 'nested'");
1650bdc31837SStella Laurenzo   PyOperation &operation = symbol.getOperation();
1651bdc31837SStella Laurenzo   operation.checkValid();
1652bdc31837SStella Laurenzo   MlirStringRef attrName = mlirSymbolTableGetVisibilityAttributeName();
1653bdc31837SStella Laurenzo   MlirAttribute existingVisAttr =
1654bdc31837SStella Laurenzo       mlirOperationGetAttributeByName(operation.get(), attrName);
1655bdc31837SStella Laurenzo   if (mlirAttributeIsNull(existingVisAttr))
1656bdc31837SStella Laurenzo     throw py::value_error("Expected operation to have a symbol visibility.");
1657bdc31837SStella Laurenzo   MlirAttribute newVisAttr = mlirStringAttrGet(operation.getContext()->get(),
1658bdc31837SStella Laurenzo                                                toMlirStringRef(visibility));
1659bdc31837SStella Laurenzo   mlirOperationSetAttributeByName(operation.get(), attrName, newVisAttr);
1660bdc31837SStella Laurenzo }
1661bdc31837SStella Laurenzo 
1662bdc31837SStella Laurenzo void PySymbolTable::replaceAllSymbolUses(const std::string &oldSymbol,
1663bdc31837SStella Laurenzo                                          const std::string &newSymbol,
1664bdc31837SStella Laurenzo                                          PyOperationBase &from) {
1665bdc31837SStella Laurenzo   PyOperation &fromOperation = from.getOperation();
1666bdc31837SStella Laurenzo   fromOperation.checkValid();
1667bdc31837SStella Laurenzo   if (mlirLogicalResultIsFailure(mlirSymbolTableReplaceAllSymbolUses(
1668bdc31837SStella Laurenzo           toMlirStringRef(oldSymbol), toMlirStringRef(newSymbol),
1669bdc31837SStella Laurenzo           from.getOperation())))
1670bdc31837SStella Laurenzo 
1671bdc31837SStella Laurenzo     throw py::value_error("Symbol rename failed");
1672bdc31837SStella Laurenzo }
1673bdc31837SStella Laurenzo 
1674bdc31837SStella Laurenzo void PySymbolTable::walkSymbolTables(PyOperationBase &from,
1675bdc31837SStella Laurenzo                                      bool allSymUsesVisible,
1676bdc31837SStella Laurenzo                                      py::object callback) {
1677bdc31837SStella Laurenzo   PyOperation &fromOperation = from.getOperation();
1678bdc31837SStella Laurenzo   fromOperation.checkValid();
1679bdc31837SStella Laurenzo   struct UserData {
1680bdc31837SStella Laurenzo     PyMlirContextRef context;
1681bdc31837SStella Laurenzo     py::object callback;
1682bdc31837SStella Laurenzo     bool gotException;
1683bdc31837SStella Laurenzo     std::string exceptionWhat;
1684bdc31837SStella Laurenzo     py::object exceptionType;
1685bdc31837SStella Laurenzo   };
1686bdc31837SStella Laurenzo   UserData userData{
1687bdc31837SStella Laurenzo       fromOperation.getContext(), std::move(callback), false, {}, {}};
1688bdc31837SStella Laurenzo   mlirSymbolTableWalkSymbolTables(
1689bdc31837SStella Laurenzo       fromOperation.get(), allSymUsesVisible,
1690bdc31837SStella Laurenzo       [](MlirOperation foundOp, bool isVisible, void *calleeUserDataVoid) {
1691bdc31837SStella Laurenzo         UserData *calleeUserData = static_cast<UserData *>(calleeUserDataVoid);
1692bdc31837SStella Laurenzo         auto pyFoundOp =
1693bdc31837SStella Laurenzo             PyOperation::forOperation(calleeUserData->context, foundOp);
1694bdc31837SStella Laurenzo         if (calleeUserData->gotException)
1695bdc31837SStella Laurenzo           return;
1696bdc31837SStella Laurenzo         try {
1697bdc31837SStella Laurenzo           calleeUserData->callback(pyFoundOp.getObject(), isVisible);
1698bdc31837SStella Laurenzo         } catch (py::error_already_set &e) {
1699bdc31837SStella Laurenzo           calleeUserData->gotException = true;
1700bdc31837SStella Laurenzo           calleeUserData->exceptionWhat = e.what();
1701bdc31837SStella Laurenzo           calleeUserData->exceptionType = e.type();
1702bdc31837SStella Laurenzo         }
1703bdc31837SStella Laurenzo       },
1704bdc31837SStella Laurenzo       static_cast<void *>(&userData));
1705bdc31837SStella Laurenzo   if (userData.gotException) {
1706bdc31837SStella Laurenzo     std::string message("Exception raised in callback: ");
1707bdc31837SStella Laurenzo     message.append(userData.exceptionWhat);
1708bdc31837SStella Laurenzo     throw std::runtime_error(std::move(message));
1709bdc31837SStella Laurenzo   }
1710bdc31837SStella Laurenzo }
1711bdc31837SStella Laurenzo 
1712436c6c9cSStella Laurenzo namespace {
1713436c6c9cSStella Laurenzo /// CRTP base class for Python MLIR values that subclass Value and should be
1714436c6c9cSStella Laurenzo /// castable from it. The value hierarchy is one level deep and is not supposed
1715436c6c9cSStella Laurenzo /// to accommodate other levels unless core MLIR changes.
1716436c6c9cSStella Laurenzo template <typename DerivedTy>
1717436c6c9cSStella Laurenzo class PyConcreteValue : public PyValue {
1718436c6c9cSStella Laurenzo public:
1719436c6c9cSStella Laurenzo   // Derived classes must define statics for:
1720436c6c9cSStella Laurenzo   //   IsAFunctionTy isaFunction
1721436c6c9cSStella Laurenzo   //   const char *pyClassName
1722436c6c9cSStella Laurenzo   // and redefine bindDerived.
1723436c6c9cSStella Laurenzo   using ClassTy = py::class_<DerivedTy, PyValue>;
1724436c6c9cSStella Laurenzo   using IsAFunctionTy = bool (*)(MlirValue);
1725436c6c9cSStella Laurenzo 
1726436c6c9cSStella Laurenzo   PyConcreteValue() = default;
1727436c6c9cSStella Laurenzo   PyConcreteValue(PyOperationRef operationRef, MlirValue value)
1728436c6c9cSStella Laurenzo       : PyValue(operationRef, value) {}
1729436c6c9cSStella Laurenzo   PyConcreteValue(PyValue &orig)
1730436c6c9cSStella Laurenzo       : PyConcreteValue(orig.getParentOperation(), castFrom(orig)) {}
1731436c6c9cSStella Laurenzo 
1732436c6c9cSStella Laurenzo   /// Attempts to cast the original value to the derived type and throws on
1733436c6c9cSStella Laurenzo   /// type mismatches.
1734436c6c9cSStella Laurenzo   static MlirValue castFrom(PyValue &orig) {
1735436c6c9cSStella Laurenzo     if (!DerivedTy::isaFunction(orig.get())) {
1736436c6c9cSStella Laurenzo       auto origRepr = py::repr(py::cast(orig)).cast<std::string>();
1737436c6c9cSStella Laurenzo       throw SetPyError(PyExc_ValueError, Twine("Cannot cast value to ") +
1738436c6c9cSStella Laurenzo                                              DerivedTy::pyClassName +
1739436c6c9cSStella Laurenzo                                              " (from " + origRepr + ")");
1740436c6c9cSStella Laurenzo     }
1741436c6c9cSStella Laurenzo     return orig.get();
1742436c6c9cSStella Laurenzo   }
1743436c6c9cSStella Laurenzo 
1744436c6c9cSStella Laurenzo   /// Binds the Python module objects to functions of this class.
1745436c6c9cSStella Laurenzo   static void bind(py::module &m) {
1746f05ff4f7SStella Laurenzo     auto cls = ClassTy(m, DerivedTy::pyClassName, py::module_local());
1747a6e7d024SStella Laurenzo     cls.def(py::init<PyValue &>(), py::keep_alive<0, 1>(), py::arg("value"));
1748a6e7d024SStella Laurenzo     cls.def_static(
1749a6e7d024SStella Laurenzo         "isinstance",
1750a6e7d024SStella Laurenzo         [](PyValue &otherValue) -> bool {
175178f2dae0SAlex Zinenko           return DerivedTy::isaFunction(otherValue);
1752a6e7d024SStella Laurenzo         },
1753a6e7d024SStella Laurenzo         py::arg("other_value"));
1754436c6c9cSStella Laurenzo     DerivedTy::bindDerived(cls);
1755436c6c9cSStella Laurenzo   }
1756436c6c9cSStella Laurenzo 
1757436c6c9cSStella Laurenzo   /// Implemented by derived classes to add methods to the Python subclass.
1758436c6c9cSStella Laurenzo   static void bindDerived(ClassTy &m) {}
1759436c6c9cSStella Laurenzo };
1760436c6c9cSStella Laurenzo 
1761436c6c9cSStella Laurenzo /// Python wrapper for MlirBlockArgument.
1762436c6c9cSStella Laurenzo class PyBlockArgument : public PyConcreteValue<PyBlockArgument> {
1763436c6c9cSStella Laurenzo public:
1764436c6c9cSStella Laurenzo   static constexpr IsAFunctionTy isaFunction = mlirValueIsABlockArgument;
1765436c6c9cSStella Laurenzo   static constexpr const char *pyClassName = "BlockArgument";
1766436c6c9cSStella Laurenzo   using PyConcreteValue::PyConcreteValue;
1767436c6c9cSStella Laurenzo 
1768436c6c9cSStella Laurenzo   static void bindDerived(ClassTy &c) {
1769436c6c9cSStella Laurenzo     c.def_property_readonly("owner", [](PyBlockArgument &self) {
1770436c6c9cSStella Laurenzo       return PyBlock(self.getParentOperation(),
1771436c6c9cSStella Laurenzo                      mlirBlockArgumentGetOwner(self.get()));
1772436c6c9cSStella Laurenzo     });
1773436c6c9cSStella Laurenzo     c.def_property_readonly("arg_number", [](PyBlockArgument &self) {
1774436c6c9cSStella Laurenzo       return mlirBlockArgumentGetArgNumber(self.get());
1775436c6c9cSStella Laurenzo     });
1776a6e7d024SStella Laurenzo     c.def(
1777a6e7d024SStella Laurenzo         "set_type",
1778a6e7d024SStella Laurenzo         [](PyBlockArgument &self, PyType type) {
1779436c6c9cSStella Laurenzo           return mlirBlockArgumentSetType(self.get(), type);
1780a6e7d024SStella Laurenzo         },
1781a6e7d024SStella Laurenzo         py::arg("type"));
1782436c6c9cSStella Laurenzo   }
1783436c6c9cSStella Laurenzo };
1784436c6c9cSStella Laurenzo 
1785436c6c9cSStella Laurenzo /// Python wrapper for MlirOpResult.
1786436c6c9cSStella Laurenzo class PyOpResult : public PyConcreteValue<PyOpResult> {
1787436c6c9cSStella Laurenzo public:
1788436c6c9cSStella Laurenzo   static constexpr IsAFunctionTy isaFunction = mlirValueIsAOpResult;
1789436c6c9cSStella Laurenzo   static constexpr const char *pyClassName = "OpResult";
1790436c6c9cSStella Laurenzo   using PyConcreteValue::PyConcreteValue;
1791436c6c9cSStella Laurenzo 
1792436c6c9cSStella Laurenzo   static void bindDerived(ClassTy &c) {
1793436c6c9cSStella Laurenzo     c.def_property_readonly("owner", [](PyOpResult &self) {
1794436c6c9cSStella Laurenzo       assert(
1795436c6c9cSStella Laurenzo           mlirOperationEqual(self.getParentOperation()->get(),
1796436c6c9cSStella Laurenzo                              mlirOpResultGetOwner(self.get())) &&
1797436c6c9cSStella Laurenzo           "expected the owner of the value in Python to match that in the IR");
17986ff74f96SMike Urbach       return self.getParentOperation().getObject();
1799436c6c9cSStella Laurenzo     });
1800436c6c9cSStella Laurenzo     c.def_property_readonly("result_number", [](PyOpResult &self) {
1801436c6c9cSStella Laurenzo       return mlirOpResultGetResultNumber(self.get());
1802436c6c9cSStella Laurenzo     });
1803436c6c9cSStella Laurenzo   }
1804436c6c9cSStella Laurenzo };
1805436c6c9cSStella Laurenzo 
1806ed9e52f3SAlex Zinenko /// Returns the list of types of the values held by container.
1807ed9e52f3SAlex Zinenko template <typename Container>
1808ed9e52f3SAlex Zinenko static std::vector<PyType> getValueTypes(Container &container,
1809ed9e52f3SAlex Zinenko                                          PyMlirContextRef &context) {
1810ed9e52f3SAlex Zinenko   std::vector<PyType> result;
1811ed9e52f3SAlex Zinenko   result.reserve(container.getNumElements());
1812ed9e52f3SAlex Zinenko   for (int i = 0, e = container.getNumElements(); i < e; ++i) {
1813ed9e52f3SAlex Zinenko     result.push_back(
1814ed9e52f3SAlex Zinenko         PyType(context, mlirValueGetType(container.getElement(i).get())));
1815ed9e52f3SAlex Zinenko   }
1816ed9e52f3SAlex Zinenko   return result;
1817ed9e52f3SAlex Zinenko }
1818ed9e52f3SAlex Zinenko 
1819436c6c9cSStella Laurenzo /// A list of block arguments. Internally, these are stored as consecutive
1820436c6c9cSStella Laurenzo /// elements, random access is cheap. The argument list is associated with the
1821436c6c9cSStella Laurenzo /// operation that contains the block (detached blocks are not allowed in
1822436c6c9cSStella Laurenzo /// Python bindings) and extends its lifetime.
1823afeda4b9SAlex Zinenko class PyBlockArgumentList
1824afeda4b9SAlex Zinenko     : public Sliceable<PyBlockArgumentList, PyBlockArgument> {
1825436c6c9cSStella Laurenzo public:
1826afeda4b9SAlex Zinenko   static constexpr const char *pyClassName = "BlockArgumentList";
1827436c6c9cSStella Laurenzo 
1828afeda4b9SAlex Zinenko   PyBlockArgumentList(PyOperationRef operation, MlirBlock block,
1829afeda4b9SAlex Zinenko                       intptr_t startIndex = 0, intptr_t length = -1,
1830afeda4b9SAlex Zinenko                       intptr_t step = 1)
1831afeda4b9SAlex Zinenko       : Sliceable(startIndex,
1832afeda4b9SAlex Zinenko                   length == -1 ? mlirBlockGetNumArguments(block) : length,
1833afeda4b9SAlex Zinenko                   step),
1834afeda4b9SAlex Zinenko         operation(std::move(operation)), block(block) {}
1835afeda4b9SAlex Zinenko 
1836afeda4b9SAlex Zinenko   /// Returns the number of arguments in the list.
1837afeda4b9SAlex Zinenko   intptr_t getNumElements() {
1838436c6c9cSStella Laurenzo     operation->checkValid();
1839436c6c9cSStella Laurenzo     return mlirBlockGetNumArguments(block);
1840436c6c9cSStella Laurenzo   }
1841436c6c9cSStella Laurenzo 
1842afeda4b9SAlex Zinenko   /// Returns `pos`-the element in the list. Asserts on out-of-bounds.
1843afeda4b9SAlex Zinenko   PyBlockArgument getElement(intptr_t pos) {
1844afeda4b9SAlex Zinenko     MlirValue argument = mlirBlockGetArgument(block, pos);
1845afeda4b9SAlex Zinenko     return PyBlockArgument(operation, argument);
1846436c6c9cSStella Laurenzo   }
1847436c6c9cSStella Laurenzo 
1848afeda4b9SAlex Zinenko   /// Returns a sublist of this list.
1849afeda4b9SAlex Zinenko   PyBlockArgumentList slice(intptr_t startIndex, intptr_t length,
1850afeda4b9SAlex Zinenko                             intptr_t step) {
1851afeda4b9SAlex Zinenko     return PyBlockArgumentList(operation, block, startIndex, length, step);
1852436c6c9cSStella Laurenzo   }
1853436c6c9cSStella Laurenzo 
1854ed9e52f3SAlex Zinenko   static void bindDerived(ClassTy &c) {
1855ed9e52f3SAlex Zinenko     c.def_property_readonly("types", [](PyBlockArgumentList &self) {
1856ed9e52f3SAlex Zinenko       return getValueTypes(self, self.operation->getContext());
1857ed9e52f3SAlex Zinenko     });
1858ed9e52f3SAlex Zinenko   }
1859ed9e52f3SAlex Zinenko 
1860436c6c9cSStella Laurenzo private:
1861436c6c9cSStella Laurenzo   PyOperationRef operation;
1862436c6c9cSStella Laurenzo   MlirBlock block;
1863436c6c9cSStella Laurenzo };
1864436c6c9cSStella Laurenzo 
1865436c6c9cSStella Laurenzo /// A list of operation operands. Internally, these are stored as consecutive
1866436c6c9cSStella Laurenzo /// elements, random access is cheap. The result list is associated with the
1867436c6c9cSStella Laurenzo /// operation whose results these are, and extends the lifetime of this
1868436c6c9cSStella Laurenzo /// operation.
1869436c6c9cSStella Laurenzo class PyOpOperandList : public Sliceable<PyOpOperandList, PyValue> {
1870436c6c9cSStella Laurenzo public:
1871436c6c9cSStella Laurenzo   static constexpr const char *pyClassName = "OpOperandList";
1872436c6c9cSStella Laurenzo 
1873436c6c9cSStella Laurenzo   PyOpOperandList(PyOperationRef operation, intptr_t startIndex = 0,
1874436c6c9cSStella Laurenzo                   intptr_t length = -1, intptr_t step = 1)
1875436c6c9cSStella Laurenzo       : Sliceable(startIndex,
1876436c6c9cSStella Laurenzo                   length == -1 ? mlirOperationGetNumOperands(operation->get())
1877436c6c9cSStella Laurenzo                                : length,
1878436c6c9cSStella Laurenzo                   step),
1879436c6c9cSStella Laurenzo         operation(operation) {}
1880436c6c9cSStella Laurenzo 
1881436c6c9cSStella Laurenzo   intptr_t getNumElements() {
1882436c6c9cSStella Laurenzo     operation->checkValid();
1883436c6c9cSStella Laurenzo     return mlirOperationGetNumOperands(operation->get());
1884436c6c9cSStella Laurenzo   }
1885436c6c9cSStella Laurenzo 
1886436c6c9cSStella Laurenzo   PyValue getElement(intptr_t pos) {
18875664c5e2SJohn Demme     MlirValue operand = mlirOperationGetOperand(operation->get(), pos);
18885664c5e2SJohn Demme     MlirOperation owner;
18895664c5e2SJohn Demme     if (mlirValueIsAOpResult(operand))
18905664c5e2SJohn Demme       owner = mlirOpResultGetOwner(operand);
18915664c5e2SJohn Demme     else if (mlirValueIsABlockArgument(operand))
18925664c5e2SJohn Demme       owner = mlirBlockGetParentOperation(mlirBlockArgumentGetOwner(operand));
18935664c5e2SJohn Demme     else
18945664c5e2SJohn Demme       assert(false && "Value must be an block arg or op result.");
18955664c5e2SJohn Demme     PyOperationRef pyOwner =
18965664c5e2SJohn Demme         PyOperation::forOperation(operation->getContext(), owner);
18975664c5e2SJohn Demme     return PyValue(pyOwner, operand);
1898436c6c9cSStella Laurenzo   }
1899436c6c9cSStella Laurenzo 
1900436c6c9cSStella Laurenzo   PyOpOperandList slice(intptr_t startIndex, intptr_t length, intptr_t step) {
1901436c6c9cSStella Laurenzo     return PyOpOperandList(operation, startIndex, length, step);
1902436c6c9cSStella Laurenzo   }
1903436c6c9cSStella Laurenzo 
190463d16d06SMike Urbach   void dunderSetItem(intptr_t index, PyValue value) {
190563d16d06SMike Urbach     index = wrapIndex(index);
190663d16d06SMike Urbach     mlirOperationSetOperand(operation->get(), index, value.get());
190763d16d06SMike Urbach   }
190863d16d06SMike Urbach 
190963d16d06SMike Urbach   static void bindDerived(ClassTy &c) {
191063d16d06SMike Urbach     c.def("__setitem__", &PyOpOperandList::dunderSetItem);
191163d16d06SMike Urbach   }
191263d16d06SMike Urbach 
1913436c6c9cSStella Laurenzo private:
1914436c6c9cSStella Laurenzo   PyOperationRef operation;
1915436c6c9cSStella Laurenzo };
1916436c6c9cSStella Laurenzo 
1917436c6c9cSStella Laurenzo /// A list of operation results. Internally, these are stored as consecutive
1918436c6c9cSStella Laurenzo /// elements, random access is cheap. The result list is associated with the
1919436c6c9cSStella Laurenzo /// operation whose results these are, and extends the lifetime of this
1920436c6c9cSStella Laurenzo /// operation.
1921436c6c9cSStella Laurenzo class PyOpResultList : public Sliceable<PyOpResultList, PyOpResult> {
1922436c6c9cSStella Laurenzo public:
1923436c6c9cSStella Laurenzo   static constexpr const char *pyClassName = "OpResultList";
1924436c6c9cSStella Laurenzo 
1925436c6c9cSStella Laurenzo   PyOpResultList(PyOperationRef operation, intptr_t startIndex = 0,
1926436c6c9cSStella Laurenzo                  intptr_t length = -1, intptr_t step = 1)
1927436c6c9cSStella Laurenzo       : Sliceable(startIndex,
1928436c6c9cSStella Laurenzo                   length == -1 ? mlirOperationGetNumResults(operation->get())
1929436c6c9cSStella Laurenzo                                : length,
1930436c6c9cSStella Laurenzo                   step),
1931436c6c9cSStella Laurenzo         operation(operation) {}
1932436c6c9cSStella Laurenzo 
1933436c6c9cSStella Laurenzo   intptr_t getNumElements() {
1934436c6c9cSStella Laurenzo     operation->checkValid();
1935436c6c9cSStella Laurenzo     return mlirOperationGetNumResults(operation->get());
1936436c6c9cSStella Laurenzo   }
1937436c6c9cSStella Laurenzo 
1938436c6c9cSStella Laurenzo   PyOpResult getElement(intptr_t index) {
1939436c6c9cSStella Laurenzo     PyValue value(operation, mlirOperationGetResult(operation->get(), index));
1940436c6c9cSStella Laurenzo     return PyOpResult(value);
1941436c6c9cSStella Laurenzo   }
1942436c6c9cSStella Laurenzo 
1943436c6c9cSStella Laurenzo   PyOpResultList slice(intptr_t startIndex, intptr_t length, intptr_t step) {
1944436c6c9cSStella Laurenzo     return PyOpResultList(operation, startIndex, length, step);
1945436c6c9cSStella Laurenzo   }
1946436c6c9cSStella Laurenzo 
1947ed9e52f3SAlex Zinenko   static void bindDerived(ClassTy &c) {
1948ed9e52f3SAlex Zinenko     c.def_property_readonly("types", [](PyOpResultList &self) {
1949ed9e52f3SAlex Zinenko       return getValueTypes(self, self.operation->getContext());
1950ed9e52f3SAlex Zinenko     });
1951ed9e52f3SAlex Zinenko   }
1952ed9e52f3SAlex Zinenko 
1953436c6c9cSStella Laurenzo private:
1954436c6c9cSStella Laurenzo   PyOperationRef operation;
1955436c6c9cSStella Laurenzo };
1956436c6c9cSStella Laurenzo 
1957436c6c9cSStella Laurenzo /// A list of operation attributes. Can be indexed by name, producing
1958436c6c9cSStella Laurenzo /// attributes, or by index, producing named attributes.
1959436c6c9cSStella Laurenzo class PyOpAttributeMap {
1960436c6c9cSStella Laurenzo public:
19611fc096afSMehdi Amini   PyOpAttributeMap(PyOperationRef operation)
19621fc096afSMehdi Amini       : operation(std::move(operation)) {}
1963436c6c9cSStella Laurenzo 
1964436c6c9cSStella Laurenzo   PyAttribute dunderGetItemNamed(const std::string &name) {
1965436c6c9cSStella Laurenzo     MlirAttribute attr = mlirOperationGetAttributeByName(operation->get(),
1966436c6c9cSStella Laurenzo                                                          toMlirStringRef(name));
1967436c6c9cSStella Laurenzo     if (mlirAttributeIsNull(attr)) {
1968436c6c9cSStella Laurenzo       throw SetPyError(PyExc_KeyError,
1969436c6c9cSStella Laurenzo                        "attempt to access a non-existent attribute");
1970436c6c9cSStella Laurenzo     }
1971436c6c9cSStella Laurenzo     return PyAttribute(operation->getContext(), attr);
1972436c6c9cSStella Laurenzo   }
1973436c6c9cSStella Laurenzo 
1974436c6c9cSStella Laurenzo   PyNamedAttribute dunderGetItemIndexed(intptr_t index) {
1975436c6c9cSStella Laurenzo     if (index < 0 || index >= dunderLen()) {
1976436c6c9cSStella Laurenzo       throw SetPyError(PyExc_IndexError,
1977436c6c9cSStella Laurenzo                        "attempt to access out of bounds attribute");
1978436c6c9cSStella Laurenzo     }
1979436c6c9cSStella Laurenzo     MlirNamedAttribute namedAttr =
1980436c6c9cSStella Laurenzo         mlirOperationGetAttribute(operation->get(), index);
1981436c6c9cSStella Laurenzo     return PyNamedAttribute(
1982436c6c9cSStella Laurenzo         namedAttr.attribute,
1983120591e1SRiver Riddle         std::string(mlirIdentifierStr(namedAttr.name).data,
1984120591e1SRiver Riddle                     mlirIdentifierStr(namedAttr.name).length));
1985436c6c9cSStella Laurenzo   }
1986436c6c9cSStella Laurenzo 
19871fc096afSMehdi Amini   void dunderSetItem(const std::string &name, const PyAttribute &attr) {
1988436c6c9cSStella Laurenzo     mlirOperationSetAttributeByName(operation->get(), toMlirStringRef(name),
1989436c6c9cSStella Laurenzo                                     attr);
1990436c6c9cSStella Laurenzo   }
1991436c6c9cSStella Laurenzo 
1992436c6c9cSStella Laurenzo   void dunderDelItem(const std::string &name) {
1993436c6c9cSStella Laurenzo     int removed = mlirOperationRemoveAttributeByName(operation->get(),
1994436c6c9cSStella Laurenzo                                                      toMlirStringRef(name));
1995436c6c9cSStella Laurenzo     if (!removed)
1996436c6c9cSStella Laurenzo       throw SetPyError(PyExc_KeyError,
1997436c6c9cSStella Laurenzo                        "attempt to delete a non-existent attribute");
1998436c6c9cSStella Laurenzo   }
1999436c6c9cSStella Laurenzo 
2000436c6c9cSStella Laurenzo   intptr_t dunderLen() {
2001436c6c9cSStella Laurenzo     return mlirOperationGetNumAttributes(operation->get());
2002436c6c9cSStella Laurenzo   }
2003436c6c9cSStella Laurenzo 
2004436c6c9cSStella Laurenzo   bool dunderContains(const std::string &name) {
2005436c6c9cSStella Laurenzo     return !mlirAttributeIsNull(mlirOperationGetAttributeByName(
2006436c6c9cSStella Laurenzo         operation->get(), toMlirStringRef(name)));
2007436c6c9cSStella Laurenzo   }
2008436c6c9cSStella Laurenzo 
2009436c6c9cSStella Laurenzo   static void bind(py::module &m) {
2010f05ff4f7SStella Laurenzo     py::class_<PyOpAttributeMap>(m, "OpAttributeMap", py::module_local())
2011436c6c9cSStella Laurenzo         .def("__contains__", &PyOpAttributeMap::dunderContains)
2012436c6c9cSStella Laurenzo         .def("__len__", &PyOpAttributeMap::dunderLen)
2013436c6c9cSStella Laurenzo         .def("__getitem__", &PyOpAttributeMap::dunderGetItemNamed)
2014436c6c9cSStella Laurenzo         .def("__getitem__", &PyOpAttributeMap::dunderGetItemIndexed)
2015436c6c9cSStella Laurenzo         .def("__setitem__", &PyOpAttributeMap::dunderSetItem)
2016436c6c9cSStella Laurenzo         .def("__delitem__", &PyOpAttributeMap::dunderDelItem);
2017436c6c9cSStella Laurenzo   }
2018436c6c9cSStella Laurenzo 
2019436c6c9cSStella Laurenzo private:
2020436c6c9cSStella Laurenzo   PyOperationRef operation;
2021436c6c9cSStella Laurenzo };
2022436c6c9cSStella Laurenzo 
2023be0a7e9fSMehdi Amini } // namespace
2024436c6c9cSStella Laurenzo 
2025436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
2026436c6c9cSStella Laurenzo // Populates the core exports of the 'ir' submodule.
2027436c6c9cSStella Laurenzo //------------------------------------------------------------------------------
2028436c6c9cSStella Laurenzo 
2029436c6c9cSStella Laurenzo void mlir::python::populateIRCore(py::module &m) {
2030436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
20314acd8457SAlex Zinenko   // Mapping of MlirContext.
2032436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2033f05ff4f7SStella Laurenzo   py::class_<PyMlirContext>(m, "Context", py::module_local())
2034436c6c9cSStella Laurenzo       .def(py::init<>(&PyMlirContext::createNewContextForInit))
2035436c6c9cSStella Laurenzo       .def_static("_get_live_count", &PyMlirContext::getLiveCount)
2036436c6c9cSStella Laurenzo       .def("_get_context_again",
2037436c6c9cSStella Laurenzo            [](PyMlirContext &self) {
2038436c6c9cSStella Laurenzo              PyMlirContextRef ref = PyMlirContext::forContext(self.get());
2039436c6c9cSStella Laurenzo              return ref.releaseObject();
2040436c6c9cSStella Laurenzo            })
2041436c6c9cSStella Laurenzo       .def("_get_live_operation_count", &PyMlirContext::getLiveOperationCount)
2042436c6c9cSStella Laurenzo       .def("_get_live_module_count", &PyMlirContext::getLiveModuleCount)
2043436c6c9cSStella Laurenzo       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
2044436c6c9cSStella Laurenzo                              &PyMlirContext::getCapsule)
2045436c6c9cSStella Laurenzo       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyMlirContext::createFromCapsule)
2046436c6c9cSStella Laurenzo       .def("__enter__", &PyMlirContext::contextEnter)
2047436c6c9cSStella Laurenzo       .def("__exit__", &PyMlirContext::contextExit)
2048436c6c9cSStella Laurenzo       .def_property_readonly_static(
2049436c6c9cSStella Laurenzo           "current",
2050436c6c9cSStella Laurenzo           [](py::object & /*class*/) {
2051436c6c9cSStella Laurenzo             auto *context = PyThreadContextEntry::getDefaultContext();
2052436c6c9cSStella Laurenzo             if (!context)
2053436c6c9cSStella Laurenzo               throw SetPyError(PyExc_ValueError, "No current Context");
2054436c6c9cSStella Laurenzo             return context;
2055436c6c9cSStella Laurenzo           },
2056436c6c9cSStella Laurenzo           "Gets the Context bound to the current thread or raises ValueError")
2057436c6c9cSStella Laurenzo       .def_property_readonly(
2058436c6c9cSStella Laurenzo           "dialects",
2059436c6c9cSStella Laurenzo           [](PyMlirContext &self) { return PyDialects(self.getRef()); },
2060436c6c9cSStella Laurenzo           "Gets a container for accessing dialects by name")
2061436c6c9cSStella Laurenzo       .def_property_readonly(
2062436c6c9cSStella Laurenzo           "d", [](PyMlirContext &self) { return PyDialects(self.getRef()); },
2063436c6c9cSStella Laurenzo           "Alias for 'dialect'")
2064436c6c9cSStella Laurenzo       .def(
2065436c6c9cSStella Laurenzo           "get_dialect_descriptor",
2066436c6c9cSStella Laurenzo           [=](PyMlirContext &self, std::string &name) {
2067436c6c9cSStella Laurenzo             MlirDialect dialect = mlirContextGetOrLoadDialect(
2068436c6c9cSStella Laurenzo                 self.get(), {name.data(), name.size()});
2069436c6c9cSStella Laurenzo             if (mlirDialectIsNull(dialect)) {
2070436c6c9cSStella Laurenzo               throw SetPyError(PyExc_ValueError,
2071436c6c9cSStella Laurenzo                                Twine("Dialect '") + name + "' not found");
2072436c6c9cSStella Laurenzo             }
2073436c6c9cSStella Laurenzo             return PyDialectDescriptor(self.getRef(), dialect);
2074436c6c9cSStella Laurenzo           },
2075a6e7d024SStella Laurenzo           py::arg("dialect_name"),
2076436c6c9cSStella Laurenzo           "Gets or loads a dialect by name, returning its descriptor object")
2077436c6c9cSStella Laurenzo       .def_property(
2078436c6c9cSStella Laurenzo           "allow_unregistered_dialects",
2079436c6c9cSStella Laurenzo           [](PyMlirContext &self) -> bool {
2080436c6c9cSStella Laurenzo             return mlirContextGetAllowUnregisteredDialects(self.get());
2081436c6c9cSStella Laurenzo           },
2082436c6c9cSStella Laurenzo           [](PyMlirContext &self, bool value) {
2083436c6c9cSStella Laurenzo             mlirContextSetAllowUnregisteredDialects(self.get(), value);
20849a9214faSStella Laurenzo           })
2085a6e7d024SStella Laurenzo       .def(
2086a6e7d024SStella Laurenzo           "enable_multithreading",
2087caa159f0SNicolas Vasilache           [](PyMlirContext &self, bool enable) {
2088caa159f0SNicolas Vasilache             mlirContextEnableMultithreading(self.get(), enable);
2089a6e7d024SStella Laurenzo           },
2090a6e7d024SStella Laurenzo           py::arg("enable"))
2091a6e7d024SStella Laurenzo       .def(
2092a6e7d024SStella Laurenzo           "is_registered_operation",
20939a9214faSStella Laurenzo           [](PyMlirContext &self, std::string &name) {
20949a9214faSStella Laurenzo             return mlirContextIsRegisteredOperation(
20959a9214faSStella Laurenzo                 self.get(), MlirStringRef{name.data(), name.size()});
2096a6e7d024SStella Laurenzo           },
2097a6e7d024SStella Laurenzo           py::arg("operation_name"));
2098436c6c9cSStella Laurenzo 
2099436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2100436c6c9cSStella Laurenzo   // Mapping of PyDialectDescriptor
2101436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2102f05ff4f7SStella Laurenzo   py::class_<PyDialectDescriptor>(m, "DialectDescriptor", py::module_local())
2103436c6c9cSStella Laurenzo       .def_property_readonly("namespace",
2104436c6c9cSStella Laurenzo                              [](PyDialectDescriptor &self) {
2105436c6c9cSStella Laurenzo                                MlirStringRef ns =
2106436c6c9cSStella Laurenzo                                    mlirDialectGetNamespace(self.get());
2107436c6c9cSStella Laurenzo                                return py::str(ns.data, ns.length);
2108436c6c9cSStella Laurenzo                              })
2109436c6c9cSStella Laurenzo       .def("__repr__", [](PyDialectDescriptor &self) {
2110436c6c9cSStella Laurenzo         MlirStringRef ns = mlirDialectGetNamespace(self.get());
2111436c6c9cSStella Laurenzo         std::string repr("<DialectDescriptor ");
2112436c6c9cSStella Laurenzo         repr.append(ns.data, ns.length);
2113436c6c9cSStella Laurenzo         repr.append(">");
2114436c6c9cSStella Laurenzo         return repr;
2115436c6c9cSStella Laurenzo       });
2116436c6c9cSStella Laurenzo 
2117436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2118436c6c9cSStella Laurenzo   // Mapping of PyDialects
2119436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2120f05ff4f7SStella Laurenzo   py::class_<PyDialects>(m, "Dialects", py::module_local())
2121436c6c9cSStella Laurenzo       .def("__getitem__",
2122436c6c9cSStella Laurenzo            [=](PyDialects &self, std::string keyName) {
2123436c6c9cSStella Laurenzo              MlirDialect dialect =
2124436c6c9cSStella Laurenzo                  self.getDialectForKey(keyName, /*attrError=*/false);
2125436c6c9cSStella Laurenzo              py::object descriptor =
2126436c6c9cSStella Laurenzo                  py::cast(PyDialectDescriptor{self.getContext(), dialect});
2127436c6c9cSStella Laurenzo              return createCustomDialectWrapper(keyName, std::move(descriptor));
2128436c6c9cSStella Laurenzo            })
2129436c6c9cSStella Laurenzo       .def("__getattr__", [=](PyDialects &self, std::string attrName) {
2130436c6c9cSStella Laurenzo         MlirDialect dialect =
2131436c6c9cSStella Laurenzo             self.getDialectForKey(attrName, /*attrError=*/true);
2132436c6c9cSStella Laurenzo         py::object descriptor =
2133436c6c9cSStella Laurenzo             py::cast(PyDialectDescriptor{self.getContext(), dialect});
2134436c6c9cSStella Laurenzo         return createCustomDialectWrapper(attrName, std::move(descriptor));
2135436c6c9cSStella Laurenzo       });
2136436c6c9cSStella Laurenzo 
2137436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2138436c6c9cSStella Laurenzo   // Mapping of PyDialect
2139436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2140f05ff4f7SStella Laurenzo   py::class_<PyDialect>(m, "Dialect", py::module_local())
2141a6e7d024SStella Laurenzo       .def(py::init<py::object>(), py::arg("descriptor"))
2142436c6c9cSStella Laurenzo       .def_property_readonly(
2143436c6c9cSStella Laurenzo           "descriptor", [](PyDialect &self) { return self.getDescriptor(); })
2144436c6c9cSStella Laurenzo       .def("__repr__", [](py::object self) {
2145436c6c9cSStella Laurenzo         auto clazz = self.attr("__class__");
2146436c6c9cSStella Laurenzo         return py::str("<Dialect ") +
2147436c6c9cSStella Laurenzo                self.attr("descriptor").attr("namespace") + py::str(" (class ") +
2148436c6c9cSStella Laurenzo                clazz.attr("__module__") + py::str(".") +
2149436c6c9cSStella Laurenzo                clazz.attr("__name__") + py::str(")>");
2150436c6c9cSStella Laurenzo       });
2151436c6c9cSStella Laurenzo 
2152436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2153436c6c9cSStella Laurenzo   // Mapping of Location
2154436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2155f05ff4f7SStella Laurenzo   py::class_<PyLocation>(m, "Location", py::module_local())
2156436c6c9cSStella Laurenzo       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyLocation::getCapsule)
2157436c6c9cSStella Laurenzo       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyLocation::createFromCapsule)
2158436c6c9cSStella Laurenzo       .def("__enter__", &PyLocation::contextEnter)
2159436c6c9cSStella Laurenzo       .def("__exit__", &PyLocation::contextExit)
2160436c6c9cSStella Laurenzo       .def("__eq__",
2161436c6c9cSStella Laurenzo            [](PyLocation &self, PyLocation &other) -> bool {
2162436c6c9cSStella Laurenzo              return mlirLocationEqual(self, other);
2163436c6c9cSStella Laurenzo            })
2164436c6c9cSStella Laurenzo       .def("__eq__", [](PyLocation &self, py::object other) { return false; })
2165436c6c9cSStella Laurenzo       .def_property_readonly_static(
2166436c6c9cSStella Laurenzo           "current",
2167436c6c9cSStella Laurenzo           [](py::object & /*class*/) {
2168436c6c9cSStella Laurenzo             auto *loc = PyThreadContextEntry::getDefaultLocation();
2169436c6c9cSStella Laurenzo             if (!loc)
2170436c6c9cSStella Laurenzo               throw SetPyError(PyExc_ValueError, "No current Location");
2171436c6c9cSStella Laurenzo             return loc;
2172436c6c9cSStella Laurenzo           },
2173436c6c9cSStella Laurenzo           "Gets the Location bound to the current thread or raises ValueError")
2174436c6c9cSStella Laurenzo       .def_static(
2175436c6c9cSStella Laurenzo           "unknown",
2176436c6c9cSStella Laurenzo           [](DefaultingPyMlirContext context) {
2177436c6c9cSStella Laurenzo             return PyLocation(context->getRef(),
2178436c6c9cSStella Laurenzo                               mlirLocationUnknownGet(context->get()));
2179436c6c9cSStella Laurenzo           },
2180436c6c9cSStella Laurenzo           py::arg("context") = py::none(),
2181436c6c9cSStella Laurenzo           "Gets a Location representing an unknown location")
2182436c6c9cSStella Laurenzo       .def_static(
2183e67cbbefSJacques Pienaar           "callsite",
2184e67cbbefSJacques Pienaar           [](PyLocation callee, const std::vector<PyLocation> &frames,
2185e67cbbefSJacques Pienaar              DefaultingPyMlirContext context) {
2186e67cbbefSJacques Pienaar             if (frames.empty())
2187e67cbbefSJacques Pienaar               throw py::value_error("No caller frames provided");
2188e67cbbefSJacques Pienaar             MlirLocation caller = frames.back().get();
2189e2f16be5SMehdi Amini             for (const PyLocation &frame :
2190e67cbbefSJacques Pienaar                  llvm::reverse(llvm::makeArrayRef(frames).drop_back()))
2191e67cbbefSJacques Pienaar               caller = mlirLocationCallSiteGet(frame.get(), caller);
2192e67cbbefSJacques Pienaar             return PyLocation(context->getRef(),
2193e67cbbefSJacques Pienaar                               mlirLocationCallSiteGet(callee.get(), caller));
2194e67cbbefSJacques Pienaar           },
2195e67cbbefSJacques Pienaar           py::arg("callee"), py::arg("frames"), py::arg("context") = py::none(),
2196e67cbbefSJacques Pienaar           kContextGetCallSiteLocationDocstring)
2197e67cbbefSJacques Pienaar       .def_static(
2198436c6c9cSStella Laurenzo           "file",
2199436c6c9cSStella Laurenzo           [](std::string filename, int line, int col,
2200436c6c9cSStella Laurenzo              DefaultingPyMlirContext context) {
2201436c6c9cSStella Laurenzo             return PyLocation(
2202436c6c9cSStella Laurenzo                 context->getRef(),
2203436c6c9cSStella Laurenzo                 mlirLocationFileLineColGet(
2204436c6c9cSStella Laurenzo                     context->get(), toMlirStringRef(filename), line, col));
2205436c6c9cSStella Laurenzo           },
2206436c6c9cSStella Laurenzo           py::arg("filename"), py::arg("line"), py::arg("col"),
2207436c6c9cSStella Laurenzo           py::arg("context") = py::none(), kContextGetFileLocationDocstring)
220804d76d36SJacques Pienaar       .def_static(
22091ab3efacSJacques Pienaar           "fused",
22101ab3efacSJacques Pienaar           [](const std::vector<PyLocation> &pyLocations, llvm::Optional<PyAttribute> metadata,
22111ab3efacSJacques Pienaar              DefaultingPyMlirContext context) {
22121ab3efacSJacques Pienaar             if (pyLocations.empty())
22131ab3efacSJacques Pienaar               throw py::value_error("No locations provided");
22141ab3efacSJacques Pienaar             llvm::SmallVector<MlirLocation, 4> locations;
22151ab3efacSJacques Pienaar             locations.reserve(pyLocations.size());
22161ab3efacSJacques Pienaar             for (auto &pyLocation : pyLocations)
22171ab3efacSJacques Pienaar               locations.push_back(pyLocation.get());
22181ab3efacSJacques Pienaar             MlirLocation location = mlirLocationFusedGet(
22191ab3efacSJacques Pienaar                 context->get(), locations.size(), locations.data(),
22201ab3efacSJacques Pienaar                 metadata ? metadata->get() : MlirAttribute{0});
22211ab3efacSJacques Pienaar             return PyLocation(context->getRef(), location);
22221ab3efacSJacques Pienaar           },
22231ab3efacSJacques Pienaar           py::arg("locations"), py::arg("metadata") = py::none(),
22241ab3efacSJacques Pienaar           py::arg("context") = py::none(), kContextGetFusedLocationDocstring)
22251ab3efacSJacques Pienaar       .def_static(
222604d76d36SJacques Pienaar           "name",
222704d76d36SJacques Pienaar           [](std::string name, llvm::Optional<PyLocation> childLoc,
222804d76d36SJacques Pienaar              DefaultingPyMlirContext context) {
222904d76d36SJacques Pienaar             return PyLocation(
223004d76d36SJacques Pienaar                 context->getRef(),
223104d76d36SJacques Pienaar                 mlirLocationNameGet(
223204d76d36SJacques Pienaar                     context->get(), toMlirStringRef(name),
223304d76d36SJacques Pienaar                     childLoc ? childLoc->get()
223404d76d36SJacques Pienaar                              : mlirLocationUnknownGet(context->get())));
223504d76d36SJacques Pienaar           },
223604d76d36SJacques Pienaar           py::arg("name"), py::arg("childLoc") = py::none(),
223704d76d36SJacques Pienaar           py::arg("context") = py::none(), kContextGetNameLocationDocString)
2238436c6c9cSStella Laurenzo       .def_property_readonly(
2239436c6c9cSStella Laurenzo           "context",
2240436c6c9cSStella Laurenzo           [](PyLocation &self) { return self.getContext().getObject(); },
2241436c6c9cSStella Laurenzo           "Context that owns the Location")
2242436c6c9cSStella Laurenzo       .def("__repr__", [](PyLocation &self) {
2243436c6c9cSStella Laurenzo         PyPrintAccumulator printAccum;
2244436c6c9cSStella Laurenzo         mlirLocationPrint(self, printAccum.getCallback(),
2245436c6c9cSStella Laurenzo                           printAccum.getUserData());
2246436c6c9cSStella Laurenzo         return printAccum.join();
2247436c6c9cSStella Laurenzo       });
2248436c6c9cSStella Laurenzo 
2249436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2250436c6c9cSStella Laurenzo   // Mapping of Module
2251436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2252f05ff4f7SStella Laurenzo   py::class_<PyModule>(m, "Module", py::module_local())
2253436c6c9cSStella Laurenzo       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyModule::getCapsule)
2254436c6c9cSStella Laurenzo       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyModule::createFromCapsule)
2255436c6c9cSStella Laurenzo       .def_static(
2256436c6c9cSStella Laurenzo           "parse",
2257436c6c9cSStella Laurenzo           [](const std::string moduleAsm, DefaultingPyMlirContext context) {
2258436c6c9cSStella Laurenzo             MlirModule module = mlirModuleCreateParse(
2259436c6c9cSStella Laurenzo                 context->get(), toMlirStringRef(moduleAsm));
2260436c6c9cSStella Laurenzo             // TODO: Rework error reporting once diagnostic engine is exposed
2261436c6c9cSStella Laurenzo             // in C API.
2262436c6c9cSStella Laurenzo             if (mlirModuleIsNull(module)) {
2263436c6c9cSStella Laurenzo               throw SetPyError(
2264436c6c9cSStella Laurenzo                   PyExc_ValueError,
2265436c6c9cSStella Laurenzo                   "Unable to parse module assembly (see diagnostics)");
2266436c6c9cSStella Laurenzo             }
2267436c6c9cSStella Laurenzo             return PyModule::forModule(module).releaseObject();
2268436c6c9cSStella Laurenzo           },
2269436c6c9cSStella Laurenzo           py::arg("asm"), py::arg("context") = py::none(),
2270436c6c9cSStella Laurenzo           kModuleParseDocstring)
2271436c6c9cSStella Laurenzo       .def_static(
2272436c6c9cSStella Laurenzo           "create",
2273436c6c9cSStella Laurenzo           [](DefaultingPyLocation loc) {
2274436c6c9cSStella Laurenzo             MlirModule module = mlirModuleCreateEmpty(loc);
2275436c6c9cSStella Laurenzo             return PyModule::forModule(module).releaseObject();
2276436c6c9cSStella Laurenzo           },
2277436c6c9cSStella Laurenzo           py::arg("loc") = py::none(), "Creates an empty module")
2278436c6c9cSStella Laurenzo       .def_property_readonly(
2279436c6c9cSStella Laurenzo           "context",
2280436c6c9cSStella Laurenzo           [](PyModule &self) { return self.getContext().getObject(); },
2281436c6c9cSStella Laurenzo           "Context that created the Module")
2282436c6c9cSStella Laurenzo       .def_property_readonly(
2283436c6c9cSStella Laurenzo           "operation",
2284436c6c9cSStella Laurenzo           [](PyModule &self) {
2285436c6c9cSStella Laurenzo             return PyOperation::forOperation(self.getContext(),
2286436c6c9cSStella Laurenzo                                              mlirModuleGetOperation(self.get()),
2287436c6c9cSStella Laurenzo                                              self.getRef().releaseObject())
2288436c6c9cSStella Laurenzo                 .releaseObject();
2289436c6c9cSStella Laurenzo           },
2290436c6c9cSStella Laurenzo           "Accesses the module as an operation")
2291436c6c9cSStella Laurenzo       .def_property_readonly(
2292436c6c9cSStella Laurenzo           "body",
2293436c6c9cSStella Laurenzo           [](PyModule &self) {
229402b6fb21SMehdi Amini             PyOperationRef moduleOp = PyOperation::forOperation(
2295436c6c9cSStella Laurenzo                 self.getContext(), mlirModuleGetOperation(self.get()),
2296436c6c9cSStella Laurenzo                 self.getRef().releaseObject());
229702b6fb21SMehdi Amini             PyBlock returnBlock(moduleOp, mlirModuleGetBody(self.get()));
2298436c6c9cSStella Laurenzo             return returnBlock;
2299436c6c9cSStella Laurenzo           },
2300436c6c9cSStella Laurenzo           "Return the block for this module")
2301436c6c9cSStella Laurenzo       .def(
2302436c6c9cSStella Laurenzo           "dump",
2303436c6c9cSStella Laurenzo           [](PyModule &self) {
2304436c6c9cSStella Laurenzo             mlirOperationDump(mlirModuleGetOperation(self.get()));
2305436c6c9cSStella Laurenzo           },
2306436c6c9cSStella Laurenzo           kDumpDocstring)
2307436c6c9cSStella Laurenzo       .def(
2308436c6c9cSStella Laurenzo           "__str__",
2309ace1d0adSStella Laurenzo           [](py::object self) {
2310ace1d0adSStella Laurenzo             // Defer to the operation's __str__.
2311ace1d0adSStella Laurenzo             return self.attr("operation").attr("__str__")();
2312436c6c9cSStella Laurenzo           },
2313436c6c9cSStella Laurenzo           kOperationStrDunderDocstring);
2314436c6c9cSStella Laurenzo 
2315436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2316436c6c9cSStella Laurenzo   // Mapping of Operation.
2317436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2318f05ff4f7SStella Laurenzo   py::class_<PyOperationBase>(m, "_OperationBase", py::module_local())
23191fb2e842SStella Laurenzo       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
23201fb2e842SStella Laurenzo                              [](PyOperationBase &self) {
23211fb2e842SStella Laurenzo                                return self.getOperation().getCapsule();
23221fb2e842SStella Laurenzo                              })
2323436c6c9cSStella Laurenzo       .def("__eq__",
2324436c6c9cSStella Laurenzo            [](PyOperationBase &self, PyOperationBase &other) {
2325436c6c9cSStella Laurenzo              return &self.getOperation() == &other.getOperation();
2326436c6c9cSStella Laurenzo            })
2327436c6c9cSStella Laurenzo       .def("__eq__",
2328436c6c9cSStella Laurenzo            [](PyOperationBase &self, py::object other) { return false; })
2329f78fe0b7Srkayaith       .def("__hash__",
2330f78fe0b7Srkayaith            [](PyOperationBase &self) {
2331f78fe0b7Srkayaith              return static_cast<size_t>(llvm::hash_value(&self.getOperation()));
2332f78fe0b7Srkayaith            })
2333436c6c9cSStella Laurenzo       .def_property_readonly("attributes",
2334436c6c9cSStella Laurenzo                              [](PyOperationBase &self) {
2335436c6c9cSStella Laurenzo                                return PyOpAttributeMap(
2336436c6c9cSStella Laurenzo                                    self.getOperation().getRef());
2337436c6c9cSStella Laurenzo                              })
2338436c6c9cSStella Laurenzo       .def_property_readonly("operands",
2339436c6c9cSStella Laurenzo                              [](PyOperationBase &self) {
2340436c6c9cSStella Laurenzo                                return PyOpOperandList(
2341436c6c9cSStella Laurenzo                                    self.getOperation().getRef());
2342436c6c9cSStella Laurenzo                              })
2343436c6c9cSStella Laurenzo       .def_property_readonly("regions",
2344436c6c9cSStella Laurenzo                              [](PyOperationBase &self) {
2345436c6c9cSStella Laurenzo                                return PyRegionList(
2346436c6c9cSStella Laurenzo                                    self.getOperation().getRef());
2347436c6c9cSStella Laurenzo                              })
2348436c6c9cSStella Laurenzo       .def_property_readonly(
2349436c6c9cSStella Laurenzo           "results",
2350436c6c9cSStella Laurenzo           [](PyOperationBase &self) {
2351436c6c9cSStella Laurenzo             return PyOpResultList(self.getOperation().getRef());
2352436c6c9cSStella Laurenzo           },
2353436c6c9cSStella Laurenzo           "Returns the list of Operation results.")
2354436c6c9cSStella Laurenzo       .def_property_readonly(
2355436c6c9cSStella Laurenzo           "result",
2356436c6c9cSStella Laurenzo           [](PyOperationBase &self) {
2357436c6c9cSStella Laurenzo             auto &operation = self.getOperation();
2358436c6c9cSStella Laurenzo             auto numResults = mlirOperationGetNumResults(operation);
2359436c6c9cSStella Laurenzo             if (numResults != 1) {
2360436c6c9cSStella Laurenzo               auto name = mlirIdentifierStr(mlirOperationGetName(operation));
2361436c6c9cSStella Laurenzo               throw SetPyError(
2362436c6c9cSStella Laurenzo                   PyExc_ValueError,
2363436c6c9cSStella Laurenzo                   Twine("Cannot call .result on operation ") +
2364436c6c9cSStella Laurenzo                       StringRef(name.data, name.length) + " which has " +
2365436c6c9cSStella Laurenzo                       Twine(numResults) +
2366436c6c9cSStella Laurenzo                       " results (it is only valid for operations with a "
2367436c6c9cSStella Laurenzo                       "single result)");
2368436c6c9cSStella Laurenzo             }
2369436c6c9cSStella Laurenzo             return PyOpResult(operation.getRef(),
2370436c6c9cSStella Laurenzo                               mlirOperationGetResult(operation, 0));
2371436c6c9cSStella Laurenzo           },
2372436c6c9cSStella Laurenzo           "Shortcut to get an op result if it has only one (throws an error "
2373436c6c9cSStella Laurenzo           "otherwise).")
2374d5429a13Srkayaith       .def_property_readonly(
2375d5429a13Srkayaith           "location",
2376d5429a13Srkayaith           [](PyOperationBase &self) {
2377d5429a13Srkayaith             PyOperation &operation = self.getOperation();
2378d5429a13Srkayaith             return PyLocation(operation.getContext(),
2379d5429a13Srkayaith                               mlirOperationGetLocation(operation.get()));
2380d5429a13Srkayaith           },
2381d5429a13Srkayaith           "Returns the source location the operation was defined or derived "
2382d5429a13Srkayaith           "from.")
2383436c6c9cSStella Laurenzo       .def(
2384436c6c9cSStella Laurenzo           "__str__",
2385436c6c9cSStella Laurenzo           [](PyOperationBase &self) {
2386436c6c9cSStella Laurenzo             return self.getAsm(/*binary=*/false,
2387436c6c9cSStella Laurenzo                                /*largeElementsLimit=*/llvm::None,
2388436c6c9cSStella Laurenzo                                /*enableDebugInfo=*/false,
2389436c6c9cSStella Laurenzo                                /*prettyDebugInfo=*/false,
2390436c6c9cSStella Laurenzo                                /*printGenericOpForm=*/false,
2391ace1d0adSStella Laurenzo                                /*useLocalScope=*/false,
2392ace1d0adSStella Laurenzo                                /*assumeVerified=*/false);
2393436c6c9cSStella Laurenzo           },
2394436c6c9cSStella Laurenzo           "Returns the assembly form of the operation.")
2395436c6c9cSStella Laurenzo       .def("print", &PyOperationBase::print,
2396436c6c9cSStella Laurenzo            // Careful: Lots of arguments must match up with print method.
2397436c6c9cSStella Laurenzo            py::arg("file") = py::none(), py::arg("binary") = false,
2398436c6c9cSStella Laurenzo            py::arg("large_elements_limit") = py::none(),
2399436c6c9cSStella Laurenzo            py::arg("enable_debug_info") = false,
2400436c6c9cSStella Laurenzo            py::arg("pretty_debug_info") = false,
2401436c6c9cSStella Laurenzo            py::arg("print_generic_op_form") = false,
2402ace1d0adSStella Laurenzo            py::arg("use_local_scope") = false,
2403ace1d0adSStella Laurenzo            py::arg("assume_verified") = false, kOperationPrintDocstring)
2404436c6c9cSStella Laurenzo       .def("get_asm", &PyOperationBase::getAsm,
2405436c6c9cSStella Laurenzo            // Careful: Lots of arguments must match up with get_asm method.
2406436c6c9cSStella Laurenzo            py::arg("binary") = false,
2407436c6c9cSStella Laurenzo            py::arg("large_elements_limit") = py::none(),
2408436c6c9cSStella Laurenzo            py::arg("enable_debug_info") = false,
2409436c6c9cSStella Laurenzo            py::arg("pretty_debug_info") = false,
2410436c6c9cSStella Laurenzo            py::arg("print_generic_op_form") = false,
2411ace1d0adSStella Laurenzo            py::arg("use_local_scope") = false,
2412ace1d0adSStella Laurenzo            py::arg("assume_verified") = false, kOperationGetAsmDocstring)
2413436c6c9cSStella Laurenzo       .def(
2414436c6c9cSStella Laurenzo           "verify",
2415436c6c9cSStella Laurenzo           [](PyOperationBase &self) {
2416436c6c9cSStella Laurenzo             return mlirOperationVerify(self.getOperation());
2417436c6c9cSStella Laurenzo           },
2418436c6c9cSStella Laurenzo           "Verify the operation and return true if it passes, false if it "
241924685aaeSAlex Zinenko           "fails.")
242024685aaeSAlex Zinenko       .def("move_after", &PyOperationBase::moveAfter, py::arg("other"),
242124685aaeSAlex Zinenko            "Puts self immediately after the other operation in its parent "
242224685aaeSAlex Zinenko            "block.")
242324685aaeSAlex Zinenko       .def("move_before", &PyOperationBase::moveBefore, py::arg("other"),
242424685aaeSAlex Zinenko            "Puts self immediately before the other operation in its parent "
242524685aaeSAlex Zinenko            "block.")
242624685aaeSAlex Zinenko       .def(
242724685aaeSAlex Zinenko           "detach_from_parent",
242824685aaeSAlex Zinenko           [](PyOperationBase &self) {
242924685aaeSAlex Zinenko             PyOperation &operation = self.getOperation();
243024685aaeSAlex Zinenko             operation.checkValid();
243124685aaeSAlex Zinenko             if (!operation.isAttached())
243224685aaeSAlex Zinenko               throw py::value_error("Detached operation has no parent.");
243324685aaeSAlex Zinenko 
243424685aaeSAlex Zinenko             operation.detachFromParent();
243524685aaeSAlex Zinenko             return operation.createOpView();
243624685aaeSAlex Zinenko           },
243724685aaeSAlex Zinenko           "Detaches the operation from its parent block.");
2438436c6c9cSStella Laurenzo 
2439f05ff4f7SStella Laurenzo   py::class_<PyOperation, PyOperationBase>(m, "Operation", py::module_local())
2440436c6c9cSStella Laurenzo       .def_static("create", &PyOperation::create, py::arg("name"),
2441436c6c9cSStella Laurenzo                   py::arg("results") = py::none(),
2442436c6c9cSStella Laurenzo                   py::arg("operands") = py::none(),
2443436c6c9cSStella Laurenzo                   py::arg("attributes") = py::none(),
2444436c6c9cSStella Laurenzo                   py::arg("successors") = py::none(), py::arg("regions") = 0,
2445436c6c9cSStella Laurenzo                   py::arg("loc") = py::none(), py::arg("ip") = py::none(),
2446436c6c9cSStella Laurenzo                   kOperationCreateDocstring)
2447c65bb760SJohn Demme       .def_property_readonly("parent",
24481689dadeSJohn Demme                              [](PyOperation &self) -> py::object {
24491689dadeSJohn Demme                                auto parent = self.getParentOperation();
24501689dadeSJohn Demme                                if (parent)
24511689dadeSJohn Demme                                  return parent->getObject();
24521689dadeSJohn Demme                                return py::none();
2453c65bb760SJohn Demme                              })
245449745f87SMike Urbach       .def("erase", &PyOperation::erase)
24550126e906SJohn Demme       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
24560126e906SJohn Demme                              &PyOperation::getCapsule)
24570126e906SJohn Demme       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyOperation::createFromCapsule)
2458436c6c9cSStella Laurenzo       .def_property_readonly("name",
2459436c6c9cSStella Laurenzo                              [](PyOperation &self) {
246049745f87SMike Urbach                                self.checkValid();
2461436c6c9cSStella Laurenzo                                MlirOperation operation = self.get();
2462436c6c9cSStella Laurenzo                                MlirStringRef name = mlirIdentifierStr(
2463436c6c9cSStella Laurenzo                                    mlirOperationGetName(operation));
2464436c6c9cSStella Laurenzo                                return py::str(name.data, name.length);
2465436c6c9cSStella Laurenzo                              })
2466436c6c9cSStella Laurenzo       .def_property_readonly(
2467436c6c9cSStella Laurenzo           "context",
246849745f87SMike Urbach           [](PyOperation &self) {
246949745f87SMike Urbach             self.checkValid();
247049745f87SMike Urbach             return self.getContext().getObject();
247149745f87SMike Urbach           },
2472436c6c9cSStella Laurenzo           "Context that owns the Operation")
2473436c6c9cSStella Laurenzo       .def_property_readonly("opview", &PyOperation::createOpView);
2474436c6c9cSStella Laurenzo 
2475436c6c9cSStella Laurenzo   auto opViewClass =
2476f05ff4f7SStella Laurenzo       py::class_<PyOpView, PyOperationBase>(m, "OpView", py::module_local())
2477a6e7d024SStella Laurenzo           .def(py::init<py::object>(), py::arg("operation"))
2478436c6c9cSStella Laurenzo           .def_property_readonly("operation", &PyOpView::getOperationObject)
2479436c6c9cSStella Laurenzo           .def_property_readonly(
2480436c6c9cSStella Laurenzo               "context",
2481436c6c9cSStella Laurenzo               [](PyOpView &self) {
2482436c6c9cSStella Laurenzo                 return self.getOperation().getContext().getObject();
2483436c6c9cSStella Laurenzo               },
2484436c6c9cSStella Laurenzo               "Context that owns the Operation")
2485436c6c9cSStella Laurenzo           .def("__str__", [](PyOpView &self) {
2486436c6c9cSStella Laurenzo             return py::str(self.getOperationObject());
2487436c6c9cSStella Laurenzo           });
2488436c6c9cSStella Laurenzo   opViewClass.attr("_ODS_REGIONS") = py::make_tuple(0, true);
2489436c6c9cSStella Laurenzo   opViewClass.attr("_ODS_OPERAND_SEGMENTS") = py::none();
2490436c6c9cSStella Laurenzo   opViewClass.attr("_ODS_RESULT_SEGMENTS") = py::none();
2491436c6c9cSStella Laurenzo   opViewClass.attr("build_generic") = classmethod(
2492436c6c9cSStella Laurenzo       &PyOpView::buildGeneric, py::arg("cls"), py::arg("results") = py::none(),
2493436c6c9cSStella Laurenzo       py::arg("operands") = py::none(), py::arg("attributes") = py::none(),
2494436c6c9cSStella Laurenzo       py::arg("successors") = py::none(), py::arg("regions") = py::none(),
2495436c6c9cSStella Laurenzo       py::arg("loc") = py::none(), py::arg("ip") = py::none(),
2496436c6c9cSStella Laurenzo       "Builds a specific, generated OpView based on class level attributes.");
2497436c6c9cSStella Laurenzo 
2498436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2499436c6c9cSStella Laurenzo   // Mapping of PyRegion.
2500436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2501f05ff4f7SStella Laurenzo   py::class_<PyRegion>(m, "Region", py::module_local())
2502436c6c9cSStella Laurenzo       .def_property_readonly(
2503436c6c9cSStella Laurenzo           "blocks",
2504436c6c9cSStella Laurenzo           [](PyRegion &self) {
2505436c6c9cSStella Laurenzo             return PyBlockList(self.getParentOperation(), self.get());
2506436c6c9cSStella Laurenzo           },
2507436c6c9cSStella Laurenzo           "Returns a forward-optimized sequence of blocks.")
250878f2dae0SAlex Zinenko       .def_property_readonly(
250978f2dae0SAlex Zinenko           "owner",
251078f2dae0SAlex Zinenko           [](PyRegion &self) {
251178f2dae0SAlex Zinenko             return self.getParentOperation()->createOpView();
251278f2dae0SAlex Zinenko           },
251378f2dae0SAlex Zinenko           "Returns the operation owning this region.")
2514436c6c9cSStella Laurenzo       .def(
2515436c6c9cSStella Laurenzo           "__iter__",
2516436c6c9cSStella Laurenzo           [](PyRegion &self) {
2517436c6c9cSStella Laurenzo             self.checkValid();
2518436c6c9cSStella Laurenzo             MlirBlock firstBlock = mlirRegionGetFirstBlock(self.get());
2519436c6c9cSStella Laurenzo             return PyBlockIterator(self.getParentOperation(), firstBlock);
2520436c6c9cSStella Laurenzo           },
2521436c6c9cSStella Laurenzo           "Iterates over blocks in the region.")
2522436c6c9cSStella Laurenzo       .def("__eq__",
2523436c6c9cSStella Laurenzo            [](PyRegion &self, PyRegion &other) {
2524436c6c9cSStella Laurenzo              return self.get().ptr == other.get().ptr;
2525436c6c9cSStella Laurenzo            })
2526436c6c9cSStella Laurenzo       .def("__eq__", [](PyRegion &self, py::object &other) { return false; });
2527436c6c9cSStella Laurenzo 
2528436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2529436c6c9cSStella Laurenzo   // Mapping of PyBlock.
2530436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2531f05ff4f7SStella Laurenzo   py::class_<PyBlock>(m, "Block", py::module_local())
2532436c6c9cSStella Laurenzo       .def_property_readonly(
253396fbd5cdSJohn Demme           "owner",
253496fbd5cdSJohn Demme           [](PyBlock &self) {
253596fbd5cdSJohn Demme             return self.getParentOperation()->createOpView();
253696fbd5cdSJohn Demme           },
253796fbd5cdSJohn Demme           "Returns the owning operation of this block.")
253896fbd5cdSJohn Demme       .def_property_readonly(
25398e6c55c9SStella Laurenzo           "region",
25408e6c55c9SStella Laurenzo           [](PyBlock &self) {
25418e6c55c9SStella Laurenzo             MlirRegion region = mlirBlockGetParentRegion(self.get());
25428e6c55c9SStella Laurenzo             return PyRegion(self.getParentOperation(), region);
25438e6c55c9SStella Laurenzo           },
25448e6c55c9SStella Laurenzo           "Returns the owning region of this block.")
25458e6c55c9SStella Laurenzo       .def_property_readonly(
2546436c6c9cSStella Laurenzo           "arguments",
2547436c6c9cSStella Laurenzo           [](PyBlock &self) {
2548436c6c9cSStella Laurenzo             return PyBlockArgumentList(self.getParentOperation(), self.get());
2549436c6c9cSStella Laurenzo           },
2550436c6c9cSStella Laurenzo           "Returns a list of block arguments.")
2551436c6c9cSStella Laurenzo       .def_property_readonly(
2552436c6c9cSStella Laurenzo           "operations",
2553436c6c9cSStella Laurenzo           [](PyBlock &self) {
2554436c6c9cSStella Laurenzo             return PyOperationList(self.getParentOperation(), self.get());
2555436c6c9cSStella Laurenzo           },
2556436c6c9cSStella Laurenzo           "Returns a forward-optimized sequence of operations.")
255778f2dae0SAlex Zinenko       .def_static(
255878f2dae0SAlex Zinenko           "create_at_start",
255978f2dae0SAlex Zinenko           [](PyRegion &parent, py::list pyArgTypes) {
256078f2dae0SAlex Zinenko             parent.checkValid();
256178f2dae0SAlex Zinenko             llvm::SmallVector<MlirType, 4> argTypes;
256278f2dae0SAlex Zinenko             argTypes.reserve(pyArgTypes.size());
256378f2dae0SAlex Zinenko             for (auto &pyArg : pyArgTypes) {
256478f2dae0SAlex Zinenko               argTypes.push_back(pyArg.cast<PyType &>());
256578f2dae0SAlex Zinenko             }
256678f2dae0SAlex Zinenko 
256778f2dae0SAlex Zinenko             MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
256878f2dae0SAlex Zinenko             mlirRegionInsertOwnedBlock(parent, 0, block);
256978f2dae0SAlex Zinenko             return PyBlock(parent.getParentOperation(), block);
257078f2dae0SAlex Zinenko           },
2571a6e7d024SStella Laurenzo           py::arg("parent"), py::arg("arg_types") = py::list(),
257278f2dae0SAlex Zinenko           "Creates and returns a new Block at the beginning of the given "
257378f2dae0SAlex Zinenko           "region (with given argument types).")
2574436c6c9cSStella Laurenzo       .def(
25758e6c55c9SStella Laurenzo           "create_before",
25768e6c55c9SStella Laurenzo           [](PyBlock &self, py::args pyArgTypes) {
25778e6c55c9SStella Laurenzo             self.checkValid();
25788e6c55c9SStella Laurenzo             llvm::SmallVector<MlirType, 4> argTypes;
25798e6c55c9SStella Laurenzo             argTypes.reserve(pyArgTypes.size());
25808e6c55c9SStella Laurenzo             for (auto &pyArg : pyArgTypes) {
25818e6c55c9SStella Laurenzo               argTypes.push_back(pyArg.cast<PyType &>());
25828e6c55c9SStella Laurenzo             }
25838e6c55c9SStella Laurenzo 
25848e6c55c9SStella Laurenzo             MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
25858e6c55c9SStella Laurenzo             MlirRegion region = mlirBlockGetParentRegion(self.get());
25868e6c55c9SStella Laurenzo             mlirRegionInsertOwnedBlockBefore(region, self.get(), block);
25878e6c55c9SStella Laurenzo             return PyBlock(self.getParentOperation(), block);
25888e6c55c9SStella Laurenzo           },
25898e6c55c9SStella Laurenzo           "Creates and returns a new Block before this block "
25908e6c55c9SStella Laurenzo           "(with given argument types).")
25918e6c55c9SStella Laurenzo       .def(
25928e6c55c9SStella Laurenzo           "create_after",
25938e6c55c9SStella Laurenzo           [](PyBlock &self, py::args pyArgTypes) {
25948e6c55c9SStella Laurenzo             self.checkValid();
25958e6c55c9SStella Laurenzo             llvm::SmallVector<MlirType, 4> argTypes;
25968e6c55c9SStella Laurenzo             argTypes.reserve(pyArgTypes.size());
25978e6c55c9SStella Laurenzo             for (auto &pyArg : pyArgTypes) {
25988e6c55c9SStella Laurenzo               argTypes.push_back(pyArg.cast<PyType &>());
25998e6c55c9SStella Laurenzo             }
26008e6c55c9SStella Laurenzo 
26018e6c55c9SStella Laurenzo             MlirBlock block = mlirBlockCreate(argTypes.size(), argTypes.data());
26028e6c55c9SStella Laurenzo             MlirRegion region = mlirBlockGetParentRegion(self.get());
26038e6c55c9SStella Laurenzo             mlirRegionInsertOwnedBlockAfter(region, self.get(), block);
26048e6c55c9SStella Laurenzo             return PyBlock(self.getParentOperation(), block);
26058e6c55c9SStella Laurenzo           },
26068e6c55c9SStella Laurenzo           "Creates and returns a new Block after this block "
26078e6c55c9SStella Laurenzo           "(with given argument types).")
26088e6c55c9SStella Laurenzo       .def(
2609436c6c9cSStella Laurenzo           "__iter__",
2610436c6c9cSStella Laurenzo           [](PyBlock &self) {
2611436c6c9cSStella Laurenzo             self.checkValid();
2612436c6c9cSStella Laurenzo             MlirOperation firstOperation =
2613436c6c9cSStella Laurenzo                 mlirBlockGetFirstOperation(self.get());
2614436c6c9cSStella Laurenzo             return PyOperationIterator(self.getParentOperation(),
2615436c6c9cSStella Laurenzo                                        firstOperation);
2616436c6c9cSStella Laurenzo           },
2617436c6c9cSStella Laurenzo           "Iterates over operations in the block.")
2618436c6c9cSStella Laurenzo       .def("__eq__",
2619436c6c9cSStella Laurenzo            [](PyBlock &self, PyBlock &other) {
2620436c6c9cSStella Laurenzo              return self.get().ptr == other.get().ptr;
2621436c6c9cSStella Laurenzo            })
2622436c6c9cSStella Laurenzo       .def("__eq__", [](PyBlock &self, py::object &other) { return false; })
2623436c6c9cSStella Laurenzo       .def(
2624436c6c9cSStella Laurenzo           "__str__",
2625436c6c9cSStella Laurenzo           [](PyBlock &self) {
2626436c6c9cSStella Laurenzo             self.checkValid();
2627436c6c9cSStella Laurenzo             PyPrintAccumulator printAccum;
2628436c6c9cSStella Laurenzo             mlirBlockPrint(self.get(), printAccum.getCallback(),
2629436c6c9cSStella Laurenzo                            printAccum.getUserData());
2630436c6c9cSStella Laurenzo             return printAccum.join();
2631436c6c9cSStella Laurenzo           },
263224685aaeSAlex Zinenko           "Returns the assembly form of the block.")
263324685aaeSAlex Zinenko       .def(
263424685aaeSAlex Zinenko           "append",
263524685aaeSAlex Zinenko           [](PyBlock &self, PyOperationBase &operation) {
263624685aaeSAlex Zinenko             if (operation.getOperation().isAttached())
263724685aaeSAlex Zinenko               operation.getOperation().detachFromParent();
263824685aaeSAlex Zinenko 
263924685aaeSAlex Zinenko             MlirOperation mlirOperation = operation.getOperation().get();
264024685aaeSAlex Zinenko             mlirBlockAppendOwnedOperation(self.get(), mlirOperation);
264124685aaeSAlex Zinenko             operation.getOperation().setAttached(
264224685aaeSAlex Zinenko                 self.getParentOperation().getObject());
264324685aaeSAlex Zinenko           },
2644a6e7d024SStella Laurenzo           py::arg("operation"),
264524685aaeSAlex Zinenko           "Appends an operation to this block. If the operation is currently "
264624685aaeSAlex Zinenko           "in another block, it will be moved.");
2647436c6c9cSStella Laurenzo 
2648436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2649436c6c9cSStella Laurenzo   // Mapping of PyInsertionPoint.
2650436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2651436c6c9cSStella Laurenzo 
2652f05ff4f7SStella Laurenzo   py::class_<PyInsertionPoint>(m, "InsertionPoint", py::module_local())
2653436c6c9cSStella Laurenzo       .def(py::init<PyBlock &>(), py::arg("block"),
2654436c6c9cSStella Laurenzo            "Inserts after the last operation but still inside the block.")
2655436c6c9cSStella Laurenzo       .def("__enter__", &PyInsertionPoint::contextEnter)
2656436c6c9cSStella Laurenzo       .def("__exit__", &PyInsertionPoint::contextExit)
2657436c6c9cSStella Laurenzo       .def_property_readonly_static(
2658436c6c9cSStella Laurenzo           "current",
2659436c6c9cSStella Laurenzo           [](py::object & /*class*/) {
2660436c6c9cSStella Laurenzo             auto *ip = PyThreadContextEntry::getDefaultInsertionPoint();
2661436c6c9cSStella Laurenzo             if (!ip)
2662436c6c9cSStella Laurenzo               throw SetPyError(PyExc_ValueError, "No current InsertionPoint");
2663436c6c9cSStella Laurenzo             return ip;
2664436c6c9cSStella Laurenzo           },
2665436c6c9cSStella Laurenzo           "Gets the InsertionPoint bound to the current thread or raises "
2666436c6c9cSStella Laurenzo           "ValueError if none has been set")
2667436c6c9cSStella Laurenzo       .def(py::init<PyOperationBase &>(), py::arg("beforeOperation"),
2668436c6c9cSStella Laurenzo            "Inserts before a referenced operation.")
2669436c6c9cSStella Laurenzo       .def_static("at_block_begin", &PyInsertionPoint::atBlockBegin,
2670436c6c9cSStella Laurenzo                   py::arg("block"), "Inserts at the beginning of the block.")
2671436c6c9cSStella Laurenzo       .def_static("at_block_terminator", &PyInsertionPoint::atBlockTerminator,
2672436c6c9cSStella Laurenzo                   py::arg("block"), "Inserts before the block terminator.")
2673436c6c9cSStella Laurenzo       .def("insert", &PyInsertionPoint::insert, py::arg("operation"),
26748e6c55c9SStella Laurenzo            "Inserts an operation.")
26758e6c55c9SStella Laurenzo       .def_property_readonly(
26768e6c55c9SStella Laurenzo           "block", [](PyInsertionPoint &self) { return self.getBlock(); },
26778e6c55c9SStella Laurenzo           "Returns the block that this InsertionPoint points to.");
2678436c6c9cSStella Laurenzo 
2679436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2680436c6c9cSStella Laurenzo   // Mapping of PyAttribute.
2681436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2682f05ff4f7SStella Laurenzo   py::class_<PyAttribute>(m, "Attribute", py::module_local())
2683b57d6fe4SStella Laurenzo       // Delegate to the PyAttribute copy constructor, which will also lifetime
2684b57d6fe4SStella Laurenzo       // extend the backing context which owns the MlirAttribute.
2685b57d6fe4SStella Laurenzo       .def(py::init<PyAttribute &>(), py::arg("cast_from_type"),
2686b57d6fe4SStella Laurenzo            "Casts the passed attribute to the generic Attribute")
2687436c6c9cSStella Laurenzo       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR,
2688436c6c9cSStella Laurenzo                              &PyAttribute::getCapsule)
2689436c6c9cSStella Laurenzo       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyAttribute::createFromCapsule)
2690436c6c9cSStella Laurenzo       .def_static(
2691436c6c9cSStella Laurenzo           "parse",
2692436c6c9cSStella Laurenzo           [](std::string attrSpec, DefaultingPyMlirContext context) {
2693436c6c9cSStella Laurenzo             MlirAttribute type = mlirAttributeParseGet(
2694436c6c9cSStella Laurenzo                 context->get(), toMlirStringRef(attrSpec));
2695436c6c9cSStella Laurenzo             // TODO: Rework error reporting once diagnostic engine is exposed
2696436c6c9cSStella Laurenzo             // in C API.
2697436c6c9cSStella Laurenzo             if (mlirAttributeIsNull(type)) {
2698436c6c9cSStella Laurenzo               throw SetPyError(PyExc_ValueError,
2699436c6c9cSStella Laurenzo                                Twine("Unable to parse attribute: '") +
2700436c6c9cSStella Laurenzo                                    attrSpec + "'");
2701436c6c9cSStella Laurenzo             }
2702436c6c9cSStella Laurenzo             return PyAttribute(context->getRef(), type);
2703436c6c9cSStella Laurenzo           },
2704436c6c9cSStella Laurenzo           py::arg("asm"), py::arg("context") = py::none(),
2705436c6c9cSStella Laurenzo           "Parses an attribute from an assembly form")
2706436c6c9cSStella Laurenzo       .def_property_readonly(
2707436c6c9cSStella Laurenzo           "context",
2708436c6c9cSStella Laurenzo           [](PyAttribute &self) { return self.getContext().getObject(); },
2709436c6c9cSStella Laurenzo           "Context that owns the Attribute")
2710436c6c9cSStella Laurenzo       .def_property_readonly("type",
2711436c6c9cSStella Laurenzo                              [](PyAttribute &self) {
2712436c6c9cSStella Laurenzo                                return PyType(self.getContext()->getRef(),
2713436c6c9cSStella Laurenzo                                              mlirAttributeGetType(self));
2714436c6c9cSStella Laurenzo                              })
2715436c6c9cSStella Laurenzo       .def(
2716436c6c9cSStella Laurenzo           "get_named",
2717436c6c9cSStella Laurenzo           [](PyAttribute &self, std::string name) {
2718436c6c9cSStella Laurenzo             return PyNamedAttribute(self, std::move(name));
2719436c6c9cSStella Laurenzo           },
2720436c6c9cSStella Laurenzo           py::keep_alive<0, 1>(), "Binds a name to the attribute")
2721436c6c9cSStella Laurenzo       .def("__eq__",
2722436c6c9cSStella Laurenzo            [](PyAttribute &self, PyAttribute &other) { return self == other; })
2723436c6c9cSStella Laurenzo       .def("__eq__", [](PyAttribute &self, py::object &other) { return false; })
2724f78fe0b7Srkayaith       .def("__hash__",
2725f78fe0b7Srkayaith            [](PyAttribute &self) {
2726f78fe0b7Srkayaith              return static_cast<size_t>(llvm::hash_value(self.get().ptr));
2727f78fe0b7Srkayaith            })
2728436c6c9cSStella Laurenzo       .def(
2729436c6c9cSStella Laurenzo           "dump", [](PyAttribute &self) { mlirAttributeDump(self); },
2730436c6c9cSStella Laurenzo           kDumpDocstring)
2731436c6c9cSStella Laurenzo       .def(
2732436c6c9cSStella Laurenzo           "__str__",
2733436c6c9cSStella Laurenzo           [](PyAttribute &self) {
2734436c6c9cSStella Laurenzo             PyPrintAccumulator printAccum;
2735436c6c9cSStella Laurenzo             mlirAttributePrint(self, printAccum.getCallback(),
2736436c6c9cSStella Laurenzo                                printAccum.getUserData());
2737436c6c9cSStella Laurenzo             return printAccum.join();
2738436c6c9cSStella Laurenzo           },
2739436c6c9cSStella Laurenzo           "Returns the assembly form of the Attribute.")
2740436c6c9cSStella Laurenzo       .def("__repr__", [](PyAttribute &self) {
2741436c6c9cSStella Laurenzo         // Generally, assembly formats are not printed for __repr__ because
2742436c6c9cSStella Laurenzo         // this can cause exceptionally long debug output and exceptions.
2743436c6c9cSStella Laurenzo         // However, attribute values are generally considered useful and are
2744436c6c9cSStella Laurenzo         // printed. This may need to be re-evaluated if debug dumps end up
2745436c6c9cSStella Laurenzo         // being excessive.
2746436c6c9cSStella Laurenzo         PyPrintAccumulator printAccum;
2747436c6c9cSStella Laurenzo         printAccum.parts.append("Attribute(");
2748436c6c9cSStella Laurenzo         mlirAttributePrint(self, printAccum.getCallback(),
2749436c6c9cSStella Laurenzo                            printAccum.getUserData());
2750436c6c9cSStella Laurenzo         printAccum.parts.append(")");
2751436c6c9cSStella Laurenzo         return printAccum.join();
2752436c6c9cSStella Laurenzo       });
2753436c6c9cSStella Laurenzo 
2754436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2755436c6c9cSStella Laurenzo   // Mapping of PyNamedAttribute
2756436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2757f05ff4f7SStella Laurenzo   py::class_<PyNamedAttribute>(m, "NamedAttribute", py::module_local())
2758436c6c9cSStella Laurenzo       .def("__repr__",
2759436c6c9cSStella Laurenzo            [](PyNamedAttribute &self) {
2760436c6c9cSStella Laurenzo              PyPrintAccumulator printAccum;
2761436c6c9cSStella Laurenzo              printAccum.parts.append("NamedAttribute(");
2762436c6c9cSStella Laurenzo              printAccum.parts.append(
2763120591e1SRiver Riddle                  py::str(mlirIdentifierStr(self.namedAttr.name).data,
2764120591e1SRiver Riddle                          mlirIdentifierStr(self.namedAttr.name).length));
2765436c6c9cSStella Laurenzo              printAccum.parts.append("=");
2766436c6c9cSStella Laurenzo              mlirAttributePrint(self.namedAttr.attribute,
2767436c6c9cSStella Laurenzo                                 printAccum.getCallback(),
2768436c6c9cSStella Laurenzo                                 printAccum.getUserData());
2769436c6c9cSStella Laurenzo              printAccum.parts.append(")");
2770436c6c9cSStella Laurenzo              return printAccum.join();
2771436c6c9cSStella Laurenzo            })
2772436c6c9cSStella Laurenzo       .def_property_readonly(
2773436c6c9cSStella Laurenzo           "name",
2774436c6c9cSStella Laurenzo           [](PyNamedAttribute &self) {
2775436c6c9cSStella Laurenzo             return py::str(mlirIdentifierStr(self.namedAttr.name).data,
2776436c6c9cSStella Laurenzo                            mlirIdentifierStr(self.namedAttr.name).length);
2777436c6c9cSStella Laurenzo           },
2778436c6c9cSStella Laurenzo           "The name of the NamedAttribute binding")
2779436c6c9cSStella Laurenzo       .def_property_readonly(
2780436c6c9cSStella Laurenzo           "attr",
2781436c6c9cSStella Laurenzo           [](PyNamedAttribute &self) {
2782436c6c9cSStella Laurenzo             // TODO: When named attribute is removed/refactored, also remove
2783436c6c9cSStella Laurenzo             // this constructor (it does an inefficient table lookup).
2784436c6c9cSStella Laurenzo             auto contextRef = PyMlirContext::forContext(
2785436c6c9cSStella Laurenzo                 mlirAttributeGetContext(self.namedAttr.attribute));
2786436c6c9cSStella Laurenzo             return PyAttribute(std::move(contextRef), self.namedAttr.attribute);
2787436c6c9cSStella Laurenzo           },
2788436c6c9cSStella Laurenzo           py::keep_alive<0, 1>(),
2789436c6c9cSStella Laurenzo           "The underlying generic attribute of the NamedAttribute binding");
2790436c6c9cSStella Laurenzo 
2791436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2792436c6c9cSStella Laurenzo   // Mapping of PyType.
2793436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2794f05ff4f7SStella Laurenzo   py::class_<PyType>(m, "Type", py::module_local())
2795b57d6fe4SStella Laurenzo       // Delegate to the PyType copy constructor, which will also lifetime
2796b57d6fe4SStella Laurenzo       // extend the backing context which owns the MlirType.
2797b57d6fe4SStella Laurenzo       .def(py::init<PyType &>(), py::arg("cast_from_type"),
2798b57d6fe4SStella Laurenzo            "Casts the passed type to the generic Type")
2799436c6c9cSStella Laurenzo       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyType::getCapsule)
2800436c6c9cSStella Laurenzo       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyType::createFromCapsule)
2801436c6c9cSStella Laurenzo       .def_static(
2802436c6c9cSStella Laurenzo           "parse",
2803436c6c9cSStella Laurenzo           [](std::string typeSpec, DefaultingPyMlirContext context) {
2804436c6c9cSStella Laurenzo             MlirType type =
2805436c6c9cSStella Laurenzo                 mlirTypeParseGet(context->get(), toMlirStringRef(typeSpec));
2806436c6c9cSStella Laurenzo             // TODO: Rework error reporting once diagnostic engine is exposed
2807436c6c9cSStella Laurenzo             // in C API.
2808436c6c9cSStella Laurenzo             if (mlirTypeIsNull(type)) {
2809436c6c9cSStella Laurenzo               throw SetPyError(PyExc_ValueError,
2810436c6c9cSStella Laurenzo                                Twine("Unable to parse type: '") + typeSpec +
2811436c6c9cSStella Laurenzo                                    "'");
2812436c6c9cSStella Laurenzo             }
2813436c6c9cSStella Laurenzo             return PyType(context->getRef(), type);
2814436c6c9cSStella Laurenzo           },
2815436c6c9cSStella Laurenzo           py::arg("asm"), py::arg("context") = py::none(),
2816436c6c9cSStella Laurenzo           kContextParseTypeDocstring)
2817436c6c9cSStella Laurenzo       .def_property_readonly(
2818436c6c9cSStella Laurenzo           "context", [](PyType &self) { return self.getContext().getObject(); },
2819436c6c9cSStella Laurenzo           "Context that owns the Type")
2820436c6c9cSStella Laurenzo       .def("__eq__", [](PyType &self, PyType &other) { return self == other; })
2821436c6c9cSStella Laurenzo       .def("__eq__", [](PyType &self, py::object &other) { return false; })
2822f78fe0b7Srkayaith       .def("__hash__",
2823f78fe0b7Srkayaith            [](PyType &self) {
2824f78fe0b7Srkayaith              return static_cast<size_t>(llvm::hash_value(self.get().ptr));
2825f78fe0b7Srkayaith            })
2826436c6c9cSStella Laurenzo       .def(
2827436c6c9cSStella Laurenzo           "dump", [](PyType &self) { mlirTypeDump(self); }, kDumpDocstring)
2828436c6c9cSStella Laurenzo       .def(
2829436c6c9cSStella Laurenzo           "__str__",
2830436c6c9cSStella Laurenzo           [](PyType &self) {
2831436c6c9cSStella Laurenzo             PyPrintAccumulator printAccum;
2832436c6c9cSStella Laurenzo             mlirTypePrint(self, printAccum.getCallback(),
2833436c6c9cSStella Laurenzo                           printAccum.getUserData());
2834436c6c9cSStella Laurenzo             return printAccum.join();
2835436c6c9cSStella Laurenzo           },
2836436c6c9cSStella Laurenzo           "Returns the assembly form of the type.")
2837436c6c9cSStella Laurenzo       .def("__repr__", [](PyType &self) {
2838436c6c9cSStella Laurenzo         // Generally, assembly formats are not printed for __repr__ because
2839436c6c9cSStella Laurenzo         // this can cause exceptionally long debug output and exceptions.
2840436c6c9cSStella Laurenzo         // However, types are an exception as they typically have compact
2841436c6c9cSStella Laurenzo         // assembly forms and printing them is useful.
2842436c6c9cSStella Laurenzo         PyPrintAccumulator printAccum;
2843436c6c9cSStella Laurenzo         printAccum.parts.append("Type(");
2844436c6c9cSStella Laurenzo         mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData());
2845436c6c9cSStella Laurenzo         printAccum.parts.append(")");
2846436c6c9cSStella Laurenzo         return printAccum.join();
2847436c6c9cSStella Laurenzo       });
2848436c6c9cSStella Laurenzo 
2849436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2850436c6c9cSStella Laurenzo   // Mapping of Value.
2851436c6c9cSStella Laurenzo   //----------------------------------------------------------------------------
2852f05ff4f7SStella Laurenzo   py::class_<PyValue>(m, "Value", py::module_local())
28533f3d1c90SMike Urbach       .def_property_readonly(MLIR_PYTHON_CAPI_PTR_ATTR, &PyValue::getCapsule)
28543f3d1c90SMike Urbach       .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyValue::createFromCapsule)
2855436c6c9cSStella Laurenzo       .def_property_readonly(
2856436c6c9cSStella Laurenzo           "context",
2857436c6c9cSStella Laurenzo           [](PyValue &self) { return self.getParentOperation()->getContext(); },
2858436c6c9cSStella Laurenzo           "Context in which the value lives.")
2859436c6c9cSStella Laurenzo       .def(
2860436c6c9cSStella Laurenzo           "dump", [](PyValue &self) { mlirValueDump(self.get()); },
2861436c6c9cSStella Laurenzo           kDumpDocstring)
28625664c5e2SJohn Demme       .def_property_readonly(
28635664c5e2SJohn Demme           "owner",
28645664c5e2SJohn Demme           [](PyValue &self) {
28655664c5e2SJohn Demme             assert(mlirOperationEqual(self.getParentOperation()->get(),
28665664c5e2SJohn Demme                                       mlirOpResultGetOwner(self.get())) &&
28675664c5e2SJohn Demme                    "expected the owner of the value in Python to match that in "
28685664c5e2SJohn Demme                    "the IR");
28695664c5e2SJohn Demme             return self.getParentOperation().getObject();
28705664c5e2SJohn Demme           })
2871436c6c9cSStella Laurenzo       .def("__eq__",
2872436c6c9cSStella Laurenzo            [](PyValue &self, PyValue &other) {
2873436c6c9cSStella Laurenzo              return self.get().ptr == other.get().ptr;
2874436c6c9cSStella Laurenzo            })
2875436c6c9cSStella Laurenzo       .def("__eq__", [](PyValue &self, py::object other) { return false; })
2876f78fe0b7Srkayaith       .def("__hash__",
2877f78fe0b7Srkayaith            [](PyValue &self) {
2878f78fe0b7Srkayaith              return static_cast<size_t>(llvm::hash_value(self.get().ptr));
2879f78fe0b7Srkayaith            })
2880436c6c9cSStella Laurenzo       .def(
2881436c6c9cSStella Laurenzo           "__str__",
2882436c6c9cSStella Laurenzo           [](PyValue &self) {
2883436c6c9cSStella Laurenzo             PyPrintAccumulator printAccum;
2884436c6c9cSStella Laurenzo             printAccum.parts.append("Value(");
2885436c6c9cSStella Laurenzo             mlirValuePrint(self.get(), printAccum.getCallback(),
2886436c6c9cSStella Laurenzo                            printAccum.getUserData());
2887436c6c9cSStella Laurenzo             printAccum.parts.append(")");
2888436c6c9cSStella Laurenzo             return printAccum.join();
2889436c6c9cSStella Laurenzo           },
2890436c6c9cSStella Laurenzo           kValueDunderStrDocstring)
2891436c6c9cSStella Laurenzo       .def_property_readonly("type", [](PyValue &self) {
2892436c6c9cSStella Laurenzo         return PyType(self.getParentOperation()->getContext(),
2893436c6c9cSStella Laurenzo                       mlirValueGetType(self.get()));
2894436c6c9cSStella Laurenzo       });
2895436c6c9cSStella Laurenzo   PyBlockArgument::bind(m);
2896436c6c9cSStella Laurenzo   PyOpResult::bind(m);
2897436c6c9cSStella Laurenzo 
289830d61893SAlex Zinenko   //----------------------------------------------------------------------------
289930d61893SAlex Zinenko   // Mapping of SymbolTable.
290030d61893SAlex Zinenko   //----------------------------------------------------------------------------
290130d61893SAlex Zinenko   py::class_<PySymbolTable>(m, "SymbolTable", py::module_local())
290230d61893SAlex Zinenko       .def(py::init<PyOperationBase &>())
290330d61893SAlex Zinenko       .def("__getitem__", &PySymbolTable::dunderGetItem)
2904a6e7d024SStella Laurenzo       .def("insert", &PySymbolTable::insert, py::arg("operation"))
2905a6e7d024SStella Laurenzo       .def("erase", &PySymbolTable::erase, py::arg("operation"))
290630d61893SAlex Zinenko       .def("__delitem__", &PySymbolTable::dunderDel)
2907bdc31837SStella Laurenzo       .def("__contains__",
2908bdc31837SStella Laurenzo            [](PySymbolTable &table, const std::string &name) {
290930d61893SAlex Zinenko              return !mlirOperationIsNull(mlirSymbolTableLookup(
291030d61893SAlex Zinenko                  table, mlirStringRefCreate(name.data(), name.length())));
2911bdc31837SStella Laurenzo            })
2912bdc31837SStella Laurenzo       // Static helpers.
2913bdc31837SStella Laurenzo       .def_static("set_symbol_name", &PySymbolTable::setSymbolName,
2914bdc31837SStella Laurenzo                   py::arg("symbol"), py::arg("name"))
2915bdc31837SStella Laurenzo       .def_static("get_symbol_name", &PySymbolTable::getSymbolName,
2916bdc31837SStella Laurenzo                   py::arg("symbol"))
2917bdc31837SStella Laurenzo       .def_static("get_visibility", &PySymbolTable::getVisibility,
2918bdc31837SStella Laurenzo                   py::arg("symbol"))
2919bdc31837SStella Laurenzo       .def_static("set_visibility", &PySymbolTable::setVisibility,
2920bdc31837SStella Laurenzo                   py::arg("symbol"), py::arg("visibility"))
2921bdc31837SStella Laurenzo       .def_static("replace_all_symbol_uses",
2922bdc31837SStella Laurenzo                   &PySymbolTable::replaceAllSymbolUses, py::arg("old_symbol"),
2923bdc31837SStella Laurenzo                   py::arg("new_symbol"), py::arg("from_op"))
2924bdc31837SStella Laurenzo       .def_static("walk_symbol_tables", &PySymbolTable::walkSymbolTables,
2925bdc31837SStella Laurenzo                   py::arg("from_op"), py::arg("all_sym_uses_visible"),
2926bdc31837SStella Laurenzo                   py::arg("callback"));
292730d61893SAlex Zinenko 
2928436c6c9cSStella Laurenzo   // Container bindings.
2929436c6c9cSStella Laurenzo   PyBlockArgumentList::bind(m);
2930436c6c9cSStella Laurenzo   PyBlockIterator::bind(m);
2931436c6c9cSStella Laurenzo   PyBlockList::bind(m);
2932436c6c9cSStella Laurenzo   PyOperationIterator::bind(m);
2933436c6c9cSStella Laurenzo   PyOperationList::bind(m);
2934436c6c9cSStella Laurenzo   PyOpAttributeMap::bind(m);
2935436c6c9cSStella Laurenzo   PyOpOperandList::bind(m);
2936436c6c9cSStella Laurenzo   PyOpResultList::bind(m);
2937436c6c9cSStella Laurenzo   PyRegionIterator::bind(m);
2938436c6c9cSStella Laurenzo   PyRegionList::bind(m);
29394acd8457SAlex Zinenko 
29404acd8457SAlex Zinenko   // Debug bindings.
29414acd8457SAlex Zinenko   PyGlobalDebugFlag::bind(m);
2942436c6c9cSStella Laurenzo }
2943