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