MLIR  21.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 <optional>
10 #include <utility>
11 
12 #include "Globals.h"
13 #include "IRModule.h"
14 #include "NanobindUtils.h"
16 #include "mlir-c/Debug.h"
17 #include "mlir-c/Diagnostics.h"
18 #include "mlir-c/IR.h"
19 #include "mlir-c/Support.h"
22 #include "mlir-c/Bindings/Python/Interop.h" // This is expected after nanobind.
23 #include "llvm/ADT/ArrayRef.h"
24 #include "llvm/ADT/SmallVector.h"
25 
26 namespace nb = nanobind;
27 using namespace nb::literals;
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 kContextGetFileRangeDocstring[] =
54  R"(Gets a Location representing a file, line and column range)";
55 
56 static const char kContextGetFusedLocationDocstring[] =
57  R"(Gets a Location representing a fused location with optional metadata)";
58 
59 static const char kContextGetNameLocationDocString[] =
60  R"(Gets a Location representing a named location with optional child location)";
61 
62 static const char kModuleParseDocstring[] =
63  R"(Parses a module's assembly format from a string.
64 
65 Returns a new MlirModule or raises an MLIRError if the parsing fails.
66 
67 See also: https://mlir.llvm.org/docs/LangRef/
68 )";
69 
70 static const char kOperationCreateDocstring[] =
71  R"(Creates a new operation.
72 
73 Args:
74  name: Operation name (e.g. "dialect.operation").
75  results: Sequence of Type representing op result types.
76  attributes: Dict of str:Attribute.
77  successors: List of Block for the operation's successors.
78  regions: Number of regions to create.
79  location: A Location object (defaults to resolve from context manager).
80  ip: An InsertionPoint (defaults to resolve from context manager or set to
81  False to disable insertion, even with an insertion point set in the
82  context manager).
83  infer_type: Whether to infer result types.
84 Returns:
85  A new "detached" Operation object. Detached operations can be added
86  to blocks, which causes them to become "attached."
87 )";
88 
89 static const char kOperationPrintDocstring[] =
90  R"(Prints the assembly form of the operation to a file like object.
91 
92 Args:
93  file: The file like object to write to. Defaults to sys.stdout.
94  binary: Whether to write bytes (True) or str (False). Defaults to False.
95  large_elements_limit: Whether to elide elements attributes above this
96  number of elements. Defaults to None (no limit).
97  enable_debug_info: Whether to print debug/location information. Defaults
98  to False.
99  pretty_debug_info: Whether to format debug information for easier reading
100  by a human (warning: the result is unparseable).
101  print_generic_op_form: Whether to print the generic assembly forms of all
102  ops. Defaults to False.
103  use_local_Scope: Whether to print in a way that is more optimized for
104  multi-threaded access but may not be consistent with how the overall
105  module prints.
106  assume_verified: By default, if not printing generic form, the verifier
107  will be run and if it fails, generic form will be printed with a comment
108  about failed verification. While a reasonable default for interactive use,
109  for systematic use, it is often better for the caller to verify explicitly
110  and report failures in a more robust fashion. Set this to True if doing this
111  in order to avoid running a redundant verification. If the IR is actually
112  invalid, behavior is undefined.
113  skip_regions: Whether to skip printing regions. Defaults to False.
114 )";
115 
116 static const char kOperationPrintStateDocstring[] =
117  R"(Prints the assembly form of the operation to a file like object.
118 
119 Args:
120  file: The file like object to write to. Defaults to sys.stdout.
121  binary: Whether to write bytes (True) or str (False). Defaults to False.
122  state: AsmState capturing the operation numbering and flags.
123 )";
124 
125 static const char kOperationGetAsmDocstring[] =
126  R"(Gets the assembly form of the operation with all options available.
127 
128 Args:
129  binary: Whether to return a bytes (True) or str (False) object. Defaults to
130  False.
131  ... others ...: See the print() method for common keyword arguments for
132  configuring the printout.
133 Returns:
134  Either a bytes or str object, depending on the setting of the 'binary'
135  argument.
136 )";
137 
138 static const char kOperationPrintBytecodeDocstring[] =
139  R"(Write the bytecode form of the operation to a file like object.
140 
141 Args:
142  file: The file like object to write to.
143  desired_version: The version of bytecode to emit.
144 Returns:
145  The bytecode writer status.
146 )";
147 
148 static const char kOperationStrDunderDocstring[] =
149  R"(Gets the assembly form of the operation with default options.
150 
151 If more advanced control over the assembly formatting or I/O options is needed,
152 use the dedicated print or get_asm method, which supports keyword arguments to
153 customize behavior.
154 )";
155 
156 static const char kDumpDocstring[] =
157  R"(Dumps a debug representation of the object to stderr.)";
158 
159 static const char kAppendBlockDocstring[] =
160  R"(Appends a new block, with argument types as positional args.
161 
162 Returns:
163  The created block.
164 )";
165 
166 static const char kValueDunderStrDocstring[] =
167  R"(Returns the string form of the value.
168 
169 If the value is a block argument, this is the assembly form of its type and the
170 position in the argument list. If the value is an operation result, this is
171 equivalent to printing the operation that produced it.
172 )";
173 
174 static const char kGetNameAsOperand[] =
175  R"(Returns the string form of value as an operand (i.e., the ValueID).
176 )";
177 
179  R"(Replace all uses of value with the new value, updating anything in
180 the IR that uses 'self' to use the other value instead.
181 )";
182 
184  R"("Replace all uses of this value with the 'with' value, except for those
185 in 'exceptions'. 'exceptions' can be either a single operation or a list of
186 operations.
187 )";
188 
189 //------------------------------------------------------------------------------
190 // Utilities.
191 //------------------------------------------------------------------------------
192 
193 /// Helper for creating an @classmethod.
194 template <class Func, typename... Args>
195 nb::object classmethod(Func f, Args... args) {
196  nb::object cf = nb::cpp_function(f, args...);
197  return nb::borrow<nb::object>((PyClassMethod_New(cf.ptr())));
198 }
199 
200 static nb::object
201 createCustomDialectWrapper(const std::string &dialectNamespace,
202  nb::object dialectDescriptor) {
203  auto dialectClass = PyGlobals::get().lookupDialectClass(dialectNamespace);
204  if (!dialectClass) {
205  // Use the base class.
206  return nb::cast(PyDialect(std::move(dialectDescriptor)));
207  }
208 
209  // Create the custom implementation.
210  return (*dialectClass)(std::move(dialectDescriptor));
211 }
212 
213 static MlirStringRef toMlirStringRef(const std::string &s) {
214  return mlirStringRefCreate(s.data(), s.size());
215 }
216 
217 static MlirStringRef toMlirStringRef(std::string_view s) {
218  return mlirStringRefCreate(s.data(), s.size());
219 }
220 
221 static MlirStringRef toMlirStringRef(const nb::bytes &s) {
222  return mlirStringRefCreate(static_cast<const char *>(s.data()), s.size());
223 }
224 
225 /// Create a block, using the current location context if no locations are
226 /// specified.
227 static MlirBlock createBlock(const nb::sequence &pyArgTypes,
228  const std::optional<nb::sequence> &pyArgLocs) {
229  SmallVector<MlirType> argTypes;
230  argTypes.reserve(nb::len(pyArgTypes));
231  for (const auto &pyType : pyArgTypes)
232  argTypes.push_back(nb::cast<PyType &>(pyType));
233 
235  if (pyArgLocs) {
236  argLocs.reserve(nb::len(*pyArgLocs));
237  for (const auto &pyLoc : *pyArgLocs)
238  argLocs.push_back(nb::cast<PyLocation &>(pyLoc));
239  } else if (!argTypes.empty()) {
240  argLocs.assign(argTypes.size(), DefaultingPyLocation::resolve());
241  }
242 
243  if (argTypes.size() != argLocs.size())
244  throw nb::value_error(("Expected " + Twine(argTypes.size()) +
245  " locations, got: " + Twine(argLocs.size()))
246  .str()
247  .c_str());
248  return mlirBlockCreate(argTypes.size(), argTypes.data(), argLocs.data());
249 }
250 
251 /// Wrapper for the global LLVM debugging flag.
253  static void set(nb::object &o, bool enable) {
254  nb::ft_lock_guard lock(mutex);
255  mlirEnableGlobalDebug(enable);
256  }
257 
258  static bool get(const nb::object &) {
259  nb::ft_lock_guard lock(mutex);
260  return mlirIsGlobalDebugEnabled();
261  }
262 
263  static void bind(nb::module_ &m) {
264  // Debug flags.
265  nb::class_<PyGlobalDebugFlag>(m, "_GlobalDebug")
266  .def_prop_rw_static("flag", &PyGlobalDebugFlag::get,
267  &PyGlobalDebugFlag::set, "LLVM-wide debug flag")
268  .def_static(
269  "set_types",
270  [](const std::string &type) {
271  nb::ft_lock_guard lock(mutex);
272  mlirSetGlobalDebugType(type.c_str());
273  },
274  "types"_a, "Sets specific debug types to be produced by LLVM")
275  .def_static("set_types", [](const std::vector<std::string> &types) {
276  std::vector<const char *> pointers;
277  pointers.reserve(types.size());
278  for (const std::string &str : types)
279  pointers.push_back(str.c_str());
280  nb::ft_lock_guard lock(mutex);
281  mlirSetGlobalDebugTypes(pointers.data(), pointers.size());
282  });
283  }
284 
285 private:
286  static nb::ft_mutex mutex;
287 };
288 
289 nb::ft_mutex PyGlobalDebugFlag::mutex;
290 
292  static bool dunderContains(const std::string &attributeKind) {
293  return PyGlobals::get().lookupAttributeBuilder(attributeKind).has_value();
294  }
295  static nb::callable dunderGetItemNamed(const std::string &attributeKind) {
296  auto builder = PyGlobals::get().lookupAttributeBuilder(attributeKind);
297  if (!builder)
298  throw nb::key_error(attributeKind.c_str());
299  return *builder;
300  }
301  static void dunderSetItemNamed(const std::string &attributeKind,
302  nb::callable func, bool replace) {
303  PyGlobals::get().registerAttributeBuilder(attributeKind, std::move(func),
304  replace);
305  }
306 
307  static void bind(nb::module_ &m) {
308  nb::class_<PyAttrBuilderMap>(m, "AttrBuilder")
309  .def_static("contains", &PyAttrBuilderMap::dunderContains)
310  .def_static("get", &PyAttrBuilderMap::dunderGetItemNamed)
311  .def_static("insert", &PyAttrBuilderMap::dunderSetItemNamed,
312  "attribute_kind"_a, "attr_builder"_a, "replace"_a = false,
313  "Register an attribute builder for building MLIR "
314  "attributes from python values.");
315  }
316 };
317 
318 //------------------------------------------------------------------------------
319 // PyBlock
320 //------------------------------------------------------------------------------
321 
322 nb::object PyBlock::getCapsule() {
323  return nb::steal<nb::object>(mlirPythonBlockToCapsule(get()));
324 }
325 
326 //------------------------------------------------------------------------------
327 // Collections.
328 //------------------------------------------------------------------------------
329 
330 namespace {
331 
332 class PyRegionIterator {
333 public:
334  PyRegionIterator(PyOperationRef operation)
335  : operation(std::move(operation)) {}
336 
337  PyRegionIterator &dunderIter() { return *this; }
338 
339  PyRegion dunderNext() {
340  operation->checkValid();
341  if (nextIndex >= mlirOperationGetNumRegions(operation->get())) {
342  throw nb::stop_iteration();
343  }
344  MlirRegion region = mlirOperationGetRegion(operation->get(), nextIndex++);
345  return PyRegion(operation, region);
346  }
347 
348  static void bind(nb::module_ &m) {
349  nb::class_<PyRegionIterator>(m, "RegionIterator")
350  .def("__iter__", &PyRegionIterator::dunderIter)
351  .def("__next__", &PyRegionIterator::dunderNext);
352  }
353 
354 private:
355  PyOperationRef operation;
356  int nextIndex = 0;
357 };
358 
359 /// Regions of an op are fixed length and indexed numerically so are represented
360 /// with a sequence-like container.
361 class PyRegionList {
362 public:
363  PyRegionList(PyOperationRef operation) : operation(std::move(operation)) {}
364 
365  PyRegionIterator dunderIter() {
366  operation->checkValid();
367  return PyRegionIterator(operation);
368  }
369 
370  intptr_t dunderLen() {
371  operation->checkValid();
372  return mlirOperationGetNumRegions(operation->get());
373  }
374 
375  PyRegion dunderGetItem(intptr_t index) {
376  // dunderLen checks validity.
377  if (index < 0 || index >= dunderLen()) {
378  throw nb::index_error("attempt to access out of bounds region");
379  }
380  MlirRegion region = mlirOperationGetRegion(operation->get(), index);
381  return PyRegion(operation, region);
382  }
383 
384  static void bind(nb::module_ &m) {
385  nb::class_<PyRegionList>(m, "RegionSequence")
386  .def("__len__", &PyRegionList::dunderLen)
387  .def("__iter__", &PyRegionList::dunderIter)
388  .def("__getitem__", &PyRegionList::dunderGetItem);
389  }
390 
391 private:
392  PyOperationRef operation;
393 };
394 
395 class PyBlockIterator {
396 public:
397  PyBlockIterator(PyOperationRef operation, MlirBlock next)
398  : operation(std::move(operation)), next(next) {}
399 
400  PyBlockIterator &dunderIter() { return *this; }
401 
402  PyBlock dunderNext() {
403  operation->checkValid();
404  if (mlirBlockIsNull(next)) {
405  throw nb::stop_iteration();
406  }
407 
408  PyBlock returnBlock(operation, next);
409  next = mlirBlockGetNextInRegion(next);
410  return returnBlock;
411  }
412 
413  static void bind(nb::module_ &m) {
414  nb::class_<PyBlockIterator>(m, "BlockIterator")
415  .def("__iter__", &PyBlockIterator::dunderIter)
416  .def("__next__", &PyBlockIterator::dunderNext);
417  }
418 
419 private:
420  PyOperationRef operation;
421  MlirBlock next;
422 };
423 
424 /// Blocks are exposed by the C-API as a forward-only linked list. In Python,
425 /// we present them as a more full-featured list-like container but optimize
426 /// it for forward iteration. Blocks are always owned by a region.
427 class PyBlockList {
428 public:
429  PyBlockList(PyOperationRef operation, MlirRegion region)
430  : operation(std::move(operation)), region(region) {}
431 
432  PyBlockIterator dunderIter() {
433  operation->checkValid();
434  return PyBlockIterator(operation, mlirRegionGetFirstBlock(region));
435  }
436 
437  intptr_t dunderLen() {
438  operation->checkValid();
439  intptr_t count = 0;
440  MlirBlock block = mlirRegionGetFirstBlock(region);
441  while (!mlirBlockIsNull(block)) {
442  count += 1;
443  block = mlirBlockGetNextInRegion(block);
444  }
445  return count;
446  }
447 
448  PyBlock dunderGetItem(intptr_t index) {
449  operation->checkValid();
450  if (index < 0) {
451  throw nb::index_error("attempt to access out of bounds block");
452  }
453  MlirBlock block = mlirRegionGetFirstBlock(region);
454  while (!mlirBlockIsNull(block)) {
455  if (index == 0) {
456  return PyBlock(operation, block);
457  }
458  block = mlirBlockGetNextInRegion(block);
459  index -= 1;
460  }
461  throw nb::index_error("attempt to access out of bounds block");
462  }
463 
464  PyBlock appendBlock(const nb::args &pyArgTypes,
465  const std::optional<nb::sequence> &pyArgLocs) {
466  operation->checkValid();
467  MlirBlock block =
468  createBlock(nb::cast<nb::sequence>(pyArgTypes), pyArgLocs);
469  mlirRegionAppendOwnedBlock(region, block);
470  return PyBlock(operation, block);
471  }
472 
473  static void bind(nb::module_ &m) {
474  nb::class_<PyBlockList>(m, "BlockList")
475  .def("__getitem__", &PyBlockList::dunderGetItem)
476  .def("__iter__", &PyBlockList::dunderIter)
477  .def("__len__", &PyBlockList::dunderLen)
478  .def("append", &PyBlockList::appendBlock, kAppendBlockDocstring,
479  nb::arg("args"), nb::kw_only(),
480  nb::arg("arg_locs") = std::nullopt);
481  }
482 
483 private:
484  PyOperationRef operation;
485  MlirRegion region;
486 };
487 
488 class PyOperationIterator {
489 public:
490  PyOperationIterator(PyOperationRef parentOperation, MlirOperation next)
491  : parentOperation(std::move(parentOperation)), next(next) {}
492 
493  PyOperationIterator &dunderIter() { return *this; }
494 
495  nb::object dunderNext() {
496  parentOperation->checkValid();
497  if (mlirOperationIsNull(next)) {
498  throw nb::stop_iteration();
499  }
500 
501  PyOperationRef returnOperation =
502  PyOperation::forOperation(parentOperation->getContext(), next);
503  next = mlirOperationGetNextInBlock(next);
504  return returnOperation->createOpView();
505  }
506 
507  static void bind(nb::module_ &m) {
508  nb::class_<PyOperationIterator>(m, "OperationIterator")
509  .def("__iter__", &PyOperationIterator::dunderIter)
510  .def("__next__", &PyOperationIterator::dunderNext);
511  }
512 
513 private:
514  PyOperationRef parentOperation;
515  MlirOperation next;
516 };
517 
518 /// Operations are exposed by the C-API as a forward-only linked list. In
519 /// Python, we present them as a more full-featured list-like container but
520 /// optimize it for forward iteration. Iterable operations are always owned
521 /// by a block.
522 class PyOperationList {
523 public:
524  PyOperationList(PyOperationRef parentOperation, MlirBlock block)
525  : parentOperation(std::move(parentOperation)), block(block) {}
526 
527  PyOperationIterator dunderIter() {
528  parentOperation->checkValid();
529  return PyOperationIterator(parentOperation,
531  }
532 
533  intptr_t dunderLen() {
534  parentOperation->checkValid();
535  intptr_t count = 0;
536  MlirOperation childOp = mlirBlockGetFirstOperation(block);
537  while (!mlirOperationIsNull(childOp)) {
538  count += 1;
539  childOp = mlirOperationGetNextInBlock(childOp);
540  }
541  return count;
542  }
543 
544  nb::object dunderGetItem(intptr_t index) {
545  parentOperation->checkValid();
546  if (index < 0) {
547  throw nb::index_error("attempt to access out of bounds operation");
548  }
549  MlirOperation childOp = mlirBlockGetFirstOperation(block);
550  while (!mlirOperationIsNull(childOp)) {
551  if (index == 0) {
552  return PyOperation::forOperation(parentOperation->getContext(), childOp)
553  ->createOpView();
554  }
555  childOp = mlirOperationGetNextInBlock(childOp);
556  index -= 1;
557  }
558  throw nb::index_error("attempt to access out of bounds operation");
559  }
560 
561  static void bind(nb::module_ &m) {
562  nb::class_<PyOperationList>(m, "OperationList")
563  .def("__getitem__", &PyOperationList::dunderGetItem)
564  .def("__iter__", &PyOperationList::dunderIter)
565  .def("__len__", &PyOperationList::dunderLen);
566  }
567 
568 private:
569  PyOperationRef parentOperation;
570  MlirBlock block;
571 };
572 
573 class PyOpOperand {
574 public:
575  PyOpOperand(MlirOpOperand opOperand) : opOperand(opOperand) {}
576 
577  nb::object getOwner() {
578  MlirOperation owner = mlirOpOperandGetOwner(opOperand);
579  PyMlirContextRef context =
580  PyMlirContext::forContext(mlirOperationGetContext(owner));
581  return PyOperation::forOperation(context, owner)->createOpView();
582  }
583 
584  size_t getOperandNumber() { return mlirOpOperandGetOperandNumber(opOperand); }
585 
586  static void bind(nb::module_ &m) {
587  nb::class_<PyOpOperand>(m, "OpOperand")
588  .def_prop_ro("owner", &PyOpOperand::getOwner)
589  .def_prop_ro("operand_number", &PyOpOperand::getOperandNumber);
590  }
591 
592 private:
593  MlirOpOperand opOperand;
594 };
595 
596 class PyOpOperandIterator {
597 public:
598  PyOpOperandIterator(MlirOpOperand opOperand) : opOperand(opOperand) {}
599 
600  PyOpOperandIterator &dunderIter() { return *this; }
601 
602  PyOpOperand dunderNext() {
603  if (mlirOpOperandIsNull(opOperand))
604  throw nb::stop_iteration();
605 
606  PyOpOperand returnOpOperand(opOperand);
607  opOperand = mlirOpOperandGetNextUse(opOperand);
608  return returnOpOperand;
609  }
610 
611  static void bind(nb::module_ &m) {
612  nb::class_<PyOpOperandIterator>(m, "OpOperandIterator")
613  .def("__iter__", &PyOpOperandIterator::dunderIter)
614  .def("__next__", &PyOpOperandIterator::dunderNext);
615  }
616 
617 private:
618  MlirOpOperand opOperand;
619 };
620 
621 } // namespace
622 
623 //------------------------------------------------------------------------------
624 // PyMlirContext
625 //------------------------------------------------------------------------------
626 
627 PyMlirContext::PyMlirContext(MlirContext context) : context(context) {
628  nb::gil_scoped_acquire acquire;
629  nb::ft_lock_guard lock(live_contexts_mutex);
630  auto &liveContexts = getLiveContexts();
631  liveContexts[context.ptr] = this;
632 }
633 
635  // Note that the only public way to construct an instance is via the
636  // forContext method, which always puts the associated handle into
637  // liveContexts.
638  nb::gil_scoped_acquire acquire;
639  {
640  nb::ft_lock_guard lock(live_contexts_mutex);
641  getLiveContexts().erase(context.ptr);
642  }
643  mlirContextDestroy(context);
644 }
645 
647  return nb::steal<nb::object>(mlirPythonContextToCapsule(get()));
648 }
649 
650 nb::object PyMlirContext::createFromCapsule(nb::object capsule) {
651  MlirContext rawContext = mlirPythonCapsuleToContext(capsule.ptr());
652  if (mlirContextIsNull(rawContext))
653  throw nb::python_error();
654  return forContext(rawContext).releaseObject();
655 }
656 
658  nb::gil_scoped_acquire acquire;
659  nb::ft_lock_guard lock(live_contexts_mutex);
660  auto &liveContexts = getLiveContexts();
661  auto it = liveContexts.find(context.ptr);
662  if (it == liveContexts.end()) {
663  // Create.
664  PyMlirContext *unownedContextWrapper = new PyMlirContext(context);
665  nb::object pyRef = nb::cast(unownedContextWrapper);
666  assert(pyRef && "cast to nb::object failed");
667  liveContexts[context.ptr] = unownedContextWrapper;
668  return PyMlirContextRef(unownedContextWrapper, std::move(pyRef));
669  }
670  // Use existing.
671  nb::object pyRef = nb::cast(it->second);
672  return PyMlirContextRef(it->second, std::move(pyRef));
673 }
674 
675 nb::ft_mutex PyMlirContext::live_contexts_mutex;
676 
677 PyMlirContext::LiveContextMap &PyMlirContext::getLiveContexts() {
678  static LiveContextMap liveContexts;
679  return liveContexts;
680 }
681 
683  nb::ft_lock_guard lock(live_contexts_mutex);
684  return getLiveContexts().size();
685 }
686 
688  nb::ft_lock_guard lock(liveOperationsMutex);
689  return liveOperations.size();
690 }
691 
692 std::vector<PyOperation *> PyMlirContext::getLiveOperationObjects() {
693  std::vector<PyOperation *> liveObjects;
694  nb::ft_lock_guard lock(liveOperationsMutex);
695  for (auto &entry : liveOperations)
696  liveObjects.push_back(entry.second.second);
697  return liveObjects;
698 }
699 
701 
702  LiveOperationMap operations;
703  {
704  nb::ft_lock_guard lock(liveOperationsMutex);
705  std::swap(operations, liveOperations);
706  }
707  for (auto &op : operations)
708  op.second.second->setInvalid();
709  size_t numInvalidated = operations.size();
710  return numInvalidated;
711 }
712 
713 void PyMlirContext::clearOperation(MlirOperation op) {
714  PyOperation *py_op;
715  {
716  nb::ft_lock_guard lock(liveOperationsMutex);
717  auto it = liveOperations.find(op.ptr);
718  if (it == liveOperations.end()) {
719  return;
720  }
721  py_op = it->second.second;
722  liveOperations.erase(it);
723  }
724  py_op->setInvalid();
725 }
726 
728  typedef struct {
729  PyOperation &rootOp;
730  bool rootSeen;
731  } callBackData;
732  callBackData data{op.getOperation(), false};
733  // Mark all ops below the op that the passmanager will be rooted
734  // at (but not op itself - note the preorder) as invalid.
735  MlirOperationWalkCallback invalidatingCallback = [](MlirOperation op,
736  void *userData) {
737  callBackData *data = static_cast<callBackData *>(userData);
738  if (LLVM_LIKELY(data->rootSeen))
739  data->rootOp.getOperation().getContext()->clearOperation(op);
740  else
741  data->rootSeen = true;
743  };
744  mlirOperationWalk(op.getOperation(), invalidatingCallback,
745  static_cast<void *>(&data), MlirWalkPreOrder);
746 }
747 void PyMlirContext::clearOperationsInside(MlirOperation op) {
750 }
751 
753  MlirOperationWalkCallback invalidatingCallback = [](MlirOperation op,
754  void *userData) {
755  PyMlirContextRef &contextRef = *static_cast<PyMlirContextRef *>(userData);
756  contextRef->clearOperation(op);
758  };
759  mlirOperationWalk(op.getOperation(), invalidatingCallback,
761 }
762 
763 size_t PyMlirContext::getLiveModuleCount() { return liveModules.size(); }
764 
765 nb::object PyMlirContext::contextEnter(nb::object context) {
766  return PyThreadContextEntry::pushContext(context);
767 }
768 
769 void PyMlirContext::contextExit(const nb::object &excType,
770  const nb::object &excVal,
771  const nb::object &excTb) {
773 }
774 
775 nb::object PyMlirContext::attachDiagnosticHandler(nb::object callback) {
776  // Note that ownership is transferred to the delete callback below by way of
777  // an explicit inc_ref (borrow).
778  PyDiagnosticHandler *pyHandler =
779  new PyDiagnosticHandler(get(), std::move(callback));
780  nb::object pyHandlerObject =
781  nb::cast(pyHandler, nb::rv_policy::take_ownership);
782  pyHandlerObject.inc_ref();
783 
784  // In these C callbacks, the userData is a PyDiagnosticHandler* that is
785  // guaranteed to be known to pybind.
786  auto handlerCallback =
787  +[](MlirDiagnostic diagnostic, void *userData) -> MlirLogicalResult {
788  PyDiagnostic *pyDiagnostic = new PyDiagnostic(diagnostic);
789  nb::object pyDiagnosticObject =
790  nb::cast(pyDiagnostic, nb::rv_policy::take_ownership);
791 
792  auto *pyHandler = static_cast<PyDiagnosticHandler *>(userData);
793  bool result = false;
794  {
795  // Since this can be called from arbitrary C++ contexts, always get the
796  // gil.
797  nb::gil_scoped_acquire gil;
798  try {
799  result = nb::cast<bool>(pyHandler->callback(pyDiagnostic));
800  } catch (std::exception &e) {
801  fprintf(stderr, "MLIR Python Diagnostic handler raised exception: %s\n",
802  e.what());
803  pyHandler->hadError = true;
804  }
805  }
806 
807  pyDiagnostic->invalidate();
809  };
810  auto deleteCallback = +[](void *userData) {
811  auto *pyHandler = static_cast<PyDiagnosticHandler *>(userData);
812  assert(pyHandler->registeredID && "handler is not registered");
813  pyHandler->registeredID.reset();
814 
815  // Decrement reference, balancing the inc_ref() above.
816  nb::object pyHandlerObject = nb::cast(pyHandler, nb::rv_policy::reference);
817  pyHandlerObject.dec_ref();
818  };
819 
820  pyHandler->registeredID = mlirContextAttachDiagnosticHandler(
821  get(), handlerCallback, static_cast<void *>(pyHandler), deleteCallback);
822  return pyHandlerObject;
823 }
824 
825 MlirLogicalResult PyMlirContext::ErrorCapture::handler(MlirDiagnostic diag,
826  void *userData) {
827  auto *self = static_cast<ErrorCapture *>(userData);
828  // Check if the context requested we emit errors instead of capturing them.
829  if (self->ctx->emitErrorDiagnostics)
830  return mlirLogicalResultFailure();
831 
833  return mlirLogicalResultFailure();
834 
835  self->errors.emplace_back(PyDiagnostic(diag).getInfo());
836  return mlirLogicalResultSuccess();
837 }
838 
841  if (!context) {
842  throw std::runtime_error(
843  "An MLIR function requires a Context but none was provided in the call "
844  "or from the surrounding environment. Either pass to the function with "
845  "a 'context=' argument or establish a default using 'with Context():'");
846  }
847  return *context;
848 }
849 
850 //------------------------------------------------------------------------------
851 // PyThreadContextEntry management
852 //------------------------------------------------------------------------------
853 
854 std::vector<PyThreadContextEntry> &PyThreadContextEntry::getStack() {
855  static thread_local std::vector<PyThreadContextEntry> stack;
856  return stack;
857 }
858 
860  auto &stack = getStack();
861  if (stack.empty())
862  return nullptr;
863  return &stack.back();
864 }
865 
866 void PyThreadContextEntry::push(FrameKind frameKind, nb::object context,
867  nb::object insertionPoint,
868  nb::object location) {
869  auto &stack = getStack();
870  stack.emplace_back(frameKind, std::move(context), std::move(insertionPoint),
871  std::move(location));
872  // If the new stack has more than one entry and the context of the new top
873  // entry matches the previous, copy the insertionPoint and location from the
874  // previous entry if missing from the new top entry.
875  if (stack.size() > 1) {
876  auto &prev = *(stack.rbegin() + 1);
877  auto &current = stack.back();
878  if (current.context.is(prev.context)) {
879  // Default non-context objects from the previous entry.
880  if (!current.insertionPoint)
881  current.insertionPoint = prev.insertionPoint;
882  if (!current.location)
883  current.location = prev.location;
884  }
885  }
886 }
887 
889  if (!context)
890  return nullptr;
891  return nb::cast<PyMlirContext *>(context);
892 }
893 
895  if (!insertionPoint)
896  return nullptr;
897  return nb::cast<PyInsertionPoint *>(insertionPoint);
898 }
899 
901  if (!location)
902  return nullptr;
903  return nb::cast<PyLocation *>(location);
904 }
905 
907  auto *tos = getTopOfStack();
908  return tos ? tos->getContext() : nullptr;
909 }
910 
912  auto *tos = getTopOfStack();
913  return tos ? tos->getInsertionPoint() : nullptr;
914 }
915 
917  auto *tos = getTopOfStack();
918  return tos ? tos->getLocation() : nullptr;
919 }
920 
921 nb::object PyThreadContextEntry::pushContext(nb::object context) {
922  push(FrameKind::Context, /*context=*/context,
923  /*insertionPoint=*/nb::object(),
924  /*location=*/nb::object());
925  return context;
926 }
927 
929  auto &stack = getStack();
930  if (stack.empty())
931  throw std::runtime_error("Unbalanced Context enter/exit");
932  auto &tos = stack.back();
933  if (tos.frameKind != FrameKind::Context && tos.getContext() != &context)
934  throw std::runtime_error("Unbalanced Context enter/exit");
935  stack.pop_back();
936 }
937 
938 nb::object
939 PyThreadContextEntry::pushInsertionPoint(nb::object insertionPointObj) {
940  PyInsertionPoint &insertionPoint =
941  nb::cast<PyInsertionPoint &>(insertionPointObj);
942  nb::object contextObj =
943  insertionPoint.getBlock().getParentOperation()->getContext().getObject();
944  push(FrameKind::InsertionPoint,
945  /*context=*/contextObj,
946  /*insertionPoint=*/insertionPointObj,
947  /*location=*/nb::object());
948  return insertionPointObj;
949 }
950 
952  auto &stack = getStack();
953  if (stack.empty())
954  throw std::runtime_error("Unbalanced InsertionPoint enter/exit");
955  auto &tos = stack.back();
956  if (tos.frameKind != FrameKind::InsertionPoint &&
957  tos.getInsertionPoint() != &insertionPoint)
958  throw std::runtime_error("Unbalanced InsertionPoint enter/exit");
959  stack.pop_back();
960 }
961 
962 nb::object PyThreadContextEntry::pushLocation(nb::object locationObj) {
963  PyLocation &location = nb::cast<PyLocation &>(locationObj);
964  nb::object contextObj = location.getContext().getObject();
965  push(FrameKind::Location, /*context=*/contextObj,
966  /*insertionPoint=*/nb::object(),
967  /*location=*/locationObj);
968  return locationObj;
969 }
970 
972  auto &stack = getStack();
973  if (stack.empty())
974  throw std::runtime_error("Unbalanced Location enter/exit");
975  auto &tos = stack.back();
976  if (tos.frameKind != FrameKind::Location && tos.getLocation() != &location)
977  throw std::runtime_error("Unbalanced Location enter/exit");
978  stack.pop_back();
979 }
980 
981 //------------------------------------------------------------------------------
982 // PyDiagnostic*
983 //------------------------------------------------------------------------------
984 
986  valid = false;
987  if (materializedNotes) {
988  for (nb::handle noteObject : *materializedNotes) {
989  PyDiagnostic *note = nb::cast<PyDiagnostic *>(noteObject);
990  note->invalidate();
991  }
992  }
993 }
994 
996  nb::object callback)
997  : context(context), callback(std::move(callback)) {}
998 
1000 
1002  if (!registeredID)
1003  return;
1004  MlirDiagnosticHandlerID localID = *registeredID;
1005  mlirContextDetachDiagnosticHandler(context, localID);
1006  assert(!registeredID && "should have unregistered");
1007  // Not strictly necessary but keeps stale pointers from being around to cause
1008  // issues.
1009  context = {nullptr};
1010 }
1011 
1012 void PyDiagnostic::checkValid() {
1013  if (!valid) {
1014  throw std::invalid_argument(
1015  "Diagnostic is invalid (used outside of callback)");
1016  }
1017 }
1018 
1020  checkValid();
1021  return mlirDiagnosticGetSeverity(diagnostic);
1022 }
1023 
1025  checkValid();
1026  MlirLocation loc = mlirDiagnosticGetLocation(diagnostic);
1027  MlirContext context = mlirLocationGetContext(loc);
1028  return PyLocation(PyMlirContext::forContext(context), loc);
1029 }
1030 
1032  checkValid();
1033  nb::object fileObject = nb::module_::import_("io").attr("StringIO")();
1034  PyFileAccumulator accum(fileObject, /*binary=*/false);
1035  mlirDiagnosticPrint(diagnostic, accum.getCallback(), accum.getUserData());
1036  return nb::cast<nb::str>(fileObject.attr("getvalue")());
1037 }
1038 
1040  checkValid();
1041  if (materializedNotes)
1042  return *materializedNotes;
1043  intptr_t numNotes = mlirDiagnosticGetNumNotes(diagnostic);
1044  nb::tuple notes = nb::steal<nb::tuple>(PyTuple_New(numNotes));
1045  for (intptr_t i = 0; i < numNotes; ++i) {
1046  MlirDiagnostic noteDiag = mlirDiagnosticGetNote(diagnostic, i);
1047  nb::object diagnostic = nb::cast(PyDiagnostic(noteDiag));
1048  PyTuple_SET_ITEM(notes.ptr(), i, diagnostic.release().ptr());
1049  }
1050  materializedNotes = std::move(notes);
1051 
1052  return *materializedNotes;
1053 }
1054 
1056  std::vector<DiagnosticInfo> notes;
1057  for (nb::handle n : getNotes())
1058  notes.emplace_back(nb::cast<PyDiagnostic>(n).getInfo());
1059  return {getSeverity(), getLocation(), nb::cast<std::string>(getMessage()),
1060  std::move(notes)};
1061 }
1062 
1063 //------------------------------------------------------------------------------
1064 // PyDialect, PyDialectDescriptor, PyDialects, PyDialectRegistry
1065 //------------------------------------------------------------------------------
1066 
1067 MlirDialect PyDialects::getDialectForKey(const std::string &key,
1068  bool attrError) {
1069  MlirDialect dialect = mlirContextGetOrLoadDialect(getContext()->get(),
1070  {key.data(), key.size()});
1071  if (mlirDialectIsNull(dialect)) {
1072  std::string msg = (Twine("Dialect '") + key + "' not found").str();
1073  if (attrError)
1074  throw nb::attribute_error(msg.c_str());
1075  throw nb::index_error(msg.c_str());
1076  }
1077  return dialect;
1078 }
1079 
1081  return nb::steal<nb::object>(mlirPythonDialectRegistryToCapsule(*this));
1082 }
1083 
1085  MlirDialectRegistry rawRegistry =
1086  mlirPythonCapsuleToDialectRegistry(capsule.ptr());
1087  if (mlirDialectRegistryIsNull(rawRegistry))
1088  throw nb::python_error();
1089  return PyDialectRegistry(rawRegistry);
1090 }
1091 
1092 //------------------------------------------------------------------------------
1093 // PyLocation
1094 //------------------------------------------------------------------------------
1095 
1097  return nb::steal<nb::object>(mlirPythonLocationToCapsule(*this));
1098 }
1099 
1101  MlirLocation rawLoc = mlirPythonCapsuleToLocation(capsule.ptr());
1102  if (mlirLocationIsNull(rawLoc))
1103  throw nb::python_error();
1105  rawLoc);
1106 }
1107 
1108 nb::object PyLocation::contextEnter(nb::object locationObj) {
1109  return PyThreadContextEntry::pushLocation(locationObj);
1110 }
1111 
1112 void PyLocation::contextExit(const nb::object &excType,
1113  const nb::object &excVal,
1114  const nb::object &excTb) {
1116 }
1117 
1119  auto *location = PyThreadContextEntry::getDefaultLocation();
1120  if (!location) {
1121  throw std::runtime_error(
1122  "An MLIR function requires a Location but none was provided in the "
1123  "call or from the surrounding environment. Either pass to the function "
1124  "with a 'loc=' argument or establish a default using 'with loc:'");
1125  }
1126  return *location;
1127 }
1128 
1129 //------------------------------------------------------------------------------
1130 // PyModule
1131 //------------------------------------------------------------------------------
1132 
1133 PyModule::PyModule(PyMlirContextRef contextRef, MlirModule module)
1134  : BaseContextObject(std::move(contextRef)), module(module) {}
1135 
1137  nb::gil_scoped_acquire acquire;
1138  auto &liveModules = getContext()->liveModules;
1139  assert(liveModules.count(module.ptr) == 1 &&
1140  "destroying module not in live map");
1141  liveModules.erase(module.ptr);
1142  mlirModuleDestroy(module);
1143 }
1144 
1145 PyModuleRef PyModule::forModule(MlirModule module) {
1146  MlirContext context = mlirModuleGetContext(module);
1147  PyMlirContextRef contextRef = PyMlirContext::forContext(context);
1148 
1149  nb::gil_scoped_acquire acquire;
1150  auto &liveModules = contextRef->liveModules;
1151  auto it = liveModules.find(module.ptr);
1152  if (it == liveModules.end()) {
1153  // Create.
1154  PyModule *unownedModule = new PyModule(std::move(contextRef), module);
1155  // Note that the default return value policy on cast is automatic_reference,
1156  // which does not take ownership (delete will not be called).
1157  // Just be explicit.
1158  nb::object pyRef = nb::cast(unownedModule, nb::rv_policy::take_ownership);
1159  unownedModule->handle = pyRef;
1160  liveModules[module.ptr] =
1161  std::make_pair(unownedModule->handle, unownedModule);
1162  return PyModuleRef(unownedModule, std::move(pyRef));
1163  }
1164  // Use existing.
1165  PyModule *existing = it->second.second;
1166  nb::object pyRef = nb::borrow<nb::object>(it->second.first);
1167  return PyModuleRef(existing, std::move(pyRef));
1168 }
1169 
1170 nb::object PyModule::createFromCapsule(nb::object capsule) {
1171  MlirModule rawModule = mlirPythonCapsuleToModule(capsule.ptr());
1172  if (mlirModuleIsNull(rawModule))
1173  throw nb::python_error();
1174  return forModule(rawModule).releaseObject();
1175 }
1176 
1177 nb::object PyModule::getCapsule() {
1178  return nb::steal<nb::object>(mlirPythonModuleToCapsule(get()));
1179 }
1180 
1181 //------------------------------------------------------------------------------
1182 // PyOperation
1183 //------------------------------------------------------------------------------
1184 
1185 PyOperation::PyOperation(PyMlirContextRef contextRef, MlirOperation operation)
1186  : BaseContextObject(std::move(contextRef)), operation(operation) {}
1187 
1189  // If the operation has already been invalidated there is nothing to do.
1190  if (!valid)
1191  return;
1192 
1193  // Otherwise, invalidate the operation and remove it from live map when it is
1194  // attached.
1195  if (isAttached()) {
1196  getContext()->clearOperation(*this);
1197  } else {
1198  // And destroy it when it is detached, i.e. owned by Python, in which case
1199  // all nested operations must be invalidated at removed from the live map as
1200  // well.
1201  erase();
1202  }
1203 }
1204 
1205 namespace {
1206 
1207 // Constructs a new object of type T in-place on the Python heap, returning a
1208 // PyObjectRef to it, loosely analogous to std::make_shared<T>().
1209 template <typename T, class... Args>
1210 PyObjectRef<T> makeObjectRef(Args &&...args) {
1211  nb::handle type = nb::type<T>();
1212  nb::object instance = nb::inst_alloc(type);
1213  T *ptr = nb::inst_ptr<T>(instance);
1214  new (ptr) T(std::forward<Args>(args)...);
1215  nb::inst_mark_ready(instance);
1216  return PyObjectRef<T>(ptr, std::move(instance));
1217 }
1218 
1219 } // namespace
1220 
1221 PyOperationRef PyOperation::createInstance(PyMlirContextRef contextRef,
1222  MlirOperation operation,
1223  nb::object parentKeepAlive) {
1224  // Create.
1225  PyOperationRef unownedOperation =
1226  makeObjectRef<PyOperation>(std::move(contextRef), operation);
1227  unownedOperation->handle = unownedOperation.getObject();
1228  if (parentKeepAlive) {
1229  unownedOperation->parentKeepAlive = std::move(parentKeepAlive);
1230  }
1231  return unownedOperation;
1232 }
1233 
1235  MlirOperation operation,
1236  nb::object parentKeepAlive) {
1237  nb::ft_lock_guard lock(contextRef->liveOperationsMutex);
1238  auto &liveOperations = contextRef->liveOperations;
1239  auto it = liveOperations.find(operation.ptr);
1240  if (it == liveOperations.end()) {
1241  // Create.
1242  PyOperationRef result = createInstance(std::move(contextRef), operation,
1243  std::move(parentKeepAlive));
1244  liveOperations[operation.ptr] =
1245  std::make_pair(result.getObject(), result.get());
1246  return result;
1247  }
1248  // Use existing.
1249  PyOperation *existing = it->second.second;
1250  nb::object pyRef = nb::borrow<nb::object>(it->second.first);
1251  return PyOperationRef(existing, std::move(pyRef));
1252 }
1253 
1255  MlirOperation operation,
1256  nb::object parentKeepAlive) {
1257  nb::ft_lock_guard lock(contextRef->liveOperationsMutex);
1258  auto &liveOperations = contextRef->liveOperations;
1259  assert(liveOperations.count(operation.ptr) == 0 &&
1260  "cannot create detached operation that already exists");
1261  (void)liveOperations;
1262  PyOperationRef created = createInstance(std::move(contextRef), operation,
1263  std::move(parentKeepAlive));
1264  liveOperations[operation.ptr] =
1265  std::make_pair(created.getObject(), created.get());
1266  created->attached = false;
1267  return created;
1268 }
1269 
1271  const std::string &sourceStr,
1272  const std::string &sourceName) {
1273  PyMlirContext::ErrorCapture errors(contextRef);
1274  MlirOperation op =
1275  mlirOperationCreateParse(contextRef->get(), toMlirStringRef(sourceStr),
1276  toMlirStringRef(sourceName));
1277  if (mlirOperationIsNull(op))
1278  throw MLIRError("Unable to parse operation assembly", errors.take());
1279  return PyOperation::createDetached(std::move(contextRef), op);
1280 }
1281 
1283  if (!valid) {
1284  throw std::runtime_error("the operation has been invalidated");
1285  }
1286 }
1287 
1288 void PyOperationBase::print(std::optional<int64_t> largeElementsLimit,
1289  bool enableDebugInfo, bool prettyDebugInfo,
1290  bool printGenericOpForm, bool useLocalScope,
1291  bool assumeVerified, nb::object fileObject,
1292  bool binary, bool skipRegions) {
1293  PyOperation &operation = getOperation();
1294  operation.checkValid();
1295  if (fileObject.is_none())
1296  fileObject = nb::module_::import_("sys").attr("stdout");
1297 
1298  MlirOpPrintingFlags flags = mlirOpPrintingFlagsCreate();
1299  if (largeElementsLimit) {
1300  mlirOpPrintingFlagsElideLargeElementsAttrs(flags, *largeElementsLimit);
1301  mlirOpPrintingFlagsElideLargeResourceString(flags, *largeElementsLimit);
1302  }
1303  if (enableDebugInfo)
1304  mlirOpPrintingFlagsEnableDebugInfo(flags, /*enable=*/true,
1305  /*prettyForm=*/prettyDebugInfo);
1306  if (printGenericOpForm)
1308  if (useLocalScope)
1310  if (assumeVerified)
1312  if (skipRegions)
1314 
1315  PyFileAccumulator accum(fileObject, binary);
1316  mlirOperationPrintWithFlags(operation, flags, accum.getCallback(),
1317  accum.getUserData());
1319 }
1320 
1321 void PyOperationBase::print(PyAsmState &state, nb::object fileObject,
1322  bool binary) {
1323  PyOperation &operation = getOperation();
1324  operation.checkValid();
1325  if (fileObject.is_none())
1326  fileObject = nb::module_::import_("sys").attr("stdout");
1327  PyFileAccumulator accum(fileObject, binary);
1328  mlirOperationPrintWithState(operation, state.get(), accum.getCallback(),
1329  accum.getUserData());
1330 }
1331 
1332 void PyOperationBase::writeBytecode(const nb::object &fileObject,
1333  std::optional<int64_t> bytecodeVersion) {
1334  PyOperation &operation = getOperation();
1335  operation.checkValid();
1336  PyFileAccumulator accum(fileObject, /*binary=*/true);
1337 
1338  if (!bytecodeVersion.has_value())
1339  return mlirOperationWriteBytecode(operation, accum.getCallback(),
1340  accum.getUserData());
1341 
1342  MlirBytecodeWriterConfig config = mlirBytecodeWriterConfigCreate();
1345  operation, config, accum.getCallback(), accum.getUserData());
1347  if (mlirLogicalResultIsFailure(res))
1348  throw nb::value_error((Twine("Unable to honor desired bytecode version ") +
1349  Twine(*bytecodeVersion))
1350  .str()
1351  .c_str());
1352 }
1353 
1355  std::function<MlirWalkResult(MlirOperation)> callback,
1356  MlirWalkOrder walkOrder) {
1357  PyOperation &operation = getOperation();
1358  operation.checkValid();
1359  struct UserData {
1360  std::function<MlirWalkResult(MlirOperation)> callback;
1361  bool gotException;
1362  std::string exceptionWhat;
1363  nb::object exceptionType;
1364  };
1365  UserData userData{callback, false, {}, {}};
1366  MlirOperationWalkCallback walkCallback = [](MlirOperation op,
1367  void *userData) {
1368  UserData *calleeUserData = static_cast<UserData *>(userData);
1369  try {
1370  return (calleeUserData->callback)(op);
1371  } catch (nb::python_error &e) {
1372  calleeUserData->gotException = true;
1373  calleeUserData->exceptionWhat = std::string(e.what());
1374  calleeUserData->exceptionType = nb::borrow(e.type());
1376  }
1377  };
1378  mlirOperationWalk(operation, walkCallback, &userData, walkOrder);
1379  if (userData.gotException) {
1380  std::string message("Exception raised in callback: ");
1381  message.append(userData.exceptionWhat);
1382  throw std::runtime_error(message);
1383  }
1384 }
1385 
1386 nb::object PyOperationBase::getAsm(bool binary,
1387  std::optional<int64_t> largeElementsLimit,
1388  bool enableDebugInfo, bool prettyDebugInfo,
1389  bool printGenericOpForm, bool useLocalScope,
1390  bool assumeVerified, bool skipRegions) {
1391  nb::object fileObject;
1392  if (binary) {
1393  fileObject = nb::module_::import_("io").attr("BytesIO")();
1394  } else {
1395  fileObject = nb::module_::import_("io").attr("StringIO")();
1396  }
1397  print(/*largeElementsLimit=*/largeElementsLimit,
1398  /*enableDebugInfo=*/enableDebugInfo,
1399  /*prettyDebugInfo=*/prettyDebugInfo,
1400  /*printGenericOpForm=*/printGenericOpForm,
1401  /*useLocalScope=*/useLocalScope,
1402  /*assumeVerified=*/assumeVerified,
1403  /*fileObject=*/fileObject,
1404  /*binary=*/binary,
1405  /*skipRegions=*/skipRegions);
1406 
1407  return fileObject.attr("getvalue")();
1408 }
1409 
1411  PyOperation &operation = getOperation();
1412  PyOperation &otherOp = other.getOperation();
1413  operation.checkValid();
1414  otherOp.checkValid();
1415  mlirOperationMoveAfter(operation, otherOp);
1416  operation.parentKeepAlive = otherOp.parentKeepAlive;
1417 }
1418 
1420  PyOperation &operation = getOperation();
1421  PyOperation &otherOp = other.getOperation();
1422  operation.checkValid();
1423  otherOp.checkValid();
1424  mlirOperationMoveBefore(operation, otherOp);
1425  operation.parentKeepAlive = otherOp.parentKeepAlive;
1426 }
1427 
1429  PyOperation &op = getOperation();
1431  if (!mlirOperationVerify(op.get()))
1432  throw MLIRError("Verification failed", errors.take());
1433  return true;
1434 }
1435 
1436 std::optional<PyOperationRef> PyOperation::getParentOperation() {
1437  checkValid();
1438  if (!isAttached())
1439  throw nb::value_error("Detached operations have no parent");
1440  MlirOperation operation = mlirOperationGetParentOperation(get());
1441  if (mlirOperationIsNull(operation))
1442  return {};
1443  return PyOperation::forOperation(getContext(), operation);
1444 }
1445 
1447  checkValid();
1448  std::optional<PyOperationRef> parentOperation = getParentOperation();
1449  MlirBlock block = mlirOperationGetBlock(get());
1450  assert(!mlirBlockIsNull(block) && "Attached operation has null parent");
1451  assert(parentOperation && "Operation has no parent");
1452  return PyBlock{std::move(*parentOperation), block};
1453 }
1454 
1456  checkValid();
1457  return nb::steal<nb::object>(mlirPythonOperationToCapsule(get()));
1458 }
1459 
1460 nb::object PyOperation::createFromCapsule(nb::object capsule) {
1461  MlirOperation rawOperation = mlirPythonCapsuleToOperation(capsule.ptr());
1462  if (mlirOperationIsNull(rawOperation))
1463  throw nb::python_error();
1464  MlirContext rawCtxt = mlirOperationGetContext(rawOperation);
1465  return forOperation(PyMlirContext::forContext(rawCtxt), rawOperation)
1466  .releaseObject();
1467 }
1468 
1470  const nb::object &maybeIp) {
1471  // InsertPoint active?
1472  if (!maybeIp.is(nb::cast(false))) {
1473  PyInsertionPoint *ip;
1474  if (maybeIp.is_none()) {
1476  } else {
1477  ip = nb::cast<PyInsertionPoint *>(maybeIp);
1478  }
1479  if (ip)
1480  ip->insert(*op.get());
1481  }
1482 }
1483 
1484 nb::object PyOperation::create(std::string_view name,
1485  std::optional<std::vector<PyType *>> results,
1486  llvm::ArrayRef<MlirValue> operands,
1487  std::optional<nb::dict> attributes,
1488  std::optional<std::vector<PyBlock *>> successors,
1489  int regions, DefaultingPyLocation location,
1490  const nb::object &maybeIp, bool inferType) {
1491  llvm::SmallVector<MlirType, 4> mlirResults;
1492  llvm::SmallVector<MlirBlock, 4> mlirSuccessors;
1494 
1495  // General parameter validation.
1496  if (regions < 0)
1497  throw nb::value_error("number of regions must be >= 0");
1498 
1499  // Unpack/validate results.
1500  if (results) {
1501  mlirResults.reserve(results->size());
1502  for (PyType *result : *results) {
1503  // TODO: Verify result type originate from the same context.
1504  if (!result)
1505  throw nb::value_error("result type cannot be None");
1506  mlirResults.push_back(*result);
1507  }
1508  }
1509  // Unpack/validate attributes.
1510  if (attributes) {
1511  mlirAttributes.reserve(attributes->size());
1512  for (std::pair<nb::handle, nb::handle> it : *attributes) {
1513  std::string key;
1514  try {
1515  key = nb::cast<std::string>(it.first);
1516  } catch (nb::cast_error &err) {
1517  std::string msg = "Invalid attribute key (not a string) when "
1518  "attempting to create the operation \"" +
1519  std::string(name) + "\" (" + err.what() + ")";
1520  throw nb::type_error(msg.c_str());
1521  }
1522  try {
1523  auto &attribute = nb::cast<PyAttribute &>(it.second);
1524  // TODO: Verify attribute originates from the same context.
1525  mlirAttributes.emplace_back(std::move(key), attribute);
1526  } catch (nb::cast_error &err) {
1527  std::string msg = "Invalid attribute value for the key \"" + key +
1528  "\" when attempting to create the operation \"" +
1529  std::string(name) + "\" (" + err.what() + ")";
1530  throw nb::type_error(msg.c_str());
1531  } catch (std::runtime_error &) {
1532  // This exception seems thrown when the value is "None".
1533  std::string msg =
1534  "Found an invalid (`None`?) attribute value for the key \"" + key +
1535  "\" when attempting to create the operation \"" +
1536  std::string(name) + "\"";
1537  throw std::runtime_error(msg);
1538  }
1539  }
1540  }
1541  // Unpack/validate successors.
1542  if (successors) {
1543  mlirSuccessors.reserve(successors->size());
1544  for (auto *successor : *successors) {
1545  // TODO: Verify successor originate from the same context.
1546  if (!successor)
1547  throw nb::value_error("successor block cannot be None");
1548  mlirSuccessors.push_back(successor->get());
1549  }
1550  }
1551 
1552  // Apply unpacked/validated to the operation state. Beyond this
1553  // point, exceptions cannot be thrown or else the state will leak.
1554  MlirOperationState state =
1555  mlirOperationStateGet(toMlirStringRef(name), location);
1556  if (!operands.empty())
1557  mlirOperationStateAddOperands(&state, operands.size(), operands.data());
1558  state.enableResultTypeInference = inferType;
1559  if (!mlirResults.empty())
1560  mlirOperationStateAddResults(&state, mlirResults.size(),
1561  mlirResults.data());
1562  if (!mlirAttributes.empty()) {
1563  // Note that the attribute names directly reference bytes in
1564  // mlirAttributes, so that vector must not be changed from here
1565  // on.
1566  llvm::SmallVector<MlirNamedAttribute, 4> mlirNamedAttributes;
1567  mlirNamedAttributes.reserve(mlirAttributes.size());
1568  for (auto &it : mlirAttributes)
1569  mlirNamedAttributes.push_back(mlirNamedAttributeGet(
1571  toMlirStringRef(it.first)),
1572  it.second));
1573  mlirOperationStateAddAttributes(&state, mlirNamedAttributes.size(),
1574  mlirNamedAttributes.data());
1575  }
1576  if (!mlirSuccessors.empty())
1577  mlirOperationStateAddSuccessors(&state, mlirSuccessors.size(),
1578  mlirSuccessors.data());
1579  if (regions) {
1581  mlirRegions.resize(regions);
1582  for (int i = 0; i < regions; ++i)
1583  mlirRegions[i] = mlirRegionCreate();
1584  mlirOperationStateAddOwnedRegions(&state, mlirRegions.size(),
1585  mlirRegions.data());
1586  }
1587 
1588  // Construct the operation.
1589  MlirOperation operation = mlirOperationCreate(&state);
1590  if (!operation.ptr)
1591  throw nb::value_error("Operation creation failed");
1592  PyOperationRef created =
1593  PyOperation::createDetached(location->getContext(), operation);
1594  maybeInsertOperation(created, maybeIp);
1595 
1596  return created.getObject();
1597 }
1598 
1599 nb::object PyOperation::clone(const nb::object &maybeIp) {
1600  MlirOperation clonedOperation = mlirOperationClone(operation);
1601  PyOperationRef cloned =
1602  PyOperation::createDetached(getContext(), clonedOperation);
1603  maybeInsertOperation(cloned, maybeIp);
1604 
1605  return cloned->createOpView();
1606 }
1607 
1609  checkValid();
1610  MlirIdentifier ident = mlirOperationGetName(get());
1611  MlirStringRef identStr = mlirIdentifierStr(ident);
1612  auto operationCls = PyGlobals::get().lookupOperationClass(
1613  StringRef(identStr.data, identStr.length));
1614  if (operationCls)
1615  return PyOpView::constructDerived(*operationCls, getRef().getObject());
1616  return nb::cast(PyOpView(getRef().getObject()));
1617 }
1618 
1620  checkValid();
1622  mlirOperationDestroy(operation);
1623 }
1624 
1625 namespace {
1626 /// CRTP base class for Python MLIR values that subclass Value and should be
1627 /// castable from it. The value hierarchy is one level deep and is not supposed
1628 /// to accommodate other levels unless core MLIR changes.
1629 template <typename DerivedTy>
1630 class PyConcreteValue : public PyValue {
1631 public:
1632  // Derived classes must define statics for:
1633  // IsAFunctionTy isaFunction
1634  // const char *pyClassName
1635  // and redefine bindDerived.
1636  using ClassTy = nb::class_<DerivedTy, PyValue>;
1637  using IsAFunctionTy = bool (*)(MlirValue);
1638 
1639  PyConcreteValue() = default;
1640  PyConcreteValue(PyOperationRef operationRef, MlirValue value)
1641  : PyValue(operationRef, value) {}
1642  PyConcreteValue(PyValue &orig)
1643  : PyConcreteValue(orig.getParentOperation(), castFrom(orig)) {}
1644 
1645  /// Attempts to cast the original value to the derived type and throws on
1646  /// type mismatches.
1647  static MlirValue castFrom(PyValue &orig) {
1648  if (!DerivedTy::isaFunction(orig.get())) {
1649  auto origRepr = nb::cast<std::string>(nb::repr(nb::cast(orig)));
1650  throw nb::value_error((Twine("Cannot cast value to ") +
1651  DerivedTy::pyClassName + " (from " + origRepr +
1652  ")")
1653  .str()
1654  .c_str());
1655  }
1656  return orig.get();
1657  }
1658 
1659  /// Binds the Python module objects to functions of this class.
1660  static void bind(nb::module_ &m) {
1661  auto cls = ClassTy(m, DerivedTy::pyClassName);
1662  cls.def(nb::init<PyValue &>(), nb::keep_alive<0, 1>(), nb::arg("value"));
1663  cls.def_static(
1664  "isinstance",
1665  [](PyValue &otherValue) -> bool {
1666  return DerivedTy::isaFunction(otherValue);
1667  },
1668  nb::arg("other_value"));
1670  [](DerivedTy &self) { return self.maybeDownCast(); });
1671  DerivedTy::bindDerived(cls);
1672  }
1673 
1674  /// Implemented by derived classes to add methods to the Python subclass.
1675  static void bindDerived(ClassTy &m) {}
1676 };
1677 
1678 } // namespace
1679 
1680 /// Python wrapper for MlirOpResult.
1681 class PyOpResult : public PyConcreteValue<PyOpResult> {
1682 public:
1683  static constexpr IsAFunctionTy isaFunction = mlirValueIsAOpResult;
1684  static constexpr const char *pyClassName = "OpResult";
1685  using PyConcreteValue::PyConcreteValue;
1686 
1687  static void bindDerived(ClassTy &c) {
1688  c.def_prop_ro("owner", [](PyOpResult &self) {
1689  assert(
1690  mlirOperationEqual(self.getParentOperation()->get(),
1691  mlirOpResultGetOwner(self.get())) &&
1692  "expected the owner of the value in Python to match that in the IR");
1693  return self.getParentOperation().getObject();
1694  });
1695  c.def_prop_ro("result_number", [](PyOpResult &self) {
1696  return mlirOpResultGetResultNumber(self.get());
1697  });
1698  }
1699 };
1700 
1701 /// Returns the list of types of the values held by container.
1702 template <typename Container>
1703 static std::vector<MlirType> getValueTypes(Container &container,
1704  PyMlirContextRef &context) {
1705  std::vector<MlirType> result;
1706  result.reserve(container.size());
1707  for (int i = 0, e = container.size(); i < e; ++i) {
1708  result.push_back(mlirValueGetType(container.getElement(i).get()));
1709  }
1710  return result;
1711 }
1712 
1713 /// A list of operation results. Internally, these are stored as consecutive
1714 /// elements, random access is cheap. The (returned) result list is associated
1715 /// with the operation whose results these are, and thus extends the lifetime of
1716 /// this operation.
1717 class PyOpResultList : public Sliceable<PyOpResultList, PyOpResult> {
1718 public:
1719  static constexpr const char *pyClassName = "OpResultList";
1721 
1722  PyOpResultList(PyOperationRef operation, intptr_t startIndex = 0,
1723  intptr_t length = -1, intptr_t step = 1)
1724  : Sliceable(startIndex,
1725  length == -1 ? mlirOperationGetNumResults(operation->get())
1726  : length,
1727  step),
1728  operation(std::move(operation)) {}
1729 
1730  static void bindDerived(ClassTy &c) {
1731  c.def_prop_ro("types", [](PyOpResultList &self) {
1732  return getValueTypes(self, self.operation->getContext());
1733  });
1734  c.def_prop_ro("owner", [](PyOpResultList &self) {
1735  return self.operation->createOpView();
1736  });
1737  }
1738 
1739  PyOperationRef &getOperation() { return operation; }
1740 
1741 private:
1742  /// Give the parent CRTP class access to hook implementations below.
1743  friend class Sliceable<PyOpResultList, PyOpResult>;
1744 
1745  intptr_t getRawNumElements() {
1746  operation->checkValid();
1747  return mlirOperationGetNumResults(operation->get());
1748  }
1749 
1750  PyOpResult getRawElement(intptr_t index) {
1751  PyValue value(operation, mlirOperationGetResult(operation->get(), index));
1752  return PyOpResult(value);
1753  }
1754 
1755  PyOpResultList slice(intptr_t startIndex, intptr_t length, intptr_t step) {
1756  return PyOpResultList(operation, startIndex, length, step);
1757  }
1758 
1759  PyOperationRef operation;
1760 };
1761 
1762 //------------------------------------------------------------------------------
1763 // PyOpView
1764 //------------------------------------------------------------------------------
1765 
1766 static void populateResultTypes(StringRef name, nb::list resultTypeList,
1767  const nb::object &resultSegmentSpecObj,
1768  std::vector<int32_t> &resultSegmentLengths,
1769  std::vector<PyType *> &resultTypes) {
1770  resultTypes.reserve(resultTypeList.size());
1771  if (resultSegmentSpecObj.is_none()) {
1772  // Non-variadic result unpacking.
1773  for (const auto &it : llvm::enumerate(resultTypeList)) {
1774  try {
1775  resultTypes.push_back(nb::cast<PyType *>(it.value()));
1776  if (!resultTypes.back())
1777  throw nb::cast_error();
1778  } catch (nb::cast_error &err) {
1779  throw nb::value_error((llvm::Twine("Result ") +
1780  llvm::Twine(it.index()) + " of operation \"" +
1781  name + "\" must be a Type (" + err.what() + ")")
1782  .str()
1783  .c_str());
1784  }
1785  }
1786  } else {
1787  // Sized result unpacking.
1788  auto resultSegmentSpec = nb::cast<std::vector<int>>(resultSegmentSpecObj);
1789  if (resultSegmentSpec.size() != resultTypeList.size()) {
1790  throw nb::value_error((llvm::Twine("Operation \"") + name +
1791  "\" requires " +
1792  llvm::Twine(resultSegmentSpec.size()) +
1793  " result segments but was provided " +
1794  llvm::Twine(resultTypeList.size()))
1795  .str()
1796  .c_str());
1797  }
1798  resultSegmentLengths.reserve(resultTypeList.size());
1799  for (const auto &it :
1800  llvm::enumerate(llvm::zip(resultTypeList, resultSegmentSpec))) {
1801  int segmentSpec = std::get<1>(it.value());
1802  if (segmentSpec == 1 || segmentSpec == 0) {
1803  // Unpack unary element.
1804  try {
1805  auto *resultType = nb::cast<PyType *>(std::get<0>(it.value()));
1806  if (resultType) {
1807  resultTypes.push_back(resultType);
1808  resultSegmentLengths.push_back(1);
1809  } else if (segmentSpec == 0) {
1810  // Allowed to be optional.
1811  resultSegmentLengths.push_back(0);
1812  } else {
1813  throw nb::value_error(
1814  (llvm::Twine("Result ") + llvm::Twine(it.index()) +
1815  " of operation \"" + name +
1816  "\" must be a Type (was None and result is not optional)")
1817  .str()
1818  .c_str());
1819  }
1820  } catch (nb::cast_error &err) {
1821  throw nb::value_error((llvm::Twine("Result ") +
1822  llvm::Twine(it.index()) + " of operation \"" +
1823  name + "\" must be a Type (" + err.what() +
1824  ")")
1825  .str()
1826  .c_str());
1827  }
1828  } else if (segmentSpec == -1) {
1829  // Unpack sequence by appending.
1830  try {
1831  if (std::get<0>(it.value()).is_none()) {
1832  // Treat it as an empty list.
1833  resultSegmentLengths.push_back(0);
1834  } else {
1835  // Unpack the list.
1836  auto segment = nb::cast<nb::sequence>(std::get<0>(it.value()));
1837  for (nb::handle segmentItem : segment) {
1838  resultTypes.push_back(nb::cast<PyType *>(segmentItem));
1839  if (!resultTypes.back()) {
1840  throw nb::type_error("contained a None item");
1841  }
1842  }
1843  resultSegmentLengths.push_back(nb::len(segment));
1844  }
1845  } catch (std::exception &err) {
1846  // NOTE: Sloppy to be using a catch-all here, but there are at least
1847  // three different unrelated exceptions that can be thrown in the
1848  // above "casts". Just keep the scope above small and catch them all.
1849  throw nb::value_error((llvm::Twine("Result ") +
1850  llvm::Twine(it.index()) + " of operation \"" +
1851  name + "\" must be a Sequence of Types (" +
1852  err.what() + ")")
1853  .str()
1854  .c_str());
1855  }
1856  } else {
1857  throw nb::value_error("Unexpected segment spec");
1858  }
1859  }
1860  }
1861 }
1862 
1863 static MlirValue getUniqueResult(MlirOperation operation) {
1864  auto numResults = mlirOperationGetNumResults(operation);
1865  if (numResults != 1) {
1866  auto name = mlirIdentifierStr(mlirOperationGetName(operation));
1867  throw nb::value_error((Twine("Cannot call .result on operation ") +
1868  StringRef(name.data, name.length) + " which has " +
1869  Twine(numResults) +
1870  " results (it is only valid for operations with a "
1871  "single result)")
1872  .str()
1873  .c_str());
1874  }
1875  return mlirOperationGetResult(operation, 0);
1876 }
1877 
1878 static MlirValue getOpResultOrValue(nb::handle operand) {
1879  if (operand.is_none()) {
1880  throw nb::value_error("contained a None item");
1881  }
1882  PyOperationBase *op;
1883  if (nb::try_cast<PyOperationBase *>(operand, op)) {
1884  return getUniqueResult(op->getOperation());
1885  }
1886  PyOpResultList *opResultList;
1887  if (nb::try_cast<PyOpResultList *>(operand, opResultList)) {
1888  return getUniqueResult(opResultList->getOperation()->get());
1889  }
1890  PyValue *value;
1891  if (nb::try_cast<PyValue *>(operand, value)) {
1892  return value->get();
1893  }
1894  throw nb::value_error("is not a Value");
1895 }
1896 
1898  std::string_view name, std::tuple<int, bool> opRegionSpec,
1899  nb::object operandSegmentSpecObj, nb::object resultSegmentSpecObj,
1900  std::optional<nb::list> resultTypeList, nb::list operandList,
1901  std::optional<nb::dict> attributes,
1902  std::optional<std::vector<PyBlock *>> successors,
1903  std::optional<int> regions, DefaultingPyLocation location,
1904  const nb::object &maybeIp) {
1905  PyMlirContextRef context = location->getContext();
1906 
1907  // Class level operation construction metadata.
1908  // Operand and result segment specs are either none, which does no
1909  // variadic unpacking, or a list of ints with segment sizes, where each
1910  // element is either a positive number (typically 1 for a scalar) or -1 to
1911  // indicate that it is derived from the length of the same-indexed operand
1912  // or result (implying that it is a list at that position).
1913  std::vector<int32_t> operandSegmentLengths;
1914  std::vector<int32_t> resultSegmentLengths;
1915 
1916  // Validate/determine region count.
1917  int opMinRegionCount = std::get<0>(opRegionSpec);
1918  bool opHasNoVariadicRegions = std::get<1>(opRegionSpec);
1919  if (!regions) {
1920  regions = opMinRegionCount;
1921  }
1922  if (*regions < opMinRegionCount) {
1923  throw nb::value_error(
1924  (llvm::Twine("Operation \"") + name + "\" requires a minimum of " +
1925  llvm::Twine(opMinRegionCount) +
1926  " regions but was built with regions=" + llvm::Twine(*regions))
1927  .str()
1928  .c_str());
1929  }
1930  if (opHasNoVariadicRegions && *regions > opMinRegionCount) {
1931  throw nb::value_error(
1932  (llvm::Twine("Operation \"") + name + "\" requires a maximum of " +
1933  llvm::Twine(opMinRegionCount) +
1934  " regions but was built with regions=" + llvm::Twine(*regions))
1935  .str()
1936  .c_str());
1937  }
1938 
1939  // Unpack results.
1940  std::vector<PyType *> resultTypes;
1941  if (resultTypeList.has_value()) {
1942  populateResultTypes(name, *resultTypeList, resultSegmentSpecObj,
1943  resultSegmentLengths, resultTypes);
1944  }
1945 
1946  // Unpack operands.
1948  operands.reserve(operands.size());
1949  if (operandSegmentSpecObj.is_none()) {
1950  // Non-sized operand unpacking.
1951  for (const auto &it : llvm::enumerate(operandList)) {
1952  try {
1953  operands.push_back(getOpResultOrValue(it.value()));
1954  } catch (nb::builtin_exception &err) {
1955  throw nb::value_error((llvm::Twine("Operand ") +
1956  llvm::Twine(it.index()) + " of operation \"" +
1957  name + "\" must be a Value (" + err.what() + ")")
1958  .str()
1959  .c_str());
1960  }
1961  }
1962  } else {
1963  // Sized operand unpacking.
1964  auto operandSegmentSpec = nb::cast<std::vector<int>>(operandSegmentSpecObj);
1965  if (operandSegmentSpec.size() != operandList.size()) {
1966  throw nb::value_error((llvm::Twine("Operation \"") + name +
1967  "\" requires " +
1968  llvm::Twine(operandSegmentSpec.size()) +
1969  "operand segments but was provided " +
1970  llvm::Twine(operandList.size()))
1971  .str()
1972  .c_str());
1973  }
1974  operandSegmentLengths.reserve(operandList.size());
1975  for (const auto &it :
1976  llvm::enumerate(llvm::zip(operandList, operandSegmentSpec))) {
1977  int segmentSpec = std::get<1>(it.value());
1978  if (segmentSpec == 1 || segmentSpec == 0) {
1979  // Unpack unary element.
1980  auto &operand = std::get<0>(it.value());
1981  if (!operand.is_none()) {
1982  try {
1983 
1984  operands.push_back(getOpResultOrValue(operand));
1985  } catch (nb::builtin_exception &err) {
1986  throw nb::value_error((llvm::Twine("Operand ") +
1987  llvm::Twine(it.index()) +
1988  " of operation \"" + name +
1989  "\" must be a Value (" + err.what() + ")")
1990  .str()
1991  .c_str());
1992  }
1993 
1994  operandSegmentLengths.push_back(1);
1995  } else if (segmentSpec == 0) {
1996  // Allowed to be optional.
1997  operandSegmentLengths.push_back(0);
1998  } else {
1999  throw nb::value_error(
2000  (llvm::Twine("Operand ") + llvm::Twine(it.index()) +
2001  " of operation \"" + name +
2002  "\" must be a Value (was None and operand is not optional)")
2003  .str()
2004  .c_str());
2005  }
2006  } else if (segmentSpec == -1) {
2007  // Unpack sequence by appending.
2008  try {
2009  if (std::get<0>(it.value()).is_none()) {
2010  // Treat it as an empty list.
2011  operandSegmentLengths.push_back(0);
2012  } else {
2013  // Unpack the list.
2014  auto segment = nb::cast<nb::sequence>(std::get<0>(it.value()));
2015  for (nb::handle segmentItem : segment) {
2016  operands.push_back(getOpResultOrValue(segmentItem));
2017  }
2018  operandSegmentLengths.push_back(nb::len(segment));
2019  }
2020  } catch (std::exception &err) {
2021  // NOTE: Sloppy to be using a catch-all here, but there are at least
2022  // three different unrelated exceptions that can be thrown in the
2023  // above "casts". Just keep the scope above small and catch them all.
2024  throw nb::value_error((llvm::Twine("Operand ") +
2025  llvm::Twine(it.index()) + " of operation \"" +
2026  name + "\" must be a Sequence of Values (" +
2027  err.what() + ")")
2028  .str()
2029  .c_str());
2030  }
2031  } else {
2032  throw nb::value_error("Unexpected segment spec");
2033  }
2034  }
2035  }
2036 
2037  // Merge operand/result segment lengths into attributes if needed.
2038  if (!operandSegmentLengths.empty() || !resultSegmentLengths.empty()) {
2039  // Dup.
2040  if (attributes) {
2041  attributes = nb::dict(*attributes);
2042  } else {
2043  attributes = nb::dict();
2044  }
2045  if (attributes->contains("resultSegmentSizes") ||
2046  attributes->contains("operandSegmentSizes")) {
2047  throw nb::value_error("Manually setting a 'resultSegmentSizes' or "
2048  "'operandSegmentSizes' attribute is unsupported. "
2049  "Use Operation.create for such low-level access.");
2050  }
2051 
2052  // Add resultSegmentSizes attribute.
2053  if (!resultSegmentLengths.empty()) {
2054  MlirAttribute segmentLengthAttr =
2055  mlirDenseI32ArrayGet(context->get(), resultSegmentLengths.size(),
2056  resultSegmentLengths.data());
2057  (*attributes)["resultSegmentSizes"] =
2058  PyAttribute(context, segmentLengthAttr);
2059  }
2060 
2061  // Add operandSegmentSizes attribute.
2062  if (!operandSegmentLengths.empty()) {
2063  MlirAttribute segmentLengthAttr =
2064  mlirDenseI32ArrayGet(context->get(), operandSegmentLengths.size(),
2065  operandSegmentLengths.data());
2066  (*attributes)["operandSegmentSizes"] =
2067  PyAttribute(context, segmentLengthAttr);
2068  }
2069  }
2070 
2071  // Delegate to create.
2072  return PyOperation::create(name,
2073  /*results=*/std::move(resultTypes),
2074  /*operands=*/std::move(operands),
2075  /*attributes=*/std::move(attributes),
2076  /*successors=*/std::move(successors),
2077  /*regions=*/*regions, location, maybeIp,
2078  !resultTypeList);
2079 }
2080 
2081 nb::object PyOpView::constructDerived(const nb::object &cls,
2082  const nb::object &operation) {
2083  nb::handle opViewType = nb::type<PyOpView>();
2084  nb::object instance = cls.attr("__new__")(cls);
2085  opViewType.attr("__init__")(instance, operation);
2086  return instance;
2087 }
2088 
2089 PyOpView::PyOpView(const nb::object &operationObject)
2090  // Casting through the PyOperationBase base-class and then back to the
2091  // Operation lets us accept any PyOperationBase subclass.
2092  : operation(nb::cast<PyOperationBase &>(operationObject).getOperation()),
2093  operationObject(operation.getRef().getObject()) {}
2094 
2095 //------------------------------------------------------------------------------
2096 // PyInsertionPoint.
2097 //------------------------------------------------------------------------------
2098 
2100 
2102  : refOperation(beforeOperationBase.getOperation().getRef()),
2103  block((*refOperation)->getBlock()) {}
2104 
2106  PyOperation &operation = operationBase.getOperation();
2107  if (operation.isAttached())
2108  throw nb::value_error(
2109  "Attempt to insert operation that is already attached");
2110  block.getParentOperation()->checkValid();
2111  MlirOperation beforeOp = {nullptr};
2112  if (refOperation) {
2113  // Insert before operation.
2114  (*refOperation)->checkValid();
2115  beforeOp = (*refOperation)->get();
2116  } else {
2117  // Insert at end (before null) is only valid if the block does not
2118  // already end in a known terminator (violating this will cause assertion
2119  // failures later).
2120  if (!mlirOperationIsNull(mlirBlockGetTerminator(block.get()))) {
2121  throw nb::index_error("Cannot insert operation at the end of a block "
2122  "that already has a terminator. Did you mean to "
2123  "use 'InsertionPoint.at_block_terminator(block)' "
2124  "versus 'InsertionPoint(block)'?");
2125  }
2126  }
2127  mlirBlockInsertOwnedOperationBefore(block.get(), beforeOp, operation);
2128  operation.setAttached();
2129 }
2130 
2132  MlirOperation firstOp = mlirBlockGetFirstOperation(block.get());
2133  if (mlirOperationIsNull(firstOp)) {
2134  // Just insert at end.
2135  return PyInsertionPoint(block);
2136  }
2137 
2138  // Insert before first op.
2140  block.getParentOperation()->getContext(), firstOp);
2141  return PyInsertionPoint{block, std::move(firstOpRef)};
2142 }
2143 
2145  MlirOperation terminator = mlirBlockGetTerminator(block.get());
2146  if (mlirOperationIsNull(terminator))
2147  throw nb::value_error("Block has no terminator");
2148  PyOperationRef terminatorOpRef = PyOperation::forOperation(
2149  block.getParentOperation()->getContext(), terminator);
2150  return PyInsertionPoint{block, std::move(terminatorOpRef)};
2151 }
2152 
2153 nb::object PyInsertionPoint::contextEnter(nb::object insertPoint) {
2154  return PyThreadContextEntry::pushInsertionPoint(insertPoint);
2155 }
2156 
2157 void PyInsertionPoint::contextExit(const nb::object &excType,
2158  const nb::object &excVal,
2159  const nb::object &excTb) {
2161 }
2162 
2163 //------------------------------------------------------------------------------
2164 // PyAttribute.
2165 //------------------------------------------------------------------------------
2166 
2167 bool PyAttribute::operator==(const PyAttribute &other) const {
2168  return mlirAttributeEqual(attr, other.attr);
2169 }
2170 
2172  return nb::steal<nb::object>(mlirPythonAttributeToCapsule(*this));
2173 }
2174 
2176  MlirAttribute rawAttr = mlirPythonCapsuleToAttribute(capsule.ptr());
2177  if (mlirAttributeIsNull(rawAttr))
2178  throw nb::python_error();
2179  return PyAttribute(
2181 }
2182 
2183 //------------------------------------------------------------------------------
2184 // PyNamedAttribute.
2185 //------------------------------------------------------------------------------
2186 
2187 PyNamedAttribute::PyNamedAttribute(MlirAttribute attr, std::string ownedName)
2188  : ownedName(new std::string(std::move(ownedName))) {
2191  toMlirStringRef(*this->ownedName)),
2192  attr);
2193 }
2194 
2195 //------------------------------------------------------------------------------
2196 // PyType.
2197 //------------------------------------------------------------------------------
2198 
2199 bool PyType::operator==(const PyType &other) const {
2200  return mlirTypeEqual(type, other.type);
2201 }
2202 
2203 nb::object PyType::getCapsule() {
2204  return nb::steal<nb::object>(mlirPythonTypeToCapsule(*this));
2205 }
2206 
2207 PyType PyType::createFromCapsule(nb::object capsule) {
2208  MlirType rawType = mlirPythonCapsuleToType(capsule.ptr());
2209  if (mlirTypeIsNull(rawType))
2210  throw nb::python_error();
2212  rawType);
2213 }
2214 
2215 //------------------------------------------------------------------------------
2216 // PyTypeID.
2217 //------------------------------------------------------------------------------
2218 
2219 nb::object PyTypeID::getCapsule() {
2220  return nb::steal<nb::object>(mlirPythonTypeIDToCapsule(*this));
2221 }
2222 
2224  MlirTypeID mlirTypeID = mlirPythonCapsuleToTypeID(capsule.ptr());
2225  if (mlirTypeIDIsNull(mlirTypeID))
2226  throw nb::python_error();
2227  return PyTypeID(mlirTypeID);
2228 }
2229 bool PyTypeID::operator==(const PyTypeID &other) const {
2230  return mlirTypeIDEqual(typeID, other.typeID);
2231 }
2232 
2233 //------------------------------------------------------------------------------
2234 // PyValue and subclasses.
2235 //------------------------------------------------------------------------------
2236 
2237 nb::object PyValue::getCapsule() {
2238  return nb::steal<nb::object>(mlirPythonValueToCapsule(get()));
2239 }
2240 
2242  MlirType type = mlirValueGetType(get());
2243  MlirTypeID mlirTypeID = mlirTypeGetTypeID(type);
2244  assert(!mlirTypeIDIsNull(mlirTypeID) &&
2245  "mlirTypeID was expected to be non-null.");
2246  std::optional<nb::callable> valueCaster =
2248  // nb::rv_policy::move means use std::move to move the return value
2249  // contents into a new instance that will be owned by Python.
2250  nb::object thisObj = nb::cast(this, nb::rv_policy::move);
2251  if (!valueCaster)
2252  return thisObj;
2253  return valueCaster.value()(thisObj);
2254 }
2255 
2257  MlirValue value = mlirPythonCapsuleToValue(capsule.ptr());
2258  if (mlirValueIsNull(value))
2259  throw nb::python_error();
2260  MlirOperation owner;
2261  if (mlirValueIsAOpResult(value))
2262  owner = mlirOpResultGetOwner(value);
2263  if (mlirValueIsABlockArgument(value))
2265  if (mlirOperationIsNull(owner))
2266  throw nb::python_error();
2267  MlirContext ctx = mlirOperationGetContext(owner);
2268  PyOperationRef ownerRef =
2270  return PyValue(ownerRef, value);
2271 }
2272 
2273 //------------------------------------------------------------------------------
2274 // PySymbolTable.
2275 //------------------------------------------------------------------------------
2276 
2278  : operation(operation.getOperation().getRef()) {
2279  symbolTable = mlirSymbolTableCreate(operation.getOperation().get());
2280  if (mlirSymbolTableIsNull(symbolTable)) {
2281  throw nb::type_error("Operation is not a Symbol Table.");
2282  }
2283 }
2284 
2285 nb::object PySymbolTable::dunderGetItem(const std::string &name) {
2286  operation->checkValid();
2287  MlirOperation symbol = mlirSymbolTableLookup(
2288  symbolTable, mlirStringRefCreate(name.data(), name.length()));
2289  if (mlirOperationIsNull(symbol))
2290  throw nb::key_error(
2291  ("Symbol '" + name + "' not in the symbol table.").c_str());
2292 
2293  return PyOperation::forOperation(operation->getContext(), symbol,
2294  operation.getObject())
2295  ->createOpView();
2296 }
2297 
2299  operation->checkValid();
2300  symbol.getOperation().checkValid();
2301  mlirSymbolTableErase(symbolTable, symbol.getOperation().get());
2302  // The operation is also erased, so we must invalidate it. There may be Python
2303  // references to this operation so we don't want to delete it from the list of
2304  // live operations here.
2305  symbol.getOperation().valid = false;
2306 }
2307 
2308 void PySymbolTable::dunderDel(const std::string &name) {
2309  nb::object operation = dunderGetItem(name);
2310  erase(nb::cast<PyOperationBase &>(operation));
2311 }
2312 
2313 MlirAttribute PySymbolTable::insert(PyOperationBase &symbol) {
2314  operation->checkValid();
2315  symbol.getOperation().checkValid();
2316  MlirAttribute symbolAttr = mlirOperationGetAttributeByName(
2318  if (mlirAttributeIsNull(symbolAttr))
2319  throw nb::value_error("Expected operation to have a symbol name.");
2320  return mlirSymbolTableInsert(symbolTable, symbol.getOperation().get());
2321 }
2322 
2324  // Op must already be a symbol.
2325  PyOperation &operation = symbol.getOperation();
2326  operation.checkValid();
2328  MlirAttribute existingNameAttr =
2329  mlirOperationGetAttributeByName(operation.get(), attrName);
2330  if (mlirAttributeIsNull(existingNameAttr))
2331  throw nb::value_error("Expected operation to have a symbol name.");
2332  return existingNameAttr;
2333 }
2334 
2336  const std::string &name) {
2337  // Op must already be a symbol.
2338  PyOperation &operation = symbol.getOperation();
2339  operation.checkValid();
2341  MlirAttribute existingNameAttr =
2342  mlirOperationGetAttributeByName(operation.get(), attrName);
2343  if (mlirAttributeIsNull(existingNameAttr))
2344  throw nb::value_error("Expected operation to have a symbol name.");
2345  MlirAttribute newNameAttr =
2346  mlirStringAttrGet(operation.getContext()->get(), toMlirStringRef(name));
2347  mlirOperationSetAttributeByName(operation.get(), attrName, newNameAttr);
2348 }
2349 
2351  PyOperation &operation = symbol.getOperation();
2352  operation.checkValid();
2354  MlirAttribute existingVisAttr =
2355  mlirOperationGetAttributeByName(operation.get(), attrName);
2356  if (mlirAttributeIsNull(existingVisAttr))
2357  throw nb::value_error("Expected operation to have a symbol visibility.");
2358  return existingVisAttr;
2359 }
2360 
2362  const std::string &visibility) {
2363  if (visibility != "public" && visibility != "private" &&
2364  visibility != "nested")
2365  throw nb::value_error(
2366  "Expected visibility to be 'public', 'private' or 'nested'");
2367  PyOperation &operation = symbol.getOperation();
2368  operation.checkValid();
2370  MlirAttribute existingVisAttr =
2371  mlirOperationGetAttributeByName(operation.get(), attrName);
2372  if (mlirAttributeIsNull(existingVisAttr))
2373  throw nb::value_error("Expected operation to have a symbol visibility.");
2374  MlirAttribute newVisAttr = mlirStringAttrGet(operation.getContext()->get(),
2375  toMlirStringRef(visibility));
2376  mlirOperationSetAttributeByName(operation.get(), attrName, newVisAttr);
2377 }
2378 
2379 void PySymbolTable::replaceAllSymbolUses(const std::string &oldSymbol,
2380  const std::string &newSymbol,
2381  PyOperationBase &from) {
2382  PyOperation &fromOperation = from.getOperation();
2383  fromOperation.checkValid();
2385  toMlirStringRef(oldSymbol), toMlirStringRef(newSymbol),
2386  from.getOperation())))
2387 
2388  throw nb::value_error("Symbol rename failed");
2389 }
2390 
2392  bool allSymUsesVisible,
2393  nb::object callback) {
2394  PyOperation &fromOperation = from.getOperation();
2395  fromOperation.checkValid();
2396  struct UserData {
2397  PyMlirContextRef context;
2398  nb::object callback;
2399  bool gotException;
2400  std::string exceptionWhat;
2401  nb::object exceptionType;
2402  };
2403  UserData userData{
2404  fromOperation.getContext(), std::move(callback), false, {}, {}};
2406  fromOperation.get(), allSymUsesVisible,
2407  [](MlirOperation foundOp, bool isVisible, void *calleeUserDataVoid) {
2408  UserData *calleeUserData = static_cast<UserData *>(calleeUserDataVoid);
2409  auto pyFoundOp =
2410  PyOperation::forOperation(calleeUserData->context, foundOp);
2411  if (calleeUserData->gotException)
2412  return;
2413  try {
2414  calleeUserData->callback(pyFoundOp.getObject(), isVisible);
2415  } catch (nb::python_error &e) {
2416  calleeUserData->gotException = true;
2417  calleeUserData->exceptionWhat = e.what();
2418  calleeUserData->exceptionType = nb::borrow(e.type());
2419  }
2420  },
2421  static_cast<void *>(&userData));
2422  if (userData.gotException) {
2423  std::string message("Exception raised in callback: ");
2424  message.append(userData.exceptionWhat);
2425  throw std::runtime_error(message);
2426  }
2427 }
2428 
2429 namespace {
2430 
2431 /// Python wrapper for MlirBlockArgument.
2432 class PyBlockArgument : public PyConcreteValue<PyBlockArgument> {
2433 public:
2434  static constexpr IsAFunctionTy isaFunction = mlirValueIsABlockArgument;
2435  static constexpr const char *pyClassName = "BlockArgument";
2436  using PyConcreteValue::PyConcreteValue;
2437 
2438  static void bindDerived(ClassTy &c) {
2439  c.def_prop_ro("owner", [](PyBlockArgument &self) {
2440  return PyBlock(self.getParentOperation(),
2441  mlirBlockArgumentGetOwner(self.get()));
2442  });
2443  c.def_prop_ro("arg_number", [](PyBlockArgument &self) {
2444  return mlirBlockArgumentGetArgNumber(self.get());
2445  });
2446  c.def(
2447  "set_type",
2448  [](PyBlockArgument &self, PyType type) {
2449  return mlirBlockArgumentSetType(self.get(), type);
2450  },
2451  nb::arg("type"));
2452  }
2453 };
2454 
2455 /// A list of block arguments. Internally, these are stored as consecutive
2456 /// elements, random access is cheap. The argument list is associated with the
2457 /// operation that contains the block (detached blocks are not allowed in
2458 /// Python bindings) and extends its lifetime.
2459 class PyBlockArgumentList
2460  : public Sliceable<PyBlockArgumentList, PyBlockArgument> {
2461 public:
2462  static constexpr const char *pyClassName = "BlockArgumentList";
2464 
2465  PyBlockArgumentList(PyOperationRef operation, MlirBlock block,
2466  intptr_t startIndex = 0, intptr_t length = -1,
2467  intptr_t step = 1)
2468  : Sliceable(startIndex,
2469  length == -1 ? mlirBlockGetNumArguments(block) : length,
2470  step),
2471  operation(std::move(operation)), block(block) {}
2472 
2473  static void bindDerived(ClassTy &c) {
2474  c.def_prop_ro("types", [](PyBlockArgumentList &self) {
2475  return getValueTypes(self, self.operation->getContext());
2476  });
2477  }
2478 
2479 private:
2480  /// Give the parent CRTP class access to hook implementations below.
2481  friend class Sliceable<PyBlockArgumentList, PyBlockArgument>;
2482 
2483  /// Returns the number of arguments in the list.
2484  intptr_t getRawNumElements() {
2485  operation->checkValid();
2486  return mlirBlockGetNumArguments(block);
2487  }
2488 
2489  /// Returns `pos`-the element in the list.
2490  PyBlockArgument getRawElement(intptr_t pos) {
2491  MlirValue argument = mlirBlockGetArgument(block, pos);
2492  return PyBlockArgument(operation, argument);
2493  }
2494 
2495  /// Returns a sublist of this list.
2496  PyBlockArgumentList slice(intptr_t startIndex, intptr_t length,
2497  intptr_t step) {
2498  return PyBlockArgumentList(operation, block, startIndex, length, step);
2499  }
2500 
2501  PyOperationRef operation;
2502  MlirBlock block;
2503 };
2504 
2505 /// A list of operation operands. Internally, these are stored as consecutive
2506 /// elements, random access is cheap. The (returned) operand list is associated
2507 /// with the operation whose operands these are, and thus extends the lifetime
2508 /// of this operation.
2509 class PyOpOperandList : public Sliceable<PyOpOperandList, PyValue> {
2510 public:
2511  static constexpr const char *pyClassName = "OpOperandList";
2512  using SliceableT = Sliceable<PyOpOperandList, PyValue>;
2513 
2514  PyOpOperandList(PyOperationRef operation, intptr_t startIndex = 0,
2515  intptr_t length = -1, intptr_t step = 1)
2516  : Sliceable(startIndex,
2517  length == -1 ? mlirOperationGetNumOperands(operation->get())
2518  : length,
2519  step),
2520  operation(operation) {}
2521 
2522  void dunderSetItem(intptr_t index, PyValue value) {
2523  index = wrapIndex(index);
2524  mlirOperationSetOperand(operation->get(), index, value.get());
2525  }
2526 
2527  static void bindDerived(ClassTy &c) {
2528  c.def("__setitem__", &PyOpOperandList::dunderSetItem);
2529  }
2530 
2531 private:
2532  /// Give the parent CRTP class access to hook implementations below.
2533  friend class Sliceable<PyOpOperandList, PyValue>;
2534 
2535  intptr_t getRawNumElements() {
2536  operation->checkValid();
2537  return mlirOperationGetNumOperands(operation->get());
2538  }
2539 
2540  PyValue getRawElement(intptr_t pos) {
2541  MlirValue operand = mlirOperationGetOperand(operation->get(), pos);
2542  MlirOperation owner;
2543  if (mlirValueIsAOpResult(operand))
2544  owner = mlirOpResultGetOwner(operand);
2545  else if (mlirValueIsABlockArgument(operand))
2547  else
2548  assert(false && "Value must be an block arg or op result.");
2549  PyOperationRef pyOwner =
2550  PyOperation::forOperation(operation->getContext(), owner);
2551  return PyValue(pyOwner, operand);
2552  }
2553 
2554  PyOpOperandList slice(intptr_t startIndex, intptr_t length, intptr_t step) {
2555  return PyOpOperandList(operation, startIndex, length, step);
2556  }
2557 
2558  PyOperationRef operation;
2559 };
2560 
2561 /// A list of operation successors. Internally, these are stored as consecutive
2562 /// elements, random access is cheap. The (returned) successor list is
2563 /// associated with the operation whose successors these are, and thus extends
2564 /// the lifetime of this operation.
2565 class PyOpSuccessors : public Sliceable<PyOpSuccessors, PyBlock> {
2566 public:
2567  static constexpr const char *pyClassName = "OpSuccessors";
2568 
2569  PyOpSuccessors(PyOperationRef operation, intptr_t startIndex = 0,
2570  intptr_t length = -1, intptr_t step = 1)
2571  : Sliceable(startIndex,
2572  length == -1 ? mlirOperationGetNumSuccessors(operation->get())
2573  : length,
2574  step),
2575  operation(operation) {}
2576 
2577  void dunderSetItem(intptr_t index, PyBlock block) {
2578  index = wrapIndex(index);
2579  mlirOperationSetSuccessor(operation->get(), index, block.get());
2580  }
2581 
2582  static void bindDerived(ClassTy &c) {
2583  c.def("__setitem__", &PyOpSuccessors::dunderSetItem);
2584  }
2585 
2586 private:
2587  /// Give the parent CRTP class access to hook implementations below.
2588  friend class Sliceable<PyOpSuccessors, PyBlock>;
2589 
2590  intptr_t getRawNumElements() {
2591  operation->checkValid();
2592  return mlirOperationGetNumSuccessors(operation->get());
2593  }
2594 
2595  PyBlock getRawElement(intptr_t pos) {
2596  MlirBlock block = mlirOperationGetSuccessor(operation->get(), pos);
2597  return PyBlock(operation, block);
2598  }
2599 
2600  PyOpSuccessors slice(intptr_t startIndex, intptr_t length, intptr_t step) {
2601  return PyOpSuccessors(operation, startIndex, length, step);
2602  }
2603 
2604  PyOperationRef operation;
2605 };
2606 
2607 /// A list of operation attributes. Can be indexed by name, producing
2608 /// attributes, or by index, producing named attributes.
2609 class PyOpAttributeMap {
2610 public:
2611  PyOpAttributeMap(PyOperationRef operation)
2612  : operation(std::move(operation)) {}
2613 
2614  MlirAttribute dunderGetItemNamed(const std::string &name) {
2615  MlirAttribute attr = mlirOperationGetAttributeByName(operation->get(),
2616  toMlirStringRef(name));
2617  if (mlirAttributeIsNull(attr)) {
2618  throw nb::key_error("attempt to access a non-existent attribute");
2619  }
2620  return attr;
2621  }
2622 
2623  PyNamedAttribute dunderGetItemIndexed(intptr_t index) {
2624  if (index < 0 || index >= dunderLen()) {
2625  throw nb::index_error("attempt to access out of bounds attribute");
2626  }
2627  MlirNamedAttribute namedAttr =
2628  mlirOperationGetAttribute(operation->get(), index);
2629  return PyNamedAttribute(
2630  namedAttr.attribute,
2631  std::string(mlirIdentifierStr(namedAttr.name).data,
2632  mlirIdentifierStr(namedAttr.name).length));
2633  }
2634 
2635  void dunderSetItem(const std::string &name, const PyAttribute &attr) {
2637  attr);
2638  }
2639 
2640  void dunderDelItem(const std::string &name) {
2641  int removed = mlirOperationRemoveAttributeByName(operation->get(),
2642  toMlirStringRef(name));
2643  if (!removed)
2644  throw nb::key_error("attempt to delete a non-existent attribute");
2645  }
2646 
2647  intptr_t dunderLen() {
2648  return mlirOperationGetNumAttributes(operation->get());
2649  }
2650 
2651  bool dunderContains(const std::string &name) {
2653  operation->get(), toMlirStringRef(name)));
2654  }
2655 
2656  static void bind(nb::module_ &m) {
2657  nb::class_<PyOpAttributeMap>(m, "OpAttributeMap")
2658  .def("__contains__", &PyOpAttributeMap::dunderContains)
2659  .def("__len__", &PyOpAttributeMap::dunderLen)
2660  .def("__getitem__", &PyOpAttributeMap::dunderGetItemNamed)
2661  .def("__getitem__", &PyOpAttributeMap::dunderGetItemIndexed)
2662  .def("__setitem__", &PyOpAttributeMap::dunderSetItem)
2663  .def("__delitem__", &PyOpAttributeMap::dunderDelItem);
2664  }
2665 
2666 private:
2667  PyOperationRef operation;
2668 };
2669 
2670 } // namespace
2671 
2672 //------------------------------------------------------------------------------
2673 // Populates the core exports of the 'ir' submodule.
2674 //------------------------------------------------------------------------------
2675 
2676 void mlir::python::populateIRCore(nb::module_ &m) {
2677  // disable leak warnings which tend to be false positives.
2678  nb::set_leak_warnings(false);
2679  //----------------------------------------------------------------------------
2680  // Enums.
2681  //----------------------------------------------------------------------------
2682  nb::enum_<MlirDiagnosticSeverity>(m, "DiagnosticSeverity")
2683  .value("ERROR", MlirDiagnosticError)
2684  .value("WARNING", MlirDiagnosticWarning)
2685  .value("NOTE", MlirDiagnosticNote)
2686  .value("REMARK", MlirDiagnosticRemark);
2687 
2688  nb::enum_<MlirWalkOrder>(m, "WalkOrder")
2689  .value("PRE_ORDER", MlirWalkPreOrder)
2690  .value("POST_ORDER", MlirWalkPostOrder);
2691 
2692  nb::enum_<MlirWalkResult>(m, "WalkResult")
2693  .value("ADVANCE", MlirWalkResultAdvance)
2694  .value("INTERRUPT", MlirWalkResultInterrupt)
2695  .value("SKIP", MlirWalkResultSkip);
2696 
2697  //----------------------------------------------------------------------------
2698  // Mapping of Diagnostics.
2699  //----------------------------------------------------------------------------
2700  nb::class_<PyDiagnostic>(m, "Diagnostic")
2701  .def_prop_ro("severity", &PyDiagnostic::getSeverity)
2702  .def_prop_ro("location", &PyDiagnostic::getLocation)
2703  .def_prop_ro("message", &PyDiagnostic::getMessage)
2704  .def_prop_ro("notes", &PyDiagnostic::getNotes)
2705  .def("__str__", [](PyDiagnostic &self) -> nb::str {
2706  if (!self.isValid())
2707  return nb::str("<Invalid Diagnostic>");
2708  return self.getMessage();
2709  });
2710 
2711  nb::class_<PyDiagnostic::DiagnosticInfo>(m, "DiagnosticInfo")
2712  .def("__init__",
2714  new (&self) PyDiagnostic::DiagnosticInfo(diag.getInfo());
2715  })
2716  .def_ro("severity", &PyDiagnostic::DiagnosticInfo::severity)
2717  .def_ro("location", &PyDiagnostic::DiagnosticInfo::location)
2718  .def_ro("message", &PyDiagnostic::DiagnosticInfo::message)
2719  .def_ro("notes", &PyDiagnostic::DiagnosticInfo::notes)
2720  .def("__str__",
2721  [](PyDiagnostic::DiagnosticInfo &self) { return self.message; });
2722 
2723  nb::class_<PyDiagnosticHandler>(m, "DiagnosticHandler")
2724  .def("detach", &PyDiagnosticHandler::detach)
2725  .def_prop_ro("attached", &PyDiagnosticHandler::isAttached)
2726  .def_prop_ro("had_error", &PyDiagnosticHandler::getHadError)
2727  .def("__enter__", &PyDiagnosticHandler::contextEnter)
2728  .def("__exit__", &PyDiagnosticHandler::contextExit,
2729  nb::arg("exc_type").none(), nb::arg("exc_value").none(),
2730  nb::arg("traceback").none());
2731 
2732  //----------------------------------------------------------------------------
2733  // Mapping of MlirContext.
2734  // Note that this is exported as _BaseContext. The containing, Python level
2735  // __init__.py will subclass it with site-specific functionality and set a
2736  // "Context" attribute on this module.
2737  //----------------------------------------------------------------------------
2738  nb::class_<PyMlirContext>(m, "_BaseContext")
2739  .def("__init__",
2740  [](PyMlirContext &self) {
2741  MlirContext context = mlirContextCreateWithThreading(false);
2742  new (&self) PyMlirContext(context);
2743  })
2744  .def_static("_get_live_count", &PyMlirContext::getLiveCount)
2745  .def("_get_context_again",
2746  [](PyMlirContext &self) {
2747  PyMlirContextRef ref = PyMlirContext::forContext(self.get());
2748  return ref.releaseObject();
2749  })
2750  .def("_get_live_operation_count", &PyMlirContext::getLiveOperationCount)
2751  .def("_get_live_operation_objects",
2752  &PyMlirContext::getLiveOperationObjects)
2753  .def("_clear_live_operations", &PyMlirContext::clearLiveOperations)
2754  .def("_clear_live_operations_inside",
2755  nb::overload_cast<MlirOperation>(
2756  &PyMlirContext::clearOperationsInside))
2757  .def("_get_live_module_count", &PyMlirContext::getLiveModuleCount)
2758  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyMlirContext::getCapsule)
2759  .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyMlirContext::createFromCapsule)
2760  .def("__enter__", &PyMlirContext::contextEnter)
2761  .def("__exit__", &PyMlirContext::contextExit, nb::arg("exc_type").none(),
2762  nb::arg("exc_value").none(), nb::arg("traceback").none())
2763  .def_prop_ro_static(
2764  "current",
2765  [](nb::object & /*class*/) {
2766  auto *context = PyThreadContextEntry::getDefaultContext();
2767  if (!context)
2768  return nb::none();
2769  return nb::cast(context);
2770  },
2771  "Gets the Context bound to the current thread or raises ValueError")
2772  .def_prop_ro(
2773  "dialects",
2774  [](PyMlirContext &self) { return PyDialects(self.getRef()); },
2775  "Gets a container for accessing dialects by name")
2776  .def_prop_ro(
2777  "d", [](PyMlirContext &self) { return PyDialects(self.getRef()); },
2778  "Alias for 'dialect'")
2779  .def(
2780  "get_dialect_descriptor",
2781  [=](PyMlirContext &self, std::string &name) {
2782  MlirDialect dialect = mlirContextGetOrLoadDialect(
2783  self.get(), {name.data(), name.size()});
2784  if (mlirDialectIsNull(dialect)) {
2785  throw nb::value_error(
2786  (Twine("Dialect '") + name + "' not found").str().c_str());
2787  }
2788  return PyDialectDescriptor(self.getRef(), dialect);
2789  },
2790  nb::arg("dialect_name"),
2791  "Gets or loads a dialect by name, returning its descriptor object")
2792  .def_prop_rw(
2793  "allow_unregistered_dialects",
2794  [](PyMlirContext &self) -> bool {
2796  },
2797  [](PyMlirContext &self, bool value) {
2799  })
2800  .def("attach_diagnostic_handler", &PyMlirContext::attachDiagnosticHandler,
2801  nb::arg("callback"),
2802  "Attaches a diagnostic handler that will receive callbacks")
2803  .def(
2804  "enable_multithreading",
2805  [](PyMlirContext &self, bool enable) {
2806  mlirContextEnableMultithreading(self.get(), enable);
2807  },
2808  nb::arg("enable"))
2809  .def(
2810  "is_registered_operation",
2811  [](PyMlirContext &self, std::string &name) {
2813  self.get(), MlirStringRef{name.data(), name.size()});
2814  },
2815  nb::arg("operation_name"))
2816  .def(
2817  "append_dialect_registry",
2818  [](PyMlirContext &self, PyDialectRegistry &registry) {
2819  mlirContextAppendDialectRegistry(self.get(), registry);
2820  },
2821  nb::arg("registry"))
2822  .def_prop_rw("emit_error_diagnostics", nullptr,
2823  &PyMlirContext::setEmitErrorDiagnostics,
2824  "Emit error diagnostics to diagnostic handlers. By default "
2825  "error diagnostics are captured and reported through "
2826  "MLIRError exceptions.")
2827  .def("load_all_available_dialects", [](PyMlirContext &self) {
2829  });
2830 
2831  //----------------------------------------------------------------------------
2832  // Mapping of PyDialectDescriptor
2833  //----------------------------------------------------------------------------
2834  nb::class_<PyDialectDescriptor>(m, "DialectDescriptor")
2835  .def_prop_ro("namespace",
2836  [](PyDialectDescriptor &self) {
2838  return nb::str(ns.data, ns.length);
2839  })
2840  .def("__repr__", [](PyDialectDescriptor &self) {
2842  std::string repr("<DialectDescriptor ");
2843  repr.append(ns.data, ns.length);
2844  repr.append(">");
2845  return repr;
2846  });
2847 
2848  //----------------------------------------------------------------------------
2849  // Mapping of PyDialects
2850  //----------------------------------------------------------------------------
2851  nb::class_<PyDialects>(m, "Dialects")
2852  .def("__getitem__",
2853  [=](PyDialects &self, std::string keyName) {
2854  MlirDialect dialect =
2855  self.getDialectForKey(keyName, /*attrError=*/false);
2856  nb::object descriptor =
2857  nb::cast(PyDialectDescriptor{self.getContext(), dialect});
2858  return createCustomDialectWrapper(keyName, std::move(descriptor));
2859  })
2860  .def("__getattr__", [=](PyDialects &self, std::string attrName) {
2861  MlirDialect dialect =
2862  self.getDialectForKey(attrName, /*attrError=*/true);
2863  nb::object descriptor =
2864  nb::cast(PyDialectDescriptor{self.getContext(), dialect});
2865  return createCustomDialectWrapper(attrName, std::move(descriptor));
2866  });
2867 
2868  //----------------------------------------------------------------------------
2869  // Mapping of PyDialect
2870  //----------------------------------------------------------------------------
2871  nb::class_<PyDialect>(m, "Dialect")
2872  .def(nb::init<nb::object>(), nb::arg("descriptor"))
2873  .def_prop_ro("descriptor",
2874  [](PyDialect &self) { return self.getDescriptor(); })
2875  .def("__repr__", [](nb::object self) {
2876  auto clazz = self.attr("__class__");
2877  return nb::str("<Dialect ") +
2878  self.attr("descriptor").attr("namespace") + nb::str(" (class ") +
2879  clazz.attr("__module__") + nb::str(".") +
2880  clazz.attr("__name__") + nb::str(")>");
2881  });
2882 
2883  //----------------------------------------------------------------------------
2884  // Mapping of PyDialectRegistry
2885  //----------------------------------------------------------------------------
2886  nb::class_<PyDialectRegistry>(m, "DialectRegistry")
2887  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyDialectRegistry::getCapsule)
2888  .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyDialectRegistry::createFromCapsule)
2889  .def(nb::init<>());
2890 
2891  //----------------------------------------------------------------------------
2892  // Mapping of Location
2893  //----------------------------------------------------------------------------
2894  nb::class_<PyLocation>(m, "Location")
2895  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyLocation::getCapsule)
2896  .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyLocation::createFromCapsule)
2897  .def("__enter__", &PyLocation::contextEnter)
2898  .def("__exit__", &PyLocation::contextExit, nb::arg("exc_type").none(),
2899  nb::arg("exc_value").none(), nb::arg("traceback").none())
2900  .def("__eq__",
2901  [](PyLocation &self, PyLocation &other) -> bool {
2902  return mlirLocationEqual(self, other);
2903  })
2904  .def("__eq__", [](PyLocation &self, nb::object other) { return false; })
2905  .def_prop_ro_static(
2906  "current",
2907  [](nb::object & /*class*/) {
2908  auto *loc = PyThreadContextEntry::getDefaultLocation();
2909  if (!loc)
2910  throw nb::value_error("No current Location");
2911  return loc;
2912  },
2913  "Gets the Location bound to the current thread or raises ValueError")
2914  .def_static(
2915  "unknown",
2916  [](DefaultingPyMlirContext context) {
2917  return PyLocation(context->getRef(),
2918  mlirLocationUnknownGet(context->get()));
2919  },
2920  nb::arg("context").none() = nb::none(),
2921  "Gets a Location representing an unknown location")
2922  .def_static(
2923  "callsite",
2924  [](PyLocation callee, const std::vector<PyLocation> &frames,
2925  DefaultingPyMlirContext context) {
2926  if (frames.empty())
2927  throw nb::value_error("No caller frames provided");
2928  MlirLocation caller = frames.back().get();
2929  for (const PyLocation &frame :
2930  llvm::reverse(llvm::ArrayRef(frames).drop_back()))
2931  caller = mlirLocationCallSiteGet(frame.get(), caller);
2932  return PyLocation(context->getRef(),
2933  mlirLocationCallSiteGet(callee.get(), caller));
2934  },
2935  nb::arg("callee"), nb::arg("frames"),
2936  nb::arg("context").none() = nb::none(),
2938  .def_static(
2939  "file",
2940  [](std::string filename, int line, int col,
2941  DefaultingPyMlirContext context) {
2942  return PyLocation(
2943  context->getRef(),
2945  context->get(), toMlirStringRef(filename), line, col));
2946  },
2947  nb::arg("filename"), nb::arg("line"), nb::arg("col"),
2948  nb::arg("context").none() = nb::none(),
2950  .def_static(
2951  "file",
2952  [](std::string filename, int startLine, int startCol, int endLine,
2953  int endCol, DefaultingPyMlirContext context) {
2954  return PyLocation(context->getRef(),
2956  context->get(), toMlirStringRef(filename),
2957  startLine, startCol, endLine, endCol));
2958  },
2959  nb::arg("filename"), nb::arg("start_line"), nb::arg("start_col"),
2960  nb::arg("end_line"), nb::arg("end_col"),
2961  nb::arg("context").none() = nb::none(), kContextGetFileRangeDocstring)
2962  .def_static(
2963  "fused",
2964  [](const std::vector<PyLocation> &pyLocations,
2965  std::optional<PyAttribute> metadata,
2966  DefaultingPyMlirContext context) {
2968  locations.reserve(pyLocations.size());
2969  for (auto &pyLocation : pyLocations)
2970  locations.push_back(pyLocation.get());
2971  MlirLocation location = mlirLocationFusedGet(
2972  context->get(), locations.size(), locations.data(),
2973  metadata ? metadata->get() : MlirAttribute{0});
2974  return PyLocation(context->getRef(), location);
2975  },
2976  nb::arg("locations"), nb::arg("metadata").none() = nb::none(),
2977  nb::arg("context").none() = nb::none(),
2979  .def_static(
2980  "name",
2981  [](std::string name, std::optional<PyLocation> childLoc,
2982  DefaultingPyMlirContext context) {
2983  return PyLocation(
2984  context->getRef(),
2986  context->get(), toMlirStringRef(name),
2987  childLoc ? childLoc->get()
2988  : mlirLocationUnknownGet(context->get())));
2989  },
2990  nb::arg("name"), nb::arg("childLoc").none() = nb::none(),
2991  nb::arg("context").none() = nb::none(),
2993  .def_static(
2994  "from_attr",
2995  [](PyAttribute &attribute, DefaultingPyMlirContext context) {
2996  return PyLocation(context->getRef(),
2997  mlirLocationFromAttribute(attribute));
2998  },
2999  nb::arg("attribute"), nb::arg("context").none() = nb::none(),
3000  "Gets a Location from a LocationAttr")
3001  .def_prop_ro(
3002  "context",
3003  [](PyLocation &self) { return self.getContext().getObject(); },
3004  "Context that owns the Location")
3005  .def_prop_ro(
3006  "attr",
3007  [](PyLocation &self) { return mlirLocationGetAttribute(self); },
3008  "Get the underlying LocationAttr")
3009  .def(
3010  "emit_error",
3011  [](PyLocation &self, std::string message) {
3012  mlirEmitError(self, message.c_str());
3013  },
3014  nb::arg("message"), "Emits an error at this location")
3015  .def("__repr__", [](PyLocation &self) {
3016  PyPrintAccumulator printAccum;
3017  mlirLocationPrint(self, printAccum.getCallback(),
3018  printAccum.getUserData());
3019  return printAccum.join();
3020  });
3021 
3022  //----------------------------------------------------------------------------
3023  // Mapping of Module
3024  //----------------------------------------------------------------------------
3025  nb::class_<PyModule>(m, "Module", nb::is_weak_referenceable())
3026  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyModule::getCapsule)
3027  .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyModule::createFromCapsule)
3028  .def_static(
3029  "parse",
3030  [](const std::string &moduleAsm, DefaultingPyMlirContext context) {
3031  PyMlirContext::ErrorCapture errors(context->getRef());
3032  MlirModule module = mlirModuleCreateParse(
3033  context->get(), toMlirStringRef(moduleAsm));
3034  if (mlirModuleIsNull(module))
3035  throw MLIRError("Unable to parse module assembly", errors.take());
3036  return PyModule::forModule(module).releaseObject();
3037  },
3038  nb::arg("asm"), nb::arg("context").none() = nb::none(),
3040  .def_static(
3041  "parse",
3042  [](nb::bytes moduleAsm, DefaultingPyMlirContext context) {
3043  PyMlirContext::ErrorCapture errors(context->getRef());
3044  MlirModule module = mlirModuleCreateParse(
3045  context->get(), toMlirStringRef(moduleAsm));
3046  if (mlirModuleIsNull(module))
3047  throw MLIRError("Unable to parse module assembly", errors.take());
3048  return PyModule::forModule(module).releaseObject();
3049  },
3050  nb::arg("asm"), nb::arg("context").none() = nb::none(),
3052  .def_static(
3053  "parseFile",
3054  [](const std::string &path, DefaultingPyMlirContext context) {
3055  PyMlirContext::ErrorCapture errors(context->getRef());
3056  MlirModule module = mlirModuleCreateParseFromFile(
3057  context->get(), toMlirStringRef(path));
3058  if (mlirModuleIsNull(module))
3059  throw MLIRError("Unable to parse module assembly", errors.take());
3060  return PyModule::forModule(module).releaseObject();
3061  },
3062  nb::arg("path"), nb::arg("context").none() = nb::none(),
3064  .def_static(
3065  "create",
3066  [](DefaultingPyLocation loc) {
3067  MlirModule module = mlirModuleCreateEmpty(loc);
3068  return PyModule::forModule(module).releaseObject();
3069  },
3070  nb::arg("loc").none() = nb::none(), "Creates an empty module")
3071  .def_prop_ro(
3072  "context",
3073  [](PyModule &self) { return self.getContext().getObject(); },
3074  "Context that created the Module")
3075  .def_prop_ro(
3076  "operation",
3077  [](PyModule &self) {
3078  return PyOperation::forOperation(self.getContext(),
3079  mlirModuleGetOperation(self.get()),
3080  self.getRef().releaseObject())
3081  .releaseObject();
3082  },
3083  "Accesses the module as an operation")
3084  .def_prop_ro(
3085  "body",
3086  [](PyModule &self) {
3087  PyOperationRef moduleOp = PyOperation::forOperation(
3088  self.getContext(), mlirModuleGetOperation(self.get()),
3089  self.getRef().releaseObject());
3090  PyBlock returnBlock(moduleOp, mlirModuleGetBody(self.get()));
3091  return returnBlock;
3092  },
3093  "Return the block for this module")
3094  .def(
3095  "dump",
3096  [](PyModule &self) {
3098  },
3100  .def(
3101  "__str__",
3102  [](nb::object self) {
3103  // Defer to the operation's __str__.
3104  return self.attr("operation").attr("__str__")();
3105  },
3107 
3108  //----------------------------------------------------------------------------
3109  // Mapping of Operation.
3110  //----------------------------------------------------------------------------
3111  nb::class_<PyOperationBase>(m, "_OperationBase")
3112  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR,
3113  [](PyOperationBase &self) {
3114  return self.getOperation().getCapsule();
3115  })
3116  .def("__eq__",
3117  [](PyOperationBase &self, PyOperationBase &other) {
3118  return &self.getOperation() == &other.getOperation();
3119  })
3120  .def("__eq__",
3121  [](PyOperationBase &self, nb::object other) { return false; })
3122  .def("__hash__",
3123  [](PyOperationBase &self) {
3124  return static_cast<size_t>(llvm::hash_value(&self.getOperation()));
3125  })
3126  .def_prop_ro("attributes",
3127  [](PyOperationBase &self) {
3128  return PyOpAttributeMap(self.getOperation().getRef());
3129  })
3130  .def_prop_ro(
3131  "context",
3132  [](PyOperationBase &self) {
3133  PyOperation &concreteOperation = self.getOperation();
3134  concreteOperation.checkValid();
3135  return concreteOperation.getContext().getObject();
3136  },
3137  "Context that owns the Operation")
3138  .def_prop_ro("name",
3139  [](PyOperationBase &self) {
3140  auto &concreteOperation = self.getOperation();
3141  concreteOperation.checkValid();
3142  MlirOperation operation = concreteOperation.get();
3143  MlirStringRef name =
3145  return nb::str(name.data, name.length);
3146  })
3147  .def_prop_ro("operands",
3148  [](PyOperationBase &self) {
3149  return PyOpOperandList(self.getOperation().getRef());
3150  })
3151  .def_prop_ro("regions",
3152  [](PyOperationBase &self) {
3153  return PyRegionList(self.getOperation().getRef());
3154  })
3155  .def_prop_ro(
3156  "results",
3157  [](PyOperationBase &self) {
3158  return PyOpResultList(self.getOperation().getRef());
3159  },
3160  "Returns the list of Operation results.")
3161  .def_prop_ro(
3162  "result",
3163  [](PyOperationBase &self) {
3164  auto &operation = self.getOperation();
3165  return PyOpResult(operation.getRef(), getUniqueResult(operation))
3166  .maybeDownCast();
3167  },
3168  "Shortcut to get an op result if it has only one (throws an error "
3169  "otherwise).")
3170  .def_prop_ro(
3171  "location",
3172  [](PyOperationBase &self) {
3173  PyOperation &operation = self.getOperation();
3174  return PyLocation(operation.getContext(),
3175  mlirOperationGetLocation(operation.get()));
3176  },
3177  "Returns the source location the operation was defined or derived "
3178  "from.")
3179  .def_prop_ro("parent",
3180  [](PyOperationBase &self) -> nb::object {
3181  auto parent = self.getOperation().getParentOperation();
3182  if (parent)
3183  return parent->getObject();
3184  return nb::none();
3185  })
3186  .def(
3187  "__str__",
3188  [](PyOperationBase &self) {
3189  return self.getAsm(/*binary=*/false,
3190  /*largeElementsLimit=*/std::nullopt,
3191  /*enableDebugInfo=*/false,
3192  /*prettyDebugInfo=*/false,
3193  /*printGenericOpForm=*/false,
3194  /*useLocalScope=*/false,
3195  /*assumeVerified=*/false,
3196  /*skipRegions=*/false);
3197  },
3198  "Returns the assembly form of the operation.")
3199  .def("print",
3200  nb::overload_cast<PyAsmState &, nb::object, bool>(
3202  nb::arg("state"), nb::arg("file").none() = nb::none(),
3203  nb::arg("binary") = false, kOperationPrintStateDocstring)
3204  .def("print",
3205  nb::overload_cast<std::optional<int64_t>, bool, bool, bool, bool,
3206  bool, nb::object, bool, bool>(
3208  // Careful: Lots of arguments must match up with print method.
3209  nb::arg("large_elements_limit").none() = nb::none(),
3210  nb::arg("enable_debug_info") = false,
3211  nb::arg("pretty_debug_info") = false,
3212  nb::arg("print_generic_op_form") = false,
3213  nb::arg("use_local_scope") = false,
3214  nb::arg("assume_verified") = false,
3215  nb::arg("file").none() = nb::none(), nb::arg("binary") = false,
3216  nb::arg("skip_regions") = false, kOperationPrintDocstring)
3217  .def("write_bytecode", &PyOperationBase::writeBytecode, nb::arg("file"),
3218  nb::arg("desired_version").none() = nb::none(),
3220  .def("get_asm", &PyOperationBase::getAsm,
3221  // Careful: Lots of arguments must match up with get_asm method.
3222  nb::arg("binary") = false,
3223  nb::arg("large_elements_limit").none() = nb::none(),
3224  nb::arg("enable_debug_info") = false,
3225  nb::arg("pretty_debug_info") = false,
3226  nb::arg("print_generic_op_form") = false,
3227  nb::arg("use_local_scope") = false,
3228  nb::arg("assume_verified") = false, nb::arg("skip_regions") = false,
3230  .def("verify", &PyOperationBase::verify,
3231  "Verify the operation. Raises MLIRError if verification fails, and "
3232  "returns true otherwise.")
3233  .def("move_after", &PyOperationBase::moveAfter, nb::arg("other"),
3234  "Puts self immediately after the other operation in its parent "
3235  "block.")
3236  .def("move_before", &PyOperationBase::moveBefore, nb::arg("other"),
3237  "Puts self immediately before the other operation in its parent "
3238  "block.")
3239  .def(
3240  "clone",
3241  [](PyOperationBase &self, nb::object ip) {
3242  return self.getOperation().clone(ip);
3243  },
3244  nb::arg("ip").none() = nb::none())
3245  .def(
3246  "detach_from_parent",
3247  [](PyOperationBase &self) {
3248  PyOperation &operation = self.getOperation();
3249  operation.checkValid();
3250  if (!operation.isAttached())
3251  throw nb::value_error("Detached operation has no parent.");
3252 
3253  operation.detachFromParent();
3254  return operation.createOpView();
3255  },
3256  "Detaches the operation from its parent block.")
3257  .def("erase", [](PyOperationBase &self) { self.getOperation().erase(); })
3258  .def("walk", &PyOperationBase::walk, nb::arg("callback"),
3259  nb::arg("walk_order") = MlirWalkPostOrder);
3260 
3261  nb::class_<PyOperation, PyOperationBase>(m, "Operation")
3262  .def_static(
3263  "create",
3264  [](std::string_view name,
3265  std::optional<std::vector<PyType *>> results,
3266  std::optional<std::vector<PyValue *>> operands,
3267  std::optional<nb::dict> attributes,
3268  std::optional<std::vector<PyBlock *>> successors, int regions,
3269  DefaultingPyLocation location, const nb::object &maybeIp,
3270  bool inferType) {
3271  // Unpack/validate operands.
3272  llvm::SmallVector<MlirValue, 4> mlirOperands;
3273  if (operands) {
3274  mlirOperands.reserve(operands->size());
3275  for (PyValue *operand : *operands) {
3276  if (!operand)
3277  throw nb::value_error("operand value cannot be None");
3278  mlirOperands.push_back(operand->get());
3279  }
3280  }
3281 
3282  return PyOperation::create(name, results, mlirOperands, attributes,
3283  successors, regions, location, maybeIp,
3284  inferType);
3285  },
3286  nb::arg("name"), nb::arg("results").none() = nb::none(),
3287  nb::arg("operands").none() = nb::none(),
3288  nb::arg("attributes").none() = nb::none(),
3289  nb::arg("successors").none() = nb::none(), nb::arg("regions") = 0,
3290  nb::arg("loc").none() = nb::none(), nb::arg("ip").none() = nb::none(),
3291  nb::arg("infer_type") = false, kOperationCreateDocstring)
3292  .def_static(
3293  "parse",
3294  [](const std::string &sourceStr, const std::string &sourceName,
3295  DefaultingPyMlirContext context) {
3296  return PyOperation::parse(context->getRef(), sourceStr, sourceName)
3297  ->createOpView();
3298  },
3299  nb::arg("source"), nb::kw_only(), nb::arg("source_name") = "",
3300  nb::arg("context").none() = nb::none(),
3301  "Parses an operation. Supports both text assembly format and binary "
3302  "bytecode format.")
3303  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyOperation::getCapsule)
3304  .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyOperation::createFromCapsule)
3305  .def_prop_ro("operation", [](nb::object self) { return self; })
3306  .def_prop_ro("opview", &PyOperation::createOpView)
3307  .def_prop_ro(
3308  "successors",
3309  [](PyOperationBase &self) {
3310  return PyOpSuccessors(self.getOperation().getRef());
3311  },
3312  "Returns the list of Operation successors.");
3313 
3314  auto opViewClass =
3315  nb::class_<PyOpView, PyOperationBase>(m, "OpView")
3316  .def(nb::init<nb::object>(), nb::arg("operation"))
3317  .def(
3318  "__init__",
3319  [](PyOpView *self, std::string_view name,
3320  std::tuple<int, bool> opRegionSpec,
3321  nb::object operandSegmentSpecObj,
3322  nb::object resultSegmentSpecObj,
3323  std::optional<nb::list> resultTypeList, nb::list operandList,
3324  std::optional<nb::dict> attributes,
3325  std::optional<std::vector<PyBlock *>> successors,
3326  std::optional<int> regions, DefaultingPyLocation location,
3327  const nb::object &maybeIp) {
3328  new (self) PyOpView(PyOpView::buildGeneric(
3329  name, opRegionSpec, operandSegmentSpecObj,
3330  resultSegmentSpecObj, resultTypeList, operandList,
3331  attributes, successors, regions, location, maybeIp));
3332  },
3333  nb::arg("name"), nb::arg("opRegionSpec"),
3334  nb::arg("operandSegmentSpecObj").none() = nb::none(),
3335  nb::arg("resultSegmentSpecObj").none() = nb::none(),
3336  nb::arg("results").none() = nb::none(),
3337  nb::arg("operands").none() = nb::none(),
3338  nb::arg("attributes").none() = nb::none(),
3339  nb::arg("successors").none() = nb::none(),
3340  nb::arg("regions").none() = nb::none(),
3341  nb::arg("loc").none() = nb::none(),
3342  nb::arg("ip").none() = nb::none())
3343 
3344  .def_prop_ro("operation", &PyOpView::getOperationObject)
3345  .def_prop_ro("opview", [](nb::object self) { return self; })
3346  .def(
3347  "__str__",
3348  [](PyOpView &self) { return nb::str(self.getOperationObject()); })
3349  .def_prop_ro(
3350  "successors",
3351  [](PyOperationBase &self) {
3352  return PyOpSuccessors(self.getOperation().getRef());
3353  },
3354  "Returns the list of Operation successors.");
3355  opViewClass.attr("_ODS_REGIONS") = nb::make_tuple(0, true);
3356  opViewClass.attr("_ODS_OPERAND_SEGMENTS") = nb::none();
3357  opViewClass.attr("_ODS_RESULT_SEGMENTS") = nb::none();
3358  // It is faster to pass the operation_name, ods_regions, and
3359  // ods_operand_segments/ods_result_segments as arguments to the constructor,
3360  // rather than to access them as attributes.
3361  opViewClass.attr("build_generic") = classmethod(
3362  [](nb::handle cls, std::optional<nb::list> resultTypeList,
3363  nb::list operandList, std::optional<nb::dict> attributes,
3364  std::optional<std::vector<PyBlock *>> successors,
3365  std::optional<int> regions, DefaultingPyLocation location,
3366  const nb::object &maybeIp) {
3367  std::string name = nb::cast<std::string>(cls.attr("OPERATION_NAME"));
3368  std::tuple<int, bool> opRegionSpec =
3369  nb::cast<std::tuple<int, bool>>(cls.attr("_ODS_REGIONS"));
3370  nb::object operandSegmentSpec = cls.attr("_ODS_OPERAND_SEGMENTS");
3371  nb::object resultSegmentSpec = cls.attr("_ODS_RESULT_SEGMENTS");
3372  return PyOpView::buildGeneric(name, opRegionSpec, operandSegmentSpec,
3373  resultSegmentSpec, resultTypeList,
3374  operandList, attributes, successors,
3375  regions, location, maybeIp);
3376  },
3377  nb::arg("cls"), nb::arg("results").none() = nb::none(),
3378  nb::arg("operands").none() = nb::none(),
3379  nb::arg("attributes").none() = nb::none(),
3380  nb::arg("successors").none() = nb::none(),
3381  nb::arg("regions").none() = nb::none(),
3382  nb::arg("loc").none() = nb::none(), nb::arg("ip").none() = nb::none(),
3383  "Builds a specific, generated OpView based on class level attributes.");
3384  opViewClass.attr("parse") = classmethod(
3385  [](const nb::object &cls, const std::string &sourceStr,
3386  const std::string &sourceName, DefaultingPyMlirContext context) {
3387  PyOperationRef parsed =
3388  PyOperation::parse(context->getRef(), sourceStr, sourceName);
3389 
3390  // Check if the expected operation was parsed, and cast to to the
3391  // appropriate `OpView` subclass if successful.
3392  // NOTE: This accesses attributes that have been automatically added to
3393  // `OpView` subclasses, and is not intended to be used on `OpView`
3394  // directly.
3395  std::string clsOpName =
3396  nb::cast<std::string>(cls.attr("OPERATION_NAME"));
3397  MlirStringRef identifier =
3399  std::string_view parsedOpName(identifier.data, identifier.length);
3400  if (clsOpName != parsedOpName)
3401  throw MLIRError(Twine("Expected a '") + clsOpName + "' op, got: '" +
3402  parsedOpName + "'");
3403  return PyOpView::constructDerived(cls, parsed.getObject());
3404  },
3405  nb::arg("cls"), nb::arg("source"), nb::kw_only(),
3406  nb::arg("source_name") = "", nb::arg("context").none() = nb::none(),
3407  "Parses a specific, generated OpView based on class level attributes");
3408 
3409  //----------------------------------------------------------------------------
3410  // Mapping of PyRegion.
3411  //----------------------------------------------------------------------------
3412  nb::class_<PyRegion>(m, "Region")
3413  .def_prop_ro(
3414  "blocks",
3415  [](PyRegion &self) {
3416  return PyBlockList(self.getParentOperation(), self.get());
3417  },
3418  "Returns a forward-optimized sequence of blocks.")
3419  .def_prop_ro(
3420  "owner",
3421  [](PyRegion &self) {
3422  return self.getParentOperation()->createOpView();
3423  },
3424  "Returns the operation owning this region.")
3425  .def(
3426  "__iter__",
3427  [](PyRegion &self) {
3428  self.checkValid();
3429  MlirBlock firstBlock = mlirRegionGetFirstBlock(self.get());
3430  return PyBlockIterator(self.getParentOperation(), firstBlock);
3431  },
3432  "Iterates over blocks in the region.")
3433  .def("__eq__",
3434  [](PyRegion &self, PyRegion &other) {
3435  return self.get().ptr == other.get().ptr;
3436  })
3437  .def("__eq__", [](PyRegion &self, nb::object &other) { return false; });
3438 
3439  //----------------------------------------------------------------------------
3440  // Mapping of PyBlock.
3441  //----------------------------------------------------------------------------
3442  nb::class_<PyBlock>(m, "Block")
3443  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyBlock::getCapsule)
3444  .def_prop_ro(
3445  "owner",
3446  [](PyBlock &self) {
3447  return self.getParentOperation()->createOpView();
3448  },
3449  "Returns the owning operation of this block.")
3450  .def_prop_ro(
3451  "region",
3452  [](PyBlock &self) {
3453  MlirRegion region = mlirBlockGetParentRegion(self.get());
3454  return PyRegion(self.getParentOperation(), region);
3455  },
3456  "Returns the owning region of this block.")
3457  .def_prop_ro(
3458  "arguments",
3459  [](PyBlock &self) {
3460  return PyBlockArgumentList(self.getParentOperation(), self.get());
3461  },
3462  "Returns a list of block arguments.")
3463  .def(
3464  "add_argument",
3465  [](PyBlock &self, const PyType &type, const PyLocation &loc) {
3466  return mlirBlockAddArgument(self.get(), type, loc);
3467  },
3468  "Append an argument of the specified type to the block and returns "
3469  "the newly added argument.")
3470  .def(
3471  "erase_argument",
3472  [](PyBlock &self, unsigned index) {
3473  return mlirBlockEraseArgument(self.get(), index);
3474  },
3475  "Erase the argument at 'index' and remove it from the argument list.")
3476  .def_prop_ro(
3477  "operations",
3478  [](PyBlock &self) {
3479  return PyOperationList(self.getParentOperation(), self.get());
3480  },
3481  "Returns a forward-optimized sequence of operations.")
3482  .def_static(
3483  "create_at_start",
3484  [](PyRegion &parent, const nb::sequence &pyArgTypes,
3485  const std::optional<nb::sequence> &pyArgLocs) {
3486  parent.checkValid();
3487  MlirBlock block = createBlock(pyArgTypes, pyArgLocs);
3488  mlirRegionInsertOwnedBlock(parent, 0, block);
3489  return PyBlock(parent.getParentOperation(), block);
3490  },
3491  nb::arg("parent"), nb::arg("arg_types") = nb::list(),
3492  nb::arg("arg_locs") = std::nullopt,
3493  "Creates and returns a new Block at the beginning of the given "
3494  "region (with given argument types and locations).")
3495  .def(
3496  "append_to",
3497  [](PyBlock &self, PyRegion &region) {
3498  MlirBlock b = self.get();
3500  mlirBlockDetach(b);
3501  mlirRegionAppendOwnedBlock(region.get(), b);
3502  },
3503  "Append this block to a region, transferring ownership if necessary")
3504  .def(
3505  "create_before",
3506  [](PyBlock &self, const nb::args &pyArgTypes,
3507  const std::optional<nb::sequence> &pyArgLocs) {
3508  self.checkValid();
3509  MlirBlock block =
3510  createBlock(nb::cast<nb::sequence>(pyArgTypes), pyArgLocs);
3511  MlirRegion region = mlirBlockGetParentRegion(self.get());
3512  mlirRegionInsertOwnedBlockBefore(region, self.get(), block);
3513  return PyBlock(self.getParentOperation(), block);
3514  },
3515  nb::arg("arg_types"), nb::kw_only(),
3516  nb::arg("arg_locs") = std::nullopt,
3517  "Creates and returns a new Block before this block "
3518  "(with given argument types and locations).")
3519  .def(
3520  "create_after",
3521  [](PyBlock &self, const nb::args &pyArgTypes,
3522  const std::optional<nb::sequence> &pyArgLocs) {
3523  self.checkValid();
3524  MlirBlock block =
3525  createBlock(nb::cast<nb::sequence>(pyArgTypes), pyArgLocs);
3526  MlirRegion region = mlirBlockGetParentRegion(self.get());
3527  mlirRegionInsertOwnedBlockAfter(region, self.get(), block);
3528  return PyBlock(self.getParentOperation(), block);
3529  },
3530  nb::arg("arg_types"), nb::kw_only(),
3531  nb::arg("arg_locs") = std::nullopt,
3532  "Creates and returns a new Block after this block "
3533  "(with given argument types and locations).")
3534  .def(
3535  "__iter__",
3536  [](PyBlock &self) {
3537  self.checkValid();
3538  MlirOperation firstOperation =
3540  return PyOperationIterator(self.getParentOperation(),
3541  firstOperation);
3542  },
3543  "Iterates over operations in the block.")
3544  .def("__eq__",
3545  [](PyBlock &self, PyBlock &other) {
3546  return self.get().ptr == other.get().ptr;
3547  })
3548  .def("__eq__", [](PyBlock &self, nb::object &other) { return false; })
3549  .def("__hash__",
3550  [](PyBlock &self) {
3551  return static_cast<size_t>(llvm::hash_value(self.get().ptr));
3552  })
3553  .def(
3554  "__str__",
3555  [](PyBlock &self) {
3556  self.checkValid();
3557  PyPrintAccumulator printAccum;
3558  mlirBlockPrint(self.get(), printAccum.getCallback(),
3559  printAccum.getUserData());
3560  return printAccum.join();
3561  },
3562  "Returns the assembly form of the block.")
3563  .def(
3564  "append",
3565  [](PyBlock &self, PyOperationBase &operation) {
3566  if (operation.getOperation().isAttached())
3567  operation.getOperation().detachFromParent();
3568 
3569  MlirOperation mlirOperation = operation.getOperation().get();
3570  mlirBlockAppendOwnedOperation(self.get(), mlirOperation);
3571  operation.getOperation().setAttached(
3572  self.getParentOperation().getObject());
3573  },
3574  nb::arg("operation"),
3575  "Appends an operation to this block. If the operation is currently "
3576  "in another block, it will be moved.");
3577 
3578  //----------------------------------------------------------------------------
3579  // Mapping of PyInsertionPoint.
3580  //----------------------------------------------------------------------------
3581 
3582  nb::class_<PyInsertionPoint>(m, "InsertionPoint")
3583  .def(nb::init<PyBlock &>(), nb::arg("block"),
3584  "Inserts after the last operation but still inside the block.")
3585  .def("__enter__", &PyInsertionPoint::contextEnter)
3586  .def("__exit__", &PyInsertionPoint::contextExit,
3587  nb::arg("exc_type").none(), nb::arg("exc_value").none(),
3588  nb::arg("traceback").none())
3589  .def_prop_ro_static(
3590  "current",
3591  [](nb::object & /*class*/) {
3592  auto *ip = PyThreadContextEntry::getDefaultInsertionPoint();
3593  if (!ip)
3594  throw nb::value_error("No current InsertionPoint");
3595  return ip;
3596  },
3597  "Gets the InsertionPoint bound to the current thread or raises "
3598  "ValueError if none has been set")
3599  .def(nb::init<PyOperationBase &>(), nb::arg("beforeOperation"),
3600  "Inserts before a referenced operation.")
3601  .def_static("at_block_begin", &PyInsertionPoint::atBlockBegin,
3602  nb::arg("block"), "Inserts at the beginning of the block.")
3603  .def_static("at_block_terminator", &PyInsertionPoint::atBlockTerminator,
3604  nb::arg("block"), "Inserts before the block terminator.")
3605  .def("insert", &PyInsertionPoint::insert, nb::arg("operation"),
3606  "Inserts an operation.")
3607  .def_prop_ro(
3608  "block", [](PyInsertionPoint &self) { return self.getBlock(); },
3609  "Returns the block that this InsertionPoint points to.")
3610  .def_prop_ro(
3611  "ref_operation",
3612  [](PyInsertionPoint &self) -> nb::object {
3613  auto refOperation = self.getRefOperation();
3614  if (refOperation)
3615  return refOperation->getObject();
3616  return nb::none();
3617  },
3618  "The reference operation before which new operations are "
3619  "inserted, or None if the insertion point is at the end of "
3620  "the block");
3621 
3622  //----------------------------------------------------------------------------
3623  // Mapping of PyAttribute.
3624  //----------------------------------------------------------------------------
3625  nb::class_<PyAttribute>(m, "Attribute")
3626  // Delegate to the PyAttribute copy constructor, which will also lifetime
3627  // extend the backing context which owns the MlirAttribute.
3628  .def(nb::init<PyAttribute &>(), nb::arg("cast_from_type"),
3629  "Casts the passed attribute to the generic Attribute")
3630  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyAttribute::getCapsule)
3631  .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyAttribute::createFromCapsule)
3632  .def_static(
3633  "parse",
3634  [](const std::string &attrSpec, DefaultingPyMlirContext context) {
3635  PyMlirContext::ErrorCapture errors(context->getRef());
3636  MlirAttribute attr = mlirAttributeParseGet(
3637  context->get(), toMlirStringRef(attrSpec));
3638  if (mlirAttributeIsNull(attr))
3639  throw MLIRError("Unable to parse attribute", errors.take());
3640  return attr;
3641  },
3642  nb::arg("asm"), nb::arg("context").none() = nb::none(),
3643  "Parses an attribute from an assembly form. Raises an MLIRError on "
3644  "failure.")
3645  .def_prop_ro(
3646  "context",
3647  [](PyAttribute &self) { return self.getContext().getObject(); },
3648  "Context that owns the Attribute")
3649  .def_prop_ro("type",
3650  [](PyAttribute &self) { return mlirAttributeGetType(self); })
3651  .def(
3652  "get_named",
3653  [](PyAttribute &self, std::string name) {
3654  return PyNamedAttribute(self, std::move(name));
3655  },
3656  nb::keep_alive<0, 1>(), "Binds a name to the attribute")
3657  .def("__eq__",
3658  [](PyAttribute &self, PyAttribute &other) { return self == other; })
3659  .def("__eq__", [](PyAttribute &self, nb::object &other) { return false; })
3660  .def("__hash__",
3661  [](PyAttribute &self) {
3662  return static_cast<size_t>(llvm::hash_value(self.get().ptr));
3663  })
3664  .def(
3665  "dump", [](PyAttribute &self) { mlirAttributeDump(self); },
3667  .def(
3668  "__str__",
3669  [](PyAttribute &self) {
3670  PyPrintAccumulator printAccum;
3671  mlirAttributePrint(self, printAccum.getCallback(),
3672  printAccum.getUserData());
3673  return printAccum.join();
3674  },
3675  "Returns the assembly form of the Attribute.")
3676  .def("__repr__",
3677  [](PyAttribute &self) {
3678  // Generally, assembly formats are not printed for __repr__ because
3679  // this can cause exceptionally long debug output and exceptions.
3680  // However, attribute values are generally considered useful and
3681  // are printed. This may need to be re-evaluated if debug dumps end
3682  // up being excessive.
3683  PyPrintAccumulator printAccum;
3684  printAccum.parts.append("Attribute(");
3685  mlirAttributePrint(self, printAccum.getCallback(),
3686  printAccum.getUserData());
3687  printAccum.parts.append(")");
3688  return printAccum.join();
3689  })
3690  .def_prop_ro("typeid",
3691  [](PyAttribute &self) -> MlirTypeID {
3692  MlirTypeID mlirTypeID = mlirAttributeGetTypeID(self);
3693  assert(!mlirTypeIDIsNull(mlirTypeID) &&
3694  "mlirTypeID was expected to be non-null.");
3695  return mlirTypeID;
3696  })
3698  MlirTypeID mlirTypeID = mlirAttributeGetTypeID(self);
3699  assert(!mlirTypeIDIsNull(mlirTypeID) &&
3700  "mlirTypeID was expected to be non-null.");
3701  std::optional<nb::callable> typeCaster =
3702  PyGlobals::get().lookupTypeCaster(mlirTypeID,
3703  mlirAttributeGetDialect(self));
3704  if (!typeCaster)
3705  return nb::cast(self);
3706  return typeCaster.value()(self);
3707  });
3708 
3709  //----------------------------------------------------------------------------
3710  // Mapping of PyNamedAttribute
3711  //----------------------------------------------------------------------------
3712  nb::class_<PyNamedAttribute>(m, "NamedAttribute")
3713  .def("__repr__",
3714  [](PyNamedAttribute &self) {
3715  PyPrintAccumulator printAccum;
3716  printAccum.parts.append("NamedAttribute(");
3717  printAccum.parts.append(
3718  nb::str(mlirIdentifierStr(self.namedAttr.name).data,
3719  mlirIdentifierStr(self.namedAttr.name).length));
3720  printAccum.parts.append("=");
3721  mlirAttributePrint(self.namedAttr.attribute,
3722  printAccum.getCallback(),
3723  printAccum.getUserData());
3724  printAccum.parts.append(")");
3725  return printAccum.join();
3726  })
3727  .def_prop_ro(
3728  "name",
3729  [](PyNamedAttribute &self) {
3730  return nb::str(mlirIdentifierStr(self.namedAttr.name).data,
3731  mlirIdentifierStr(self.namedAttr.name).length);
3732  },
3733  "The name of the NamedAttribute binding")
3734  .def_prop_ro(
3735  "attr",
3736  [](PyNamedAttribute &self) { return self.namedAttr.attribute; },
3737  nb::keep_alive<0, 1>(),
3738  "The underlying generic attribute of the NamedAttribute binding");
3739 
3740  //----------------------------------------------------------------------------
3741  // Mapping of PyType.
3742  //----------------------------------------------------------------------------
3743  nb::class_<PyType>(m, "Type")
3744  // Delegate to the PyType copy constructor, which will also lifetime
3745  // extend the backing context which owns the MlirType.
3746  .def(nb::init<PyType &>(), nb::arg("cast_from_type"),
3747  "Casts the passed type to the generic Type")
3748  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyType::getCapsule)
3749  .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyType::createFromCapsule)
3750  .def_static(
3751  "parse",
3752  [](std::string typeSpec, DefaultingPyMlirContext context) {
3753  PyMlirContext::ErrorCapture errors(context->getRef());
3754  MlirType type =
3755  mlirTypeParseGet(context->get(), toMlirStringRef(typeSpec));
3756  if (mlirTypeIsNull(type))
3757  throw MLIRError("Unable to parse type", errors.take());
3758  return type;
3759  },
3760  nb::arg("asm"), nb::arg("context").none() = nb::none(),
3762  .def_prop_ro(
3763  "context", [](PyType &self) { return self.getContext().getObject(); },
3764  "Context that owns the Type")
3765  .def("__eq__", [](PyType &self, PyType &other) { return self == other; })
3766  .def(
3767  "__eq__", [](PyType &self, nb::object &other) { return false; },
3768  nb::arg("other").none())
3769  .def("__hash__",
3770  [](PyType &self) {
3771  return static_cast<size_t>(llvm::hash_value(self.get().ptr));
3772  })
3773  .def(
3774  "dump", [](PyType &self) { mlirTypeDump(self); }, kDumpDocstring)
3775  .def(
3776  "__str__",
3777  [](PyType &self) {
3778  PyPrintAccumulator printAccum;
3779  mlirTypePrint(self, printAccum.getCallback(),
3780  printAccum.getUserData());
3781  return printAccum.join();
3782  },
3783  "Returns the assembly form of the type.")
3784  .def("__repr__",
3785  [](PyType &self) {
3786  // Generally, assembly formats are not printed for __repr__ because
3787  // this can cause exceptionally long debug output and exceptions.
3788  // However, types are an exception as they typically have compact
3789  // assembly forms and printing them is useful.
3790  PyPrintAccumulator printAccum;
3791  printAccum.parts.append("Type(");
3792  mlirTypePrint(self, printAccum.getCallback(),
3793  printAccum.getUserData());
3794  printAccum.parts.append(")");
3795  return printAccum.join();
3796  })
3798  [](PyType &self) {
3799  MlirTypeID mlirTypeID = mlirTypeGetTypeID(self);
3800  assert(!mlirTypeIDIsNull(mlirTypeID) &&
3801  "mlirTypeID was expected to be non-null.");
3802  std::optional<nb::callable> typeCaster =
3803  PyGlobals::get().lookupTypeCaster(mlirTypeID,
3804  mlirTypeGetDialect(self));
3805  if (!typeCaster)
3806  return nb::cast(self);
3807  return typeCaster.value()(self);
3808  })
3809  .def_prop_ro("typeid", [](PyType &self) -> MlirTypeID {
3810  MlirTypeID mlirTypeID = mlirTypeGetTypeID(self);
3811  if (!mlirTypeIDIsNull(mlirTypeID))
3812  return mlirTypeID;
3813  auto origRepr = nb::cast<std::string>(nb::repr(nb::cast(self)));
3814  throw nb::value_error(
3815  (origRepr + llvm::Twine(" has no typeid.")).str().c_str());
3816  });
3817 
3818  //----------------------------------------------------------------------------
3819  // Mapping of PyTypeID.
3820  //----------------------------------------------------------------------------
3821  nb::class_<PyTypeID>(m, "TypeID")
3822  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyTypeID::getCapsule)
3823  .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyTypeID::createFromCapsule)
3824  // Note, this tests whether the underlying TypeIDs are the same,
3825  // not whether the wrapper MlirTypeIDs are the same, nor whether
3826  // the Python objects are the same (i.e., PyTypeID is a value type).
3827  .def("__eq__",
3828  [](PyTypeID &self, PyTypeID &other) { return self == other; })
3829  .def("__eq__",
3830  [](PyTypeID &self, const nb::object &other) { return false; })
3831  // Note, this gives the hash value of the underlying TypeID, not the
3832  // hash value of the Python object, nor the hash value of the
3833  // MlirTypeID wrapper.
3834  .def("__hash__", [](PyTypeID &self) {
3835  return static_cast<size_t>(mlirTypeIDHashValue(self));
3836  });
3837 
3838  //----------------------------------------------------------------------------
3839  // Mapping of Value.
3840  //----------------------------------------------------------------------------
3841  nb::class_<PyValue>(m, "Value")
3842  .def(nb::init<PyValue &>(), nb::keep_alive<0, 1>(), nb::arg("value"))
3843  .def_prop_ro(MLIR_PYTHON_CAPI_PTR_ATTR, &PyValue::getCapsule)
3844  .def(MLIR_PYTHON_CAPI_FACTORY_ATTR, &PyValue::createFromCapsule)
3845  .def_prop_ro(
3846  "context",
3847  [](PyValue &self) { return self.getParentOperation()->getContext(); },
3848  "Context in which the value lives.")
3849  .def(
3850  "dump", [](PyValue &self) { mlirValueDump(self.get()); },
3852  .def_prop_ro(
3853  "owner",
3854  [](PyValue &self) -> nb::object {
3855  MlirValue v = self.get();
3856  if (mlirValueIsAOpResult(v)) {
3857  assert(
3858  mlirOperationEqual(self.getParentOperation()->get(),
3859  mlirOpResultGetOwner(self.get())) &&
3860  "expected the owner of the value in Python to match that in "
3861  "the IR");
3862  return self.getParentOperation().getObject();
3863  }
3864 
3865  if (mlirValueIsABlockArgument(v)) {
3866  MlirBlock block = mlirBlockArgumentGetOwner(self.get());
3867  return nb::cast(PyBlock(self.getParentOperation(), block));
3868  }
3869 
3870  assert(false && "Value must be a block argument or an op result");
3871  return nb::none();
3872  })
3873  .def_prop_ro("uses",
3874  [](PyValue &self) {
3875  return PyOpOperandIterator(
3876  mlirValueGetFirstUse(self.get()));
3877  })
3878  .def("__eq__",
3879  [](PyValue &self, PyValue &other) {
3880  return self.get().ptr == other.get().ptr;
3881  })
3882  .def("__eq__", [](PyValue &self, nb::object other) { return false; })
3883  .def("__hash__",
3884  [](PyValue &self) {
3885  return static_cast<size_t>(llvm::hash_value(self.get().ptr));
3886  })
3887  .def(
3888  "__str__",
3889  [](PyValue &self) {
3890  PyPrintAccumulator printAccum;
3891  printAccum.parts.append("Value(");
3892  mlirValuePrint(self.get(), printAccum.getCallback(),
3893  printAccum.getUserData());
3894  printAccum.parts.append(")");
3895  return printAccum.join();
3896  },
3898  .def(
3899  "get_name",
3900  [](PyValue &self, bool useLocalScope) {
3901  PyPrintAccumulator printAccum;
3902  MlirOpPrintingFlags flags = mlirOpPrintingFlagsCreate();
3903  if (useLocalScope)
3905  MlirAsmState valueState =
3906  mlirAsmStateCreateForValue(self.get(), flags);
3907  mlirValuePrintAsOperand(self.get(), valueState,
3908  printAccum.getCallback(),
3909  printAccum.getUserData());
3911  mlirAsmStateDestroy(valueState);
3912  return printAccum.join();
3913  },
3914  nb::arg("use_local_scope") = false)
3915  .def(
3916  "get_name",
3917  [](PyValue &self, PyAsmState &state) {
3918  PyPrintAccumulator printAccum;
3919  MlirAsmState valueState = state.get();
3920  mlirValuePrintAsOperand(self.get(), valueState,
3921  printAccum.getCallback(),
3922  printAccum.getUserData());
3923  return printAccum.join();
3924  },
3925  nb::arg("state"), kGetNameAsOperand)
3926  .def_prop_ro("type",
3927  [](PyValue &self) { return mlirValueGetType(self.get()); })
3928  .def(
3929  "set_type",
3930  [](PyValue &self, const PyType &type) {
3931  return mlirValueSetType(self.get(), type);
3932  },
3933  nb::arg("type"))
3934  .def(
3935  "replace_all_uses_with",
3936  [](PyValue &self, PyValue &with) {
3937  mlirValueReplaceAllUsesOfWith(self.get(), with.get());
3938  },
3940  .def(
3941  "replace_all_uses_except",
3942  [](MlirValue self, MlirValue with, PyOperation &exception) {
3943  MlirOperation exceptedUser = exception.get();
3944  mlirValueReplaceAllUsesExcept(self, with, 1, &exceptedUser);
3945  },
3946  nb::arg("with"), nb::arg("exceptions"),
3948  .def(
3949  "replace_all_uses_except",
3950  [](MlirValue self, MlirValue with, nb::list exceptions) {
3951  // Convert Python list to a SmallVector of MlirOperations
3952  llvm::SmallVector<MlirOperation> exceptionOps;
3953  for (nb::handle exception : exceptions) {
3954  exceptionOps.push_back(nb::cast<PyOperation &>(exception).get());
3955  }
3956 
3958  self, with, static_cast<intptr_t>(exceptionOps.size()),
3959  exceptionOps.data());
3960  },
3961  nb::arg("with"), nb::arg("exceptions"),
3964  [](PyValue &self) { return self.maybeDownCast(); });
3965  PyBlockArgument::bind(m);
3966  PyOpResult::bind(m);
3967  PyOpOperand::bind(m);
3968 
3969  nb::class_<PyAsmState>(m, "AsmState")
3970  .def(nb::init<PyValue &, bool>(), nb::arg("value"),
3971  nb::arg("use_local_scope") = false)
3972  .def(nb::init<PyOperationBase &, bool>(), nb::arg("op"),
3973  nb::arg("use_local_scope") = false);
3974 
3975  //----------------------------------------------------------------------------
3976  // Mapping of SymbolTable.
3977  //----------------------------------------------------------------------------
3978  nb::class_<PySymbolTable>(m, "SymbolTable")
3979  .def(nb::init<PyOperationBase &>())
3980  .def("__getitem__", &PySymbolTable::dunderGetItem)
3981  .def("insert", &PySymbolTable::insert, nb::arg("operation"))
3982  .def("erase", &PySymbolTable::erase, nb::arg("operation"))
3983  .def("__delitem__", &PySymbolTable::dunderDel)
3984  .def("__contains__",
3985  [](PySymbolTable &table, const std::string &name) {
3987  table, mlirStringRefCreate(name.data(), name.length())));
3988  })
3989  // Static helpers.
3990  .def_static("set_symbol_name", &PySymbolTable::setSymbolName,
3991  nb::arg("symbol"), nb::arg("name"))
3992  .def_static("get_symbol_name", &PySymbolTable::getSymbolName,
3993  nb::arg("symbol"))
3994  .def_static("get_visibility", &PySymbolTable::getVisibility,
3995  nb::arg("symbol"))
3996  .def_static("set_visibility", &PySymbolTable::setVisibility,
3997  nb::arg("symbol"), nb::arg("visibility"))
3998  .def_static("replace_all_symbol_uses",
3999  &PySymbolTable::replaceAllSymbolUses, nb::arg("old_symbol"),
4000  nb::arg("new_symbol"), nb::arg("from_op"))
4001  .def_static("walk_symbol_tables", &PySymbolTable::walkSymbolTables,
4002  nb::arg("from_op"), nb::arg("all_sym_uses_visible"),
4003  nb::arg("callback"));
4004 
4005  // Container bindings.
4006  PyBlockArgumentList::bind(m);
4007  PyBlockIterator::bind(m);
4008  PyBlockList::bind(m);
4009  PyOperationIterator::bind(m);
4010  PyOperationList::bind(m);
4011  PyOpAttributeMap::bind(m);
4012  PyOpOperandIterator::bind(m);
4013  PyOpOperandList::bind(m);
4015  PyOpSuccessors::bind(m);
4016  PyRegionIterator::bind(m);
4017  PyRegionList::bind(m);
4018 
4019  // Debug bindings.
4021 
4022  // Attribute builder getter.
4024 
4025  nb::register_exception_translator([](const std::exception_ptr &p,
4026  void *payload) {
4027  // We can't define exceptions with custom fields through pybind, so instead
4028  // the exception class is defined in python and imported here.
4029  try {
4030  if (p)
4031  std::rethrow_exception(p);
4032  } catch (const MLIRError &e) {
4033  nb::object obj = nb::module_::import_(MAKE_MLIR_PYTHON_QUALNAME("ir"))
4034  .attr("MLIRError")(e.message, e.errorDiagnostics);
4035  PyErr_SetObject(PyExc_Exception, obj.ptr());
4036  }
4037  });
4038 }
MLIR_CAPI_EXPORTED void mlirSetGlobalDebugType(const char *type)
Sets the current debug type, similarly to -debug-only=type in the command-line tools.
Definition: Debug.cpp:20
MLIR_CAPI_EXPORTED void mlirSetGlobalDebugTypes(const char **types, intptr_t n)
Sets multiple current debug types, similarly to `-debug-only=type1,type2" in the command-line tools.
Definition: Debug.cpp:28
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 const char kOperationPrintStateDocstring[]
Definition: IRCore.cpp:116
static const char kValueReplaceAllUsesWithDocstring[]
Definition: IRCore.cpp:178
static const char kContextGetNameLocationDocString[]
Definition: IRCore.cpp:59
static const char kGetNameAsOperand[]
Definition: IRCore.cpp:174
static MlirStringRef toMlirStringRef(const std::string &s)
Definition: IRCore.cpp:213
static const char kModuleParseDocstring[]
Definition: IRCore.cpp:62
static const char kOperationStrDunderDocstring[]
Definition: IRCore.cpp:148
static const char kOperationPrintDocstring[]
Definition: IRCore.cpp:89
static MlirValue getUniqueResult(MlirOperation operation)
Definition: IRCore.cpp:1863
static const char kContextGetFileLocationDocstring[]
Definition: IRCore.cpp:50
static const char kDumpDocstring[]
Definition: IRCore.cpp:156
static const char kAppendBlockDocstring[]
Definition: IRCore.cpp:159
static MlirValue getOpResultOrValue(nb::handle operand)
Definition: IRCore.cpp:1878
static const char kContextGetFusedLocationDocstring[]
Definition: IRCore.cpp:56
static const char kContextGetFileRangeDocstring[]
Definition: IRCore.cpp:53
static void maybeInsertOperation(PyOperationRef &op, const nb::object &maybeIp)
Definition: IRCore.cpp:1469
static nb::object createCustomDialectWrapper(const std::string &dialectNamespace, nb::object dialectDescriptor)
Definition: IRCore.cpp:201
nb::object classmethod(Func f, Args... args)
Helper for creating an @classmethod.
Definition: IRCore.cpp:195
static const char kOperationPrintBytecodeDocstring[]
Definition: IRCore.cpp:138
static const char kOperationGetAsmDocstring[]
Definition: IRCore.cpp:125
static MlirBlock createBlock(const nb::sequence &pyArgTypes, const std::optional< nb::sequence > &pyArgLocs)
Create a block, using the current location context if no locations are specified.
Definition: IRCore.cpp:227
static const char kOperationCreateDocstring[]
Definition: IRCore.cpp:70
static std::vector< MlirType > getValueTypes(Container &container, PyMlirContextRef &context)
Returns the list of types of the values held by container.
Definition: IRCore.cpp:1703
static const char kContextParseTypeDocstring[]
Definition: IRCore.cpp:39
static void populateResultTypes(StringRef name, nb::list resultTypeList, const nb::object &resultSegmentSpecObj, std::vector< int32_t > &resultSegmentLengths, std::vector< PyType * > &resultTypes)
Definition: IRCore.cpp:1766
static const char kContextGetCallSiteLocationDocstring[]
Definition: IRCore.cpp:47
static const char kValueDunderStrDocstring[]
Definition: IRCore.cpp:166
static const char kValueReplaceAllUsesExceptDocstring[]
Definition: IRCore.cpp:183
static MLIRContext * getContext(OpFoldResult val)
static PyObject * mlirPythonModuleToCapsule(MlirModule module)
Creates a capsule object encapsulating the raw C-API MlirModule.
Definition: Interop.h:273
#define MLIR_PYTHON_MAYBE_DOWNCAST_ATTR
Attribute on MLIR Python objects that expose a function for downcasting the corresponding Python obje...
Definition: Interop.h:118
static PyObject * mlirPythonTypeIDToCapsule(MlirTypeID typeID)
Creates a capsule object encapsulating the raw C-API MlirTypeID.
Definition: Interop.h:348
static MlirOperation mlirPythonCapsuleToOperation(PyObject *capsule)
Extracts an MlirOperations from a capsule as produced from mlirPythonOperationToCapsule.
Definition: Interop.h:338
#define MLIR_PYTHON_CAPI_PTR_ATTR
Attribute on MLIR Python objects that expose their C-API pointer.
Definition: Interop.h:97
static MlirAttribute mlirPythonCapsuleToAttribute(PyObject *capsule)
Extracts an MlirAttribute from a capsule as produced from mlirPythonAttributeToCapsule.
Definition: Interop.h:189
static PyObject * mlirPythonAttributeToCapsule(MlirAttribute attribute)
Creates a capsule object encapsulating the raw C-API MlirAttribute.
Definition: Interop.h:180
static PyObject * mlirPythonLocationToCapsule(MlirLocation loc)
Creates a capsule object encapsulating the raw C-API MlirLocation.
Definition: Interop.h:255
#define MLIR_PYTHON_CAPI_FACTORY_ATTR
Attribute on MLIR Python objects that exposes a factory function for constructing the corresponding P...
Definition: Interop.h:110
static MlirModule mlirPythonCapsuleToModule(PyObject *capsule)
Extracts an MlirModule from a capsule as produced from mlirPythonModuleToCapsule.
Definition: Interop.h:282
static MlirContext mlirPythonCapsuleToContext(PyObject *capsule)
Extracts a MlirContext from a capsule as produced from mlirPythonContextToCapsule.
Definition: Interop.h:224
static MlirTypeID mlirPythonCapsuleToTypeID(PyObject *capsule)
Extracts an MlirTypeID from a capsule as produced from mlirPythonTypeIDToCapsule.
Definition: Interop.h:357
static PyObject * mlirPythonDialectRegistryToCapsule(MlirDialectRegistry registry)
Creates a capsule object encapsulating the raw C-API MlirDialectRegistry.
Definition: Interop.h:235
static PyObject * mlirPythonTypeToCapsule(MlirType type)
Creates a capsule object encapsulating the raw C-API MlirType.
Definition: Interop.h:367
static MlirDialectRegistry mlirPythonCapsuleToDialectRegistry(PyObject *capsule)
Extracts an MlirDialectRegistry from a capsule as produced from mlirPythonDialectRegistryToCapsule.
Definition: Interop.h:245
#define MAKE_MLIR_PYTHON_QUALNAME(local)
Definition: Interop.h:57
static MlirType mlirPythonCapsuleToType(PyObject *capsule)
Extracts an MlirType from a capsule as produced from mlirPythonTypeToCapsule.
Definition: Interop.h:376
static MlirValue mlirPythonCapsuleToValue(PyObject *capsule)
Extracts an MlirValue from a capsule as produced from mlirPythonValueToCapsule.
Definition: Interop.h:454
static PyObject * mlirPythonBlockToCapsule(MlirBlock block)
Creates a capsule object encapsulating the raw C-API MlirBlock.
Definition: Interop.h:198
static PyObject * mlirPythonOperationToCapsule(MlirOperation operation)
Creates a capsule object encapsulating the raw C-API MlirOperation.
Definition: Interop.h:330
static MlirLocation mlirPythonCapsuleToLocation(PyObject *capsule)
Extracts an MlirLocation from a capsule as produced from mlirPythonLocationToCapsule.
Definition: Interop.h:264
static PyObject * mlirPythonValueToCapsule(MlirValue value)
Creates a capsule object encapsulating the raw C-API MlirValue.
Definition: Interop.h:445
static PyObject * mlirPythonContextToCapsule(MlirContext context)
Creates a capsule object encapsulating the raw C-API MlirContext.
Definition: Interop.h:216
static LogicalResult nextIndex(ArrayRef< int64_t > shape, MutableArrayRef< int64_t > index)
Walks over the indices of the elements of a tensor of a given shape by updating index in place to the...
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static sycl::context getDefaultContext()
const float * table
A list of operation results.
Definition: IRCore.cpp:1717
PyOperationRef & getOperation()
Definition: IRCore.cpp:1739
static void bindDerived(ClassTy &c)
Definition: IRCore.cpp:1730
PyOpResultList(PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition: IRCore.cpp:1722
Python wrapper for MlirOpResult.
Definition: IRCore.cpp:1681
static void bindDerived(ClassTy &c)
Definition: IRCore.cpp:1687
Accumulates int a python file-like object, either writing text (default) or binary.
MlirStringCallback getCallback()
A CRTP base class for pseudo-containers willing to support Python-type slicing access on top of index...
static void bind(nanobind::module_ &m)
Binds the indexing and length methods in the Python class.
nanobind::class_< PyOpResultList > ClassTy
Base class for all objects that directly or indirectly depend on an MlirContext.
Definition: IRModule.h:306
PyMlirContextRef & getContext()
Accesses the context reference.
Definition: IRModule.h:314
Used in function arguments when None should resolve to the current context manager set instance.
Definition: IRModule.h:521
static PyLocation & resolve()
Definition: IRCore.cpp:1118
Used in function arguments when None should resolve to the current context manager set instance.
Definition: IRModule.h:295
static PyMlirContext & resolve()
Definition: IRCore.cpp:839
ReferrentTy * get() const
Definition: NanobindUtils.h:55
Wrapper around an MlirAsmState.
Definition: IRModule.h:791
Wrapper around the generic MlirAttribute.
Definition: IRModule.h:1012
PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
Definition: IRModule.h:1014
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirAttribute.
Definition: IRCore.cpp:2171
static PyAttribute createFromCapsule(nanobind::object capsule)
Creates a PyAttribute from the MlirAttribute wrapped by a capsule.
Definition: IRCore.cpp:2175
bool operator==(const PyAttribute &other) const
Definition: IRCore.cpp:2167
Wrapper around an MlirBlock.
Definition: IRModule.h:826
MlirBlock get()
Definition: IRModule.h:833
PyOperationRef & getParentOperation()
Definition: IRModule.h:834
Represents a diagnostic handler attached to the context.
Definition: IRModule.h:402
PyDiagnosticHandler(MlirContext context, nanobind::object callback)
Definition: IRCore.cpp:995
void detach()
Detaches the handler. Does nothing if not attached.
Definition: IRCore.cpp:1001
Python class mirroring the C MlirDiagnostic struct.
Definition: IRModule.h:352
PyLocation getLocation()
Definition: IRCore.cpp:1024
nanobind::tuple getNotes()
Definition: IRCore.cpp:1039
nanobind::str getMessage()
Definition: IRCore.cpp:1031
DiagnosticInfo getInfo()
Definition: IRCore.cpp:1055
PyDiagnostic(MlirDiagnostic diagnostic)
Definition: IRModule.h:354
MlirDiagnosticSeverity getSeverity()
Definition: IRCore.cpp:1019
Wrapper around an MlirDialect.
Definition: IRModule.h:457
Wrapper around an MlirDialectRegistry.
Definition: IRModule.h:494
nanobind::object getCapsule()
Definition: IRCore.cpp:1080
static PyDialectRegistry createFromCapsule(nanobind::object capsule)
Definition: IRCore.cpp:1084
User-level dialect object.
Definition: IRModule.h:481
User-level object for accessing dialects with dotted syntax such as: ctx.dialect.std.
Definition: IRModule.h:470
MlirDialect getDialectForKey(const std::string &key, bool attrError)
Definition: IRCore.cpp:1067
std::optional< nanobind::callable > lookupValueCaster(MlirTypeID mlirTypeID, MlirDialect dialect)
Returns the custom value caster for MlirTypeID mlirTypeID.
Definition: IRModule.cpp:155
std::optional< nanobind::object > lookupOperationClass(llvm::StringRef operationName)
Looks up a registered operation class (deriving from OpView) by operation name.
Definition: IRModule.cpp:184
static PyGlobals & get()
Most code should get the globals via this static accessor.
Definition: Globals.h:34
An insertion point maintains a pointer to a Block and a reference operation.
Definition: IRModule.h:850
static PyInsertionPoint atBlockTerminator(PyBlock &block)
Shortcut to create an insertion point before the block terminator.
Definition: IRCore.cpp:2144
PyInsertionPoint(PyBlock &block)
Creates an insertion point positioned after the last operation in the block, but still inside the blo...
Definition: IRCore.cpp:2099
static PyInsertionPoint atBlockBegin(PyBlock &block)
Shortcut to create an insertion point at the beginning of the block.
Definition: IRCore.cpp:2131
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition: IRCore.cpp:2157
void insert(PyOperationBase &operationBase)
Inserts an operation.
Definition: IRCore.cpp:2105
static nanobind::object contextEnter(nanobind::object insertionPoint)
Enter and exit the context manager.
Definition: IRCore.cpp:2153
Wrapper around an MlirLocation.
Definition: IRModule.h:321
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirLocation.
Definition: IRCore.cpp:1096
PyLocation(PyMlirContextRef contextRef, MlirLocation loc)
Definition: IRModule.h:323
static PyLocation createFromCapsule(nanobind::object capsule)
Creates a PyLocation from the MlirLocation wrapped by a capsule.
Definition: IRCore.cpp:1100
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition: IRCore.cpp:1112
static nanobind::object contextEnter(nanobind::object location)
Enter and exit the context manager.
Definition: IRCore.cpp:1108
MlirLocation get() const
Definition: IRModule.h:327
MlirContext get()
Accesses the underlying MlirContext.
Definition: IRModule.h:186
PyMlirContextRef getRef()
Gets a strong reference to this context, which will ensure it is kept alive for the life of the refer...
Definition: IRModule.h:190
void clearOperationsInside(PyOperationBase &op)
Clears all operations nested inside the given op using clearOperation(MlirOperation).
Definition: IRCore.cpp:727
static size_t getLiveCount()
Gets the count of live context objects. Used for testing.
Definition: IRCore.cpp:682
void clearOperationAndInside(PyOperationBase &op)
Clears the operaiton and all operations inside using clearOperation(MlirOperation).
Definition: IRCore.cpp:752
size_t getLiveModuleCount()
Gets the count of live modules associated with this context.
Definition: IRCore.cpp:763
nanobind::object attachDiagnosticHandler(nanobind::object callback)
Attaches a Python callback as a diagnostic handler, returning a registration object (internally a PyD...
Definition: IRCore.cpp:775
size_t clearLiveOperations()
Clears the live operations map, returning the number of entries which were invalidated.
Definition: IRCore.cpp:700
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirContext.
Definition: IRCore.cpp:646
std::vector< PyOperation * > getLiveOperationObjects()
Get a list of Python objects which are still in the live context map.
Definition: IRCore.cpp:692
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition: IRCore.cpp:769
void clearOperation(MlirOperation op)
Removes an operation from the live operations map and sets it invalid.
Definition: IRCore.cpp:713
static PyMlirContextRef forContext(MlirContext context)
Returns a context reference for the singleton PyMlirContext wrapper for the given context.
Definition: IRCore.cpp:657
static nanobind::object createFromCapsule(nanobind::object capsule)
Creates a PyMlirContext from the MlirContext wrapped by a capsule.
Definition: IRCore.cpp:650
size_t getLiveOperationCount()
Gets the count of live operations associated with this context.
Definition: IRCore.cpp:687
static nanobind::object contextEnter(nanobind::object context)
Enter and exit the context manager.
Definition: IRCore.cpp:765
MlirModule get()
Gets the backing MlirModule.
Definition: IRModule.h:544
static PyModuleRef forModule(MlirModule module)
Returns a PyModule reference for the given MlirModule.
Definition: IRCore.cpp:1145
static nanobind::object createFromCapsule(nanobind::object capsule)
Creates a PyModule from the MlirModule wrapped by a capsule.
Definition: IRCore.cpp:1170
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirModule.
Definition: IRCore.cpp:1177
PyModule(PyModule &)=delete
Represents a Python MlirNamedAttr, carrying an optional owned name.
Definition: IRModule.h:1036
PyNamedAttribute(MlirAttribute attr, std::string ownedName)
Constructs a PyNamedAttr that retains an owned name.
Definition: IRCore.cpp:2187
MlirNamedAttribute namedAttr
Definition: IRModule.h:1045
nanobind::object getObject()
Definition: IRModule.h:88
nanobind::object releaseObject()
Releases the object held by this instance, returning it.
Definition: IRModule.h:76
A PyOpView is equivalent to the C++ "Op" wrappers: these are the basis for providing more instance-sp...
Definition: IRModule.h:736
static nanobind::object constructDerived(const nanobind::object &cls, const nanobind::object &operation)
Construct an instance of a class deriving from OpView, bypassing its __init__ method.
Definition: IRCore.cpp:2081
static nanobind::object buildGeneric(std::string_view name, std::tuple< int, bool > opRegionSpec, nanobind::object operandSegmentSpecObj, nanobind::object resultSegmentSpecObj, std::optional< nanobind::list > resultTypeList, nanobind::list operandList, std::optional< nanobind::dict > attributes, std::optional< std::vector< PyBlock * >> successors, std::optional< int > regions, DefaultingPyLocation location, const nanobind::object &maybeIp)
Definition: IRCore.cpp:1897
PyOpView(const nanobind::object &operationObject)
Definition: IRCore.cpp:2089
Base class for PyOperation and PyOpView which exposes the primary, user visible methods for manipulat...
Definition: IRModule.h:573
void walk(std::function< MlirWalkResult(MlirOperation)> callback, MlirWalkOrder walkOrder)
Definition: IRCore.cpp:1354
virtual PyOperation & getOperation()=0
Each must provide access to the raw Operation.
void print(std::optional< int64_t > largeElementsLimit, bool enableDebugInfo, bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope, bool assumeVerified, nanobind::object fileObject, bool binary, bool skipRegions)
Implements the bound 'print' method and helps with others.
void moveAfter(PyOperationBase &other)
Moves the operation before or after the other operation.
Definition: IRCore.cpp:1410
nanobind::object getAsm(bool binary, std::optional< int64_t > largeElementsLimit, bool enableDebugInfo, bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope, bool assumeVerified, bool skipRegions)
Definition: IRCore.cpp:1386
void writeBytecode(const nanobind::object &fileObject, std::optional< int64_t > bytecodeVersion)
Definition: IRCore.cpp:1332
void moveBefore(PyOperationBase &other)
Definition: IRCore.cpp:1419
bool verify()
Verify the operation.
Definition: IRCore.cpp:1428
void detachFromParent()
Detaches the operation from its parent block and updates its state accordingly.
Definition: IRModule.h:642
PyOperation(PyMlirContextRef contextRef, MlirOperation operation)
Definition: IRCore.cpp:1185
void erase()
Erases the underlying MlirOperation, removes its pointer from the parent context's live operations ma...
Definition: IRCore.cpp:1619
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirOperation.
Definition: IRCore.cpp:1455
static PyOperationRef createDetached(PyMlirContextRef contextRef, MlirOperation operation, nanobind::object parentKeepAlive=nanobind::object())
Creates a detached operation.
Definition: IRCore.cpp:1254
nanobind::object clone(const nanobind::object &ip)
Clones this operation.
Definition: IRCore.cpp:1599
PyOperation & getOperation() override
Each must provide access to the raw Operation.
Definition: IRModule.h:620
PyOperationRef getRef()
Definition: IRModule.h:655
static nanobind::object createFromCapsule(nanobind::object capsule)
Creates a PyOperation from the MlirOperation wrapped by a capsule.
Definition: IRCore.cpp:1460
MlirOperation get() const
Definition: IRModule.h:650
static PyOperationRef forOperation(PyMlirContextRef contextRef, MlirOperation operation, nanobind::object parentKeepAlive=nanobind::object())
Returns a PyOperation for the given MlirOperation, optionally associating it with a parentKeepAlive.
Definition: IRCore.cpp:1234
void setAttached(const nanobind::object &parent=nanobind::object())
Definition: IRModule.h:660
std::optional< PyOperationRef > getParentOperation()
Gets the parent operation or raises an exception if the operation has no parent.
Definition: IRCore.cpp:1436
nanobind::object createOpView()
Creates an OpView suitable for this operation.
Definition: IRCore.cpp:1608
PyBlock getBlock()
Gets the owning block or raises an exception if the operation has no owning block.
Definition: IRCore.cpp:1446
static nanobind::object create(std::string_view name, std::optional< std::vector< PyType * >> results, llvm::ArrayRef< MlirValue > operands, std::optional< nanobind::dict > attributes, std::optional< std::vector< PyBlock * >> successors, int regions, DefaultingPyLocation location, const nanobind::object &ip, bool inferType)
Creates an operation. See corresponding python docstring.
Definition: IRCore.cpp:1484
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:1270
void checkValid() const
Definition: IRCore.cpp:1282
void setInvalid()
Invalidate the operation.
Definition: IRModule.h:703
Wrapper around an MlirRegion.
Definition: IRModule.h:772
PyOperationRef & getParentOperation()
Definition: IRModule.h:781
MlirRegion get()
Definition: IRModule.h:780
Bindings for MLIR symbol tables.
Definition: IRModule.h:1251
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:2308
static void walkSymbolTables(PyOperationBase &from, bool allSymUsesVisible, nanobind::object callback)
Walks all symbol tables under and including 'from'.
Definition: IRCore.cpp:2391
static void replaceAllSymbolUses(const std::string &oldSymbol, const std::string &newSymbol, PyOperationBase &from)
Replaces all symbol uses within an operation.
Definition: IRCore.cpp:2379
static void setVisibility(PyOperationBase &symbol, const std::string &visibility)
Definition: IRCore.cpp:2361
static void setSymbolName(PyOperationBase &symbol, const std::string &name)
Definition: IRCore.cpp:2335
MlirAttribute insert(PyOperationBase &symbol)
Inserts the given operation into the symbol table.
Definition: IRCore.cpp:2313
void erase(PyOperationBase &symbol)
Removes the given operation from the symbol table and erases it.
Definition: IRCore.cpp:2298
PySymbolTable(PyOperationBase &operation)
Constructs a symbol table for the given operation.
Definition: IRCore.cpp:2277
static MlirAttribute getSymbolName(PyOperationBase &symbol)
Gets and sets the name of a symbol op.
Definition: IRCore.cpp:2323
nanobind::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:2285
static MlirAttribute getVisibility(PyOperationBase &symbol)
Gets and sets the visibility of a symbol op.
Definition: IRCore.cpp:2350
Tracks an entry in the thread context stack.
Definition: IRModule.h:107
static PyThreadContextEntry * getTopOfStack()
Stack management.
Definition: IRCore.cpp:859
static void popLocation(PyLocation &location)
Definition: IRCore.cpp:971
static nanobind::object pushLocation(nanobind::object location)
Definition: IRCore.cpp:962
static nanobind::object pushContext(nanobind::object context)
Definition: IRCore.cpp:921
static PyLocation * getDefaultLocation()
Gets the top of stack location and returns nullptr if not defined.
Definition: IRCore.cpp:916
static void popInsertionPoint(PyInsertionPoint &insertionPoint)
Definition: IRCore.cpp:951
static nanobind::object pushInsertionPoint(nanobind::object insertionPoint)
Definition: IRCore.cpp:939
static void popContext(PyMlirContext &context)
Definition: IRCore.cpp:928
static PyInsertionPoint * getDefaultInsertionPoint()
Gets the top of stack insertion point and return nullptr if not defined.
Definition: IRCore.cpp:911
PyMlirContext * getContext()
Definition: IRCore.cpp:888
static PyMlirContext * getDefaultContext()
Gets the top of stack context and return nullptr if not defined.
Definition: IRCore.cpp:906
static std::vector< PyThreadContextEntry > & getStack()
Gets the thread local stack.
Definition: IRCore.cpp:854
PyInsertionPoint * getInsertionPoint()
Definition: IRCore.cpp:894
A TypeID provides an efficient and unique identifier for a specific C++ type.
Definition: IRModule.h:910
static PyTypeID createFromCapsule(nanobind::object capsule)
Creates a PyTypeID from the MlirTypeID wrapped by a capsule.
Definition: IRCore.cpp:2223
bool operator==(const PyTypeID &other) const
Definition: IRCore.cpp:2229
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirTypeID.
Definition: IRCore.cpp:2219
PyTypeID(MlirTypeID typeID)
Definition: IRModule.h:912
Wrapper around the generic MlirType.
Definition: IRModule.h:886
PyType(PyMlirContextRef contextRef, MlirType type)
Definition: IRModule.h:888
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirType.
Definition: IRCore.cpp:2203
static PyType createFromCapsule(nanobind::object capsule)
Creates a PyType from the MlirType wrapped by a capsule.
Definition: IRCore.cpp:2207
bool operator==(const PyType &other) const
Definition: IRCore.cpp:2199
Wrapper around the generic MlirValue.
Definition: IRModule.h:1152
PyValue(PyOperationRef parentOperation, MlirValue value)
Definition: IRModule.h:1158
static PyValue createFromCapsule(nanobind::object capsule)
Creates a PyValue from the MlirValue wrapped by a capsule.
Definition: IRCore.cpp:2256
nanobind::object maybeDownCast()
Definition: IRCore.cpp:2241
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirValue.
Definition: IRCore.cpp:2237
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 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 MlirAttribute mlirLocationGetAttribute(MlirLocation location)
Returns the underlying location attribute of this location.
Definition: IR.cpp:253
MLIR_CAPI_EXPORTED intptr_t mlirBlockArgumentGetArgNumber(MlirValue value)
Returns the position of the value in the argument list of its block.
Definition: IR.cpp:977
static bool mlirAttributeIsNull(MlirAttribute attr)
Checks whether an attribute is null.
Definition: IR.h:1052
MlirWalkResult(* MlirOperationWalkCallback)(MlirOperation, void *userData)
Operation walker type.
Definition: IR.h:744
MLIR_CAPI_EXPORTED void mlirOperationWriteBytecode(MlirOperation op, MlirStringCallback callback, void *userData)
Same as mlirOperationPrint but writing the bytecode format.
Definition: IR.cpp:720
MLIR_CAPI_EXPORTED MlirIdentifier mlirOperationGetName(MlirOperation op)
Gets the name of the operation as an identifier.
Definition: IR.cpp:548
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:261
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:1220
MLIR_CAPI_EXPORTED MlirStringRef mlirDialectGetNamespace(MlirDialect dialect)
Returns the namespace of the given dialect.
Definition: IR.cpp:129
MLIR_CAPI_EXPORTED intptr_t mlirOperationGetNumResults(MlirOperation op)
Returns the number of results of the operation.
Definition: IR.cpp:607
MLIR_CAPI_EXPORTED MlirAttribute mlirSymbolTableInsert(MlirSymbolTable symbolTable, MlirOperation operation)
Inserts the given operation into the given symbol table.
Definition: IR.cpp:1199
MlirWalkOrder
Traversal order for operation walk.
Definition: IR.h:737
@ MlirWalkPreOrder
Definition: IR.h:738
@ MlirWalkPostOrder
Definition: IR.h:739
MLIR_CAPI_EXPORTED MlirNamedAttribute mlirOperationGetAttribute(MlirOperation op, intptr_t pos)
Return pos-th attribute of the operation.
Definition: IR.cpp:681
MLIR_CAPI_EXPORTED void mlirOperationStateAddOperands(MlirOperationState *state, intptr_t n, MlirValue const *operands)
Definition: IR.cpp:396
MLIR_CAPI_EXPORTED void mlirModuleDestroy(MlirModule module)
Takes a module owned by the caller and deletes it.
Definition: IR.cpp:349
MLIR_CAPI_EXPORTED MlirNamedAttribute mlirNamedAttributeGet(MlirIdentifier name, MlirAttribute attr)
Associates an attribute with the name. Takes ownership of neither.
Definition: IR.cpp:1147
MLIR_CAPI_EXPORTED void mlirSymbolTableErase(MlirSymbolTable symbolTable, MlirOperation operation)
Removes the given operation from the symbol table and erases it.
Definition: IR.cpp:1204
MLIR_CAPI_EXPORTED void mlirOpPrintingFlagsUseLocalScope(MlirOpPrintingFlags flags)
Use local scope when printing the operation.
Definition: IR.cpp:221
MLIR_CAPI_EXPORTED bool mlirValueIsABlockArgument(MlirValue value)
Returns 1 if the value is a block argument, 0 otherwise.
Definition: IR.cpp:965
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:84
MLIR_CAPI_EXPORTED MlirStringRef mlirIdentifierStr(MlirIdentifier ident)
Gets the string value of the identifier.
Definition: IR.cpp:1168
static bool mlirModuleIsNull(MlirModule module)
Checks whether a module is null.
Definition: IR.h:323
MLIR_CAPI_EXPORTED MlirType mlirTypeParseGet(MlirContext context, MlirStringRef type)
Parses a type. The type is owned by the context.
Definition: IR.cpp:1081
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:1064
MLIR_CAPI_EXPORTED MlirType mlirAttributeGetType(MlirAttribute attribute)
Gets the type of this attribute.
Definition: IR.cpp:1120
MLIR_CAPI_EXPORTED void mlirContextSetAllowUnregisteredDialects(MlirContext context, bool allow)
Sets whether unregistered dialects are allowed in this context.
Definition: IR.cpp:73
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:821
MLIR_CAPI_EXPORTED void mlirValueReplaceAllUsesOfWith(MlirValue of, MlirValue with)
Replace all uses of 'of' value with the 'with' value, updating anything in the IR that uses 'of' to u...
Definition: IR.cpp:1028
MLIR_CAPI_EXPORTED MlirBlock mlirOperationGetSuccessor(MlirOperation op, intptr_t pos)
Returns pos-th successor of the operation.
Definition: IR.cpp:619
MLIR_CAPI_EXPORTED void mlirValuePrintAsOperand(MlirValue value, MlirAsmState state, MlirStringCallback callback, void *userData)
Prints a value as an operand (i.e., the ValueID).
Definition: IR.cpp:1011
MLIR_CAPI_EXPORTED MlirLocation mlirLocationUnknownGet(MlirContext context)
Creates a location with unknown position owned by the given context.
Definition: IR.cpp:298
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:1101
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:691
MLIR_CAPI_EXPORTED MlirOperation mlirOpOperandGetOwner(MlirOpOperand opOperand)
Returns the owner operation of an op operand.
Definition: IR.cpp:1052
MLIR_CAPI_EXPORTED void mlirOpPrintingFlagsElideLargeResourceString(MlirOpPrintingFlags flags, intptr_t largeResourceLimit)
Enables the elision of large resources strings by omitting them from the dialect_resources section.
Definition: IR.cpp:207
MLIR_CAPI_EXPORTED MlirDialect mlirAttributeGetDialect(MlirAttribute attribute)
Gets the dialect of the attribute.
Definition: IR.cpp:1131
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:1139
MLIR_CAPI_EXPORTED MlirRegion mlirBlockGetParentRegion(MlirBlock block)
Returns the region that contains this block.
Definition: IR.cpp:860
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:744
static bool mlirValueIsNull(MlirValue value)
Returns whether the value is null.
Definition: IR.h:907
MLIR_CAPI_EXPORTED void mlirValueReplaceAllUsesExcept(MlirValue of, MlirValue with, intptr_t numExceptions, MlirOperation *exceptions)
Replace all uses of 'of' value with 'with' value, updating anything in the IR that uses 'of' to use '...
Definition: IR.cpp:1032
MLIR_CAPI_EXPORTED void mlirOperationPrintWithState(MlirOperation op, MlirAsmState state, MlirStringCallback callback, void *userData)
Same as mlirOperationPrint but accepts AsmState controlling the printing behavior as well as caching ...
Definition: IR.cpp:712
MlirWalkResult
Operation walk result.
Definition: IR.h:730
@ MlirWalkResultInterrupt
Definition: IR.h:732
@ MlirWalkResultSkip
Definition: IR.h:733
@ MlirWalkResultAdvance
Definition: IR.h:731
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:801
MLIR_CAPI_EXPORTED MlirAttribute mlirOperationGetAttributeByName(MlirOperation op, MlirStringRef name)
Returns an attribute attached to the operation given its name.
Definition: IR.cpp:686
static bool mlirTypeIsNull(MlirType type)
Checks whether a type is null.
Definition: IR.h:1017
MLIR_CAPI_EXPORTED bool mlirContextIsRegisteredOperation(MlirContext context, MlirStringRef name)
Returns whether the given fully-qualified operation (i.e.
Definition: IR.cpp:100
MLIR_CAPI_EXPORTED intptr_t mlirOperationGetNumSuccessors(MlirOperation op)
Returns the number of successor blocks of the operation.
Definition: IR.cpp:615
MLIR_CAPI_EXPORTED MlirOperation mlirOperationClone(MlirOperation op)
Creates a deep copy of an operation.
Definition: IR.cpp:522
MLIR_CAPI_EXPORTED intptr_t mlirBlockGetNumArguments(MlirBlock block)
Returns the number of arguments of the block.
Definition: IR.cpp:929
MLIR_CAPI_EXPORTED void mlirOpPrintingFlagsPrintGenericOpForm(MlirOpPrintingFlags flags)
Always print operations in the generic form.
Definition: IR.cpp:217
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:281
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:910
MLIR_CAPI_EXPORTED void mlirAsmStateDestroy(MlirAsmState state)
Destroys printing flags created with mlirAsmStateCreate.
Definition: IR.cpp:188
static bool mlirContextIsNull(MlirContext context)
Checks whether a context is null.
Definition: IR.h:104
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:95
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:202
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:807
MLIR_CAPI_EXPORTED void mlirBlockArgumentSetType(MlirValue value, MlirType type)
Sets the type of the block argument to the given type.
Definition: IR.cpp:982
MLIR_CAPI_EXPORTED MlirContext mlirOperationGetContext(MlirOperation op)
Gets the context this operation is associated with.
Definition: IR.cpp:534
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:844
static bool mlirBlockIsNull(MlirBlock block)
Checks whether a block is null.
Definition: IR.h:826
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:885
MLIR_CAPI_EXPORTED MlirValue mlirBlockGetArgument(MlirBlock block, intptr_t pos)
Returns pos-th argument of the block.
Definition: IR.cpp:947
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:1194
MLIR_CAPI_EXPORTED MlirContext mlirTypeGetContext(MlirType type)
Gets the context that a type was created with.
Definition: IR.cpp:1085
MLIR_CAPI_EXPORTED MlirLocation mlirLocationFileLineColRangeGet(MlirContext context, MlirStringRef filename, unsigned start_line, unsigned start_col, unsigned end_line, unsigned end_col)
Creates an File/Line/Column range location owned by the given context.
Definition: IR.cpp:269
MLIR_CAPI_EXPORTED void mlirValueDump(MlirValue value)
Prints the value to the standard error stream.
Definition: IR.cpp:1003
MLIR_CAPI_EXPORTED MlirModule mlirModuleCreateEmpty(MlirLocation location)
Creates a new, empty module and transfers ownership to the caller.
Definition: IR.cpp:320
MLIR_CAPI_EXPORTED bool mlirOpOperandIsNull(MlirOpOperand opOperand)
Returns whether the op operand is null.
Definition: IR.cpp:1050
MLIR_CAPI_EXPORTED MlirSymbolTable mlirSymbolTableCreate(MlirOperation operation)
Creates a symbol table for the given operation.
Definition: IR.cpp:1184
MLIR_CAPI_EXPORTED bool mlirLocationEqual(MlirLocation l1, MlirLocation l2)
Checks if two locations are equal.
Definition: IR.cpp:302
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:552
static bool mlirLocationIsNull(MlirLocation location)
Checks if the location is null.
Definition: IR.h:287
MLIR_CAPI_EXPORTED bool mlirOperationEqual(MlirOperation op, MlirOperation other)
Checks whether two operation handles point to the same operation.
Definition: IR.cpp:530
MLIR_CAPI_EXPORTED MlirValue mlirBlockAddArgument(MlirBlock block, MlirType type, MlirLocation loc)
Appends an argument of the specified type to the block.
Definition: IR.cpp:933
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:706
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:1018
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:310
MLIR_CAPI_EXPORTED bool mlirOperationVerify(MlirOperation op)
Verify the operation and return true if it passes, false if it fails.
Definition: IR.cpp:736
MLIR_CAPI_EXPORTED MlirOperation mlirModuleGetOperation(MlirModule module)
Views the module as a generic operation.
Definition: IR.cpp:355
MLIR_CAPI_EXPORTED bool mlirTypeEqual(MlirType t1, MlirType t2)
Checks if two types are equal.
Definition: IR.cpp:1097
MLIR_CAPI_EXPORTED MlirOperationState mlirOperationStateGet(MlirStringRef name, MlirLocation loc)
Constructs an operation state from a name and a location.
Definition: IR.cpp:367
MLIR_CAPI_EXPORTED unsigned mlirOpOperandGetOperandNumber(MlirOpOperand opOperand)
Returns the operand number of an op operand.
Definition: IR.cpp:1060
MLIR_CAPI_EXPORTED MlirOperation mlirBlockGetTerminator(MlirBlock block)
Returns the terminator operation in the block or null if no terminator.
Definition: IR.cpp:875
MLIR_CAPI_EXPORTED void mlirOpPrintingFlagsSkipRegions(MlirOpPrintingFlags flags)
Skip printing regions.
Definition: IR.cpp:229
MLIR_CAPI_EXPORTED MlirOperation mlirOperationGetNextInBlock(MlirOperation op)
Returns an operation immediately following the given operation it its enclosing block.
Definition: IR.cpp:584
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:556
MLIR_CAPI_EXPORTED MlirContext mlirModuleGetContext(MlirModule module)
Gets the context that a module was created with.
Definition: IR.cpp:341
MLIR_CAPI_EXPORTED MlirLocation mlirLocationFromAttribute(MlirAttribute attribute)
Creates a location from a location attribute.
Definition: IR.cpp:257
MLIR_CAPI_EXPORTED void mlirOpPrintingFlagsAssumeVerified(MlirOpPrintingFlags flags)
Do not verify the operation when using custom operation printers.
Definition: IR.cpp:225
MLIR_CAPI_EXPORTED MlirTypeID mlirTypeGetTypeID(MlirType type)
Gets the type ID of the type.
Definition: IR.cpp:1089
MLIR_CAPI_EXPORTED MlirStringRef mlirSymbolTableGetVisibilityAttributeName(void)
Returns the name of the attribute used to store symbol visibility.
Definition: IR.cpp:1180
static bool mlirDialectIsNull(MlirDialect dialect)
Checks if the dialect is null.
Definition: IR.h:173
MLIR_CAPI_EXPORTED void mlirBytecodeWriterConfigDestroy(MlirBytecodeWriterConfig config)
Destroys printing flags created with mlirBytecodeWriterConfigCreate.
Definition: IR.cpp:240
MLIR_CAPI_EXPORTED MlirValue mlirOperationGetOperand(MlirOperation op, intptr_t pos)
Returns pos-th operand of the operation.
Definition: IR.cpp:592
MLIR_CAPI_EXPORTED void mlirOperationStateAddAttributes(MlirOperationState *state, intptr_t n, MlirNamedAttribute const *attributes)
Definition: IR.cpp:408
MLIR_CAPI_EXPORTED MlirBlock mlirBlockGetNextInRegion(MlirBlock block)
Returns the block immediately following the given block in its parent region.
Definition: IR.cpp:864
MLIR_CAPI_EXPORTED MlirLocation mlirLocationCallSiteGet(MlirLocation callee, MlirLocation caller)
Creates a call site location with a callee and a caller.
Definition: IR.cpp:277
MLIR_CAPI_EXPORTED MlirOperation mlirOpResultGetOwner(MlirValue value)
Returns an operation that produced this value as its result.
Definition: IR.cpp:986
MLIR_CAPI_EXPORTED bool mlirValueIsAOpResult(MlirValue value)
Returns 1 if the value is an operation result, 0 otherwise.
Definition: IR.cpp:969
MLIR_CAPI_EXPORTED intptr_t mlirOperationGetNumOperands(MlirOperation op)
Returns the number of operands of the operation.
Definition: IR.cpp:588
static bool mlirDialectRegistryIsNull(MlirDialectRegistry registry)
Checks if the dialect registry is null.
Definition: IR.h:235
MLIR_CAPI_EXPORTED void mlirOperationWalk(MlirOperation op, MlirOperationWalkCallback callback, void *userData, MlirWalkOrder walkOrder)
Walks operation op in walkOrder and calls callback on that operation.
Definition: IR.cpp:762
MLIR_CAPI_EXPORTED MlirContext mlirContextCreateWithThreading(bool threadingEnabled)
Creates an MLIR context with an explicit setting of the multithreading setting and transfers its owne...
Definition: IR.cpp:55
MLIR_CAPI_EXPORTED MlirOperation mlirBlockGetParentOperation(MlirBlock)
Returns the closest surrounding operation that contains this block.
Definition: IR.cpp:856
MLIR_CAPI_EXPORTED intptr_t mlirOperationGetNumRegions(MlirOperation op)
Returns the number of regions attached to the given operation.
Definition: IR.cpp:560
MLIR_CAPI_EXPORTED MlirContext mlirLocationGetContext(MlirLocation location)
Gets the context that a location was created with.
Definition: IR.cpp:306
MLIR_CAPI_EXPORTED void mlirBlockEraseArgument(MlirBlock block, unsigned index)
Erase the argument at 'index' and remove it from the argument list.
Definition: IR.cpp:938
MLIR_CAPI_EXPORTED bool mlirOperationRemoveAttributeByName(MlirOperation op, MlirStringRef name)
Removes an attribute by name.
Definition: IR.cpp:696
MLIR_CAPI_EXPORTED void mlirAttributeDump(MlirAttribute attr)
Prints the attribute to the standard error stream.
Definition: IR.cpp:1145
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:1209
MLIR_CAPI_EXPORTED MlirAttribute mlirAttributeParseGet(MlirContext context, MlirStringRef attr)
Parses an attribute. The attribute is owned by the context.
Definition: IR.cpp:1112
MLIR_CAPI_EXPORTED MlirModule mlirModuleCreateParse(MlirContext context, MlirStringRef module)
Parses a module from the string and transfers ownership to the caller.
Definition: IR.cpp:324
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:797
MLIR_CAPI_EXPORTED MlirOperation mlirBlockGetFirstOperation(MlirBlock block)
Returns the first operation in the block.
Definition: IR.cpp:868
MLIR_CAPI_EXPORTED void mlirTypeDump(MlirType type)
Prints the type to the standard error stream.
Definition: IR.cpp:1106
MLIR_CAPI_EXPORTED MlirValue mlirOperationGetResult(MlirOperation op, intptr_t pos)
Returns pos-th result of the operation.
Definition: IR.cpp:611
MLIR_CAPI_EXPORTED MlirBytecodeWriterConfig mlirBytecodeWriterConfigCreate(void)
Creates new printing flags with defaults, intended for customization.
Definition: IR.cpp:236
MLIR_CAPI_EXPORTED MlirContext mlirAttributeGetContext(MlirAttribute attribute)
Gets the context that an attribute was created with.
Definition: IR.cpp:1116
MLIR_CAPI_EXPORTED MlirBlock mlirBlockArgumentGetOwner(MlirValue value)
Returns the block in which this value is defined as an argument.
Definition: IR.cpp:973
static bool mlirRegionIsNull(MlirRegion region)
Checks whether a region is null.
Definition: IR.h:765
MLIR_CAPI_EXPORTED void mlirOperationDestroy(MlirOperation op)
Takes an operation owned by the caller and destroys it.
Definition: IR.cpp:526
MLIR_CAPI_EXPORTED MlirRegion mlirOperationGetRegion(MlirOperation op, intptr_t pos)
Returns pos-th region attached to the operation.
Definition: IR.cpp:564
MLIR_CAPI_EXPORTED MlirDialect mlirTypeGetDialect(MlirType type)
Gets the dialect a type belongs to.
Definition: IR.cpp:1093
MLIR_CAPI_EXPORTED MlirIdentifier mlirIdentifierGet(MlirContext context, MlirStringRef str)
Gets an identifier with the given string value.
Definition: IR.cpp:1156
MLIR_CAPI_EXPORTED void mlirOperationSetSuccessor(MlirOperation op, intptr_t pos, MlirBlock block)
Set pos-th successor of the operation.
Definition: IR.cpp:672
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:108
MLIR_CAPI_EXPORTED void mlirOperationStateAddOwnedRegions(MlirOperationState *state, intptr_t n, MlirRegion const *regions)
Definition: IR.cpp:400
MLIR_CAPI_EXPORTED void mlirOperationStateAddSuccessors(MlirOperationState *state, intptr_t n, MlirBlock const *successors)
Definition: IR.cpp:404
MLIR_CAPI_EXPORTED MlirBlock mlirModuleGetBody(MlirModule module)
Gets the body of the module, i.e. the only block it contains.
Definition: IR.cpp:345
MLIR_CAPI_EXPORTED void mlirOpPrintingFlagsDestroy(MlirOpPrintingFlags flags)
Destroys printing flags created with mlirOpPrintingFlagsCreate.
Definition: IR.cpp:198
MLIR_CAPI_EXPORTED MlirLocation mlirLocationNameGet(MlirContext context, MlirStringRef name, MlirLocation childLoc)
Creates a name location owned by the given context.
Definition: IR.cpp:289
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:104
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:951
MLIR_CAPI_EXPORTED void mlirBytecodeWriterConfigDesiredEmitVersion(MlirBytecodeWriterConfig flags, int64_t version)
Sets the version to emit in the writer config.
Definition: IR.cpp:244
MLIR_CAPI_EXPORTED MlirStringRef mlirSymbolTableGetSymbolAttributeName(void)
Returns the name of the attribute used to store symbol names compatible with symbol tables.
Definition: IR.cpp:1176
MLIR_CAPI_EXPORTED MlirRegion mlirRegionCreate(void)
Creates a new empty region and transfers ownership to the caller.
Definition: IR.cpp:784
MLIR_CAPI_EXPORTED MlirModule mlirModuleCreateParseFromFile(MlirContext context, MlirStringRef fileName)
Parses a module from file and transfers ownership to the caller.
Definition: IR.cpp:332
MLIR_CAPI_EXPORTED void mlirBlockDetach(MlirBlock block)
Detach a block from the owning region and assume ownership.
Definition: IR.cpp:924
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:391
MLIR_CAPI_EXPORTED void mlirOpPrintingFlagsEnableDebugInfo(MlirOpPrintingFlags flags, bool enable, bool prettyForm)
Enable or disable printing of debug information (based on enable).
Definition: IR.cpp:212
MLIR_CAPI_EXPORTED MlirLocation mlirOperationGetLocation(MlirOperation op)
Gets the location of the operation.
Definition: IR.cpp:538
MLIR_CAPI_EXPORTED MlirTypeID mlirAttributeGetTypeID(MlirAttribute attribute)
Gets the type id of the attribute.
Definition: IR.cpp:1127
MLIR_CAPI_EXPORTED void mlirOperationSetOperand(MlirOperation op, intptr_t pos, MlirValue newValue)
Sets the pos-th operand of the operation.
Definition: IR.cpp:596
MLIR_CAPI_EXPORTED void mlirOperationDump(MlirOperation op)
Prints an operation to stderr.
Definition: IR.cpp:734
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:990
MLIR_CAPI_EXPORTED MlirOpPrintingFlags mlirOpPrintingFlagsCreate(void)
Creates new printing flags with defaults, intended for customization.
Definition: IR.cpp:194
MLIR_CAPI_EXPORTED MlirAsmState mlirAsmStateCreateForValue(MlirValue value, MlirOpPrintingFlags flags)
Creates new AsmState from value.
Definition: IR.cpp:170
MLIR_CAPI_EXPORTED MlirOperation mlirOperationCreate(MlirOperationState *state)
Creates an operation and transfers ownership to the caller.
Definition: IR.cpp:476
static bool mlirSymbolTableIsNull(MlirSymbolTable symbolTable)
Returns true if the symbol table is null.
Definition: IR.h:1107
MLIR_CAPI_EXPORTED bool mlirContextGetAllowUnregisteredDialects(MlirContext context)
Returns whether the context allows unregistered dialects.
Definition: IR.cpp:77
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:740
MLIR_CAPI_EXPORTED intptr_t mlirOperationGetNumAttributes(MlirOperation op)
Returns the number of attributes attached to the operation.
Definition: IR.cpp:677
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:1005
MLIR_CAPI_EXPORTED MlirLogicalResult mlirOperationWriteBytecodeWithConfig(MlirOperation op, MlirBytecodeWriterConfig config, MlirStringCallback callback, void *userData)
Same as mlirOperationWriteBytecode but with writer config and returns failure only if desired bytecod...
Definition: IR.cpp:727
MLIR_CAPI_EXPORTED void mlirValueSetType(MlirValue value, MlirType type)
Set the type of the value.
Definition: IR.cpp:999
MLIR_CAPI_EXPORTED MlirType mlirValueGetType(MlirValue value)
Returns the type of the value.
Definition: IR.cpp:995
MLIR_CAPI_EXPORTED void mlirContextDestroy(MlirContext context)
Takes an MLIR context owned by the caller and destroys it.
Definition: IR.cpp:71
MLIR_CAPI_EXPORTED MlirOperation mlirOperationCreateParse(MlirContext context, MlirStringRef sourceStr, MlirStringRef sourceName)
Parses an operation, giving ownership to the caller.
Definition: IR.cpp:513
MLIR_CAPI_EXPORTED bool mlirAttributeEqual(MlirAttribute a1, MlirAttribute a2)
Checks if two attributes are equal.
Definition: IR.cpp:1135
static bool mlirOperationIsNull(MlirOperation op)
Checks whether the underlying operation is null.
Definition: IR.h:528
MLIR_CAPI_EXPORTED MlirBlock mlirRegionGetFirstBlock(MlirRegion region)
Gets the first block in the region.
Definition: IR.cpp:790
static MlirStringRef mlirStringRefCreate(const char *str, size_t length)
Constructs a string reference from the pointer and length.
Definition: Support.h:82
static MlirLogicalResult mlirLogicalResultFailure(void)
Creates a logical result representing a failure.
Definition: Support.h:138
MLIR_CAPI_EXPORTED size_t mlirTypeIDHashValue(MlirTypeID typeID)
Returns the hash value of the type id.
Definition: Support.cpp:51
static MlirLogicalResult mlirLogicalResultSuccess(void)
Creates a logical result representing a success.
Definition: Support.h:132
static bool mlirLogicalResultIsFailure(MlirLogicalResult res)
Checks if the given logical result represents a failure.
Definition: Support.h:127
static bool mlirTypeIDIsNull(MlirTypeID typeID)
Checks whether a type id is null.
Definition: Support.h:163
MLIR_CAPI_EXPORTED bool mlirTypeIDEqual(MlirTypeID typeID1, MlirTypeID typeID2)
Checks if two type ids are equal.
Definition: Support.cpp:47
void walk(Operation *op, function_ref< void(Region *)> callback, WalkOrder order)
Walk all of the regions, blocks, or operations nested under (and including) the given operation.
Definition: Visitors.h:136
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:344
inline ::llvm::hash_code hash_value(const PolynomialBase< D, T > &arg)
Definition: Polynomial.h:262
PyObjectRef< PyMlirContext > PyMlirContextRef
Wrapper around MlirContext.
Definition: IRModule.h:162
PyObjectRef< PyModule > PyModuleRef
Definition: IRModule.h:533
void populateIRCore(nanobind::module_ &m)
PyObjectRef< PyOperation > PyOperationRef
Definition: IRModule.h:616
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:20
Include the generated interface declarations.
const FrozenRewritePatternSet GreedyRewriteConfig config
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
Definition: Verifier.cpp:425
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:116
Named MLIR attribute.
Definition: IR.h:76
MlirAttribute attribute
Definition: IR.h:78
MlirIdentifier name
Definition: IR.h:77
An auxiliary class for constructing operations.
Definition: IR.h:349
A pointer to a sized fragment of a string, not necessarily null-terminated.
Definition: Support.h:73
const char * data
Pointer to the first symbol.
Definition: Support.h:74
size_t length
Length of the fragment.
Definition: Support.h:75
static bool dunderContains(const std::string &attributeKind)
Definition: IRCore.cpp:292
static void dunderSetItemNamed(const std::string &attributeKind, nb::callable func, bool replace)
Definition: IRCore.cpp:301
static nb::callable dunderGetItemNamed(const std::string &attributeKind)
Definition: IRCore.cpp:295
static void bind(nb::module_ &m)
Definition: IRCore.cpp:307
Wrapper for the global LLVM debugging flag.
Definition: IRCore.cpp:252
static void bind(nb::module_ &m)
Definition: IRCore.cpp:263
static void set(nb::object &o, bool enable)
Definition: IRCore.cpp:253
static bool get(const nb::object &)
Definition: IRCore.cpp:258
Accumulates into a python string from a method that accepts an MlirStringCallback.
MlirStringCallback getCallback()
Custom exception that allows access to error diagnostic information.
Definition: IRModule.h:1303
std::vector< PyDiagnostic::DiagnosticInfo > errorDiagnostics
Definition: IRModule.h:1308
Materialized diagnostic information.
Definition: IRModule.h:364
RAII object that captures any error diagnostics emitted to the provided context.
Definition: IRModule.h:430
std::vector< PyDiagnostic::DiagnosticInfo > take()
Definition: IRModule.h:440
ErrorCapture(PyMlirContextRef ctx)
Definition: IRModule.h:431