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