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