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