MLIR 23.0.0git
IRCore.h
Go to the documentation of this file.
1//===- IRCore.h - IR helpers of python bindings ---------------------------===//
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#ifndef MLIR_BINDINGS_PYTHON_IRCORE_H
10#define MLIR_BINDINGS_PYTHON_IRCORE_H
11
12#include <cstddef>
13#include <exception>
14#include <optional>
15#include <sstream>
16#include <utility>
17#include <vector>
18
19#include "Globals.h"
20#include "NanobindUtils.h"
21#include "mlir-c/AffineExpr.h"
22#include "mlir-c/AffineMap.h"
24#include "mlir-c/Debug.h"
25#include "mlir-c/Diagnostics.h"
27#include "mlir-c/IR.h"
28#include "mlir-c/IntegerSet.h"
29#include "mlir-c/Support.h"
30#include "mlir-c/Transforms.h"
33
34namespace mlir {
35namespace python {
37
38class PyBlock;
39class PyDiagnostic;
42class PyLocation;
44class PyMlirContext;
46class PyModule;
47class PyOperation;
48class PyOperationBase;
49class PyType;
50class PySymbolTable;
51class PyValue;
52
53/// Wrapper for the global LLVM debugging flag.
55 static void set(nanobind::object &o, bool enable);
56 static bool get(const nanobind::object &);
57 static void bind(nanobind::module_ &m);
58
59private:
60 static nanobind::ft_mutex mutex;
61};
62
63/// Template for a reference to a concrete type which captures a python
64/// reference to its underlying python object.
65template <typename T>
67public:
68 PyObjectRef(T *referrent, nanobind::object object)
69 : referrent(referrent), object(std::move(object)) {
70 assert(this->referrent &&
71 "cannot construct PyObjectRef with null referrent");
72 assert(this->object && "cannot construct PyObjectRef with null object");
73 }
74 PyObjectRef(PyObjectRef &&other) noexcept
75 : referrent(other.referrent), object(std::move(other.object)) {
76 other.referrent = nullptr;
77 assert(!other.object);
78 }
80 : referrent(other.referrent), object(other.object /* copies */) {}
82 referrent = other.referrent;
83 object = other.object;
84 return *this;
85 }
86 PyObjectRef &operator=(PyObjectRef &&other) noexcept {
87 referrent = other.referrent;
88 object = std::move(other.object);
89 other.referrent = nullptr;
90 assert(!other.object);
91 return *this;
92 }
93 ~PyObjectRef() = default;
94
96 if (!object)
97 return 0;
98 return Py_REFCNT(object.ptr());
99 }
100
101 /// Releases the object held by this instance, returning it.
102 /// This is the proper thing to return from a function that wants to return
103 /// the reference. Note that this does not work from initializers.
104 nanobind::object releaseObject() {
105 assert(referrent && object);
106 referrent = nullptr;
107 auto stolen = std::move(object);
108 return stolen;
109 }
110
111 T *get() { return referrent; }
113 assert(referrent && object);
114 return referrent;
115 }
116 nanobind::object getObject() {
117 assert(referrent && object);
118 return object;
119 }
120 operator bool() const { return referrent && object; }
121
122 using NBTypedT = nanobind::typed<nanobind::object, T>;
123
124private:
125 T *referrent;
126 nanobind::object object;
127};
128
129/// Tracks an entry in the thread context stack. New entries are pushed onto
130/// here for each with block that activates a new InsertionPoint, Context or
131/// Location.
132///
133/// Pushing either a Location or InsertionPoint also pushes its associated
134/// Context. Pushing a Context will not modify the Location or InsertionPoint
135/// unless if they are from a different context, in which case, they are
136/// cleared.
138public:
144
145 PyThreadContextEntry(FrameKind frameKind, nanobind::object context,
146 nanobind::object insertionPoint,
147 nanobind::object location)
148 : context(std::move(context)), insertionPoint(std::move(insertionPoint)),
149 location(std::move(location)), frameKind(frameKind) {}
150
151 /// Gets the top of stack context and return nullptr if not defined.
153
154 /// Gets the top of stack insertion point and return nullptr if not defined.
155 static PyInsertionPoint *getDefaultInsertionPoint();
156
157 /// Gets the top of stack location and returns nullptr if not defined.
158 static PyLocation *getDefaultLocation();
159
161 PyInsertionPoint *getInsertionPoint();
162 PyLocation *getLocation();
163 FrameKind getFrameKind() { return frameKind; }
164
165 /// Stack management.
166 static PyThreadContextEntry *getTopOfStack();
167 static nanobind::object pushContext(nanobind::object context);
168 static void popContext(PyMlirContext &context);
169 static nanobind::object pushInsertionPoint(nanobind::object insertionPoint);
170 static void popInsertionPoint(PyInsertionPoint &insertionPoint);
171 static nanobind::object pushLocation(nanobind::object location);
172 static void popLocation(PyLocation &location);
173
174 /// Gets the thread local stack.
175 static std::vector<PyThreadContextEntry> &getStack();
176
177private:
178 static void push(FrameKind frameKind, nanobind::object context,
179 nanobind::object insertionPoint, nanobind::object location);
180
181 /// An object reference to the PyContext.
182 nanobind::object context;
183 /// An object reference to the current insertion point.
184 nanobind::object insertionPoint;
185 /// An object reference to the current location.
186 nanobind::object location;
187 // The kind of push that was performed.
188 FrameKind frameKind;
189};
190
191/// Wrapper around MlirLlvmThreadPool
192/// Python object owns the C++ thread pool
194public:
195 PyThreadPool();
197 PyThreadPool(const PyThreadPool &) = delete;
199
200 int getMaxConcurrency() const;
201 MlirLlvmThreadPool get() { return threadPool; }
202
203 std::string _mlir_thread_pool_ptr() const;
204
205private:
206 MlirLlvmThreadPool threadPool;
207};
208
209/// Wrapper around MlirContext.
212public:
213 PyMlirContext() = delete;
214 PyMlirContext(MlirContext context);
215 PyMlirContext(const PyMlirContext &) = delete;
217
218 /// Returns a context reference for the singleton PyMlirContext wrapper for
219 /// the given context.
220 static PyMlirContextRef forContext(MlirContext context);
222
223 /// Accesses the underlying MlirContext.
224 MlirContext get() { return context; }
225
226 /// Gets a strong reference to this context, which will ensure it is kept
227 /// alive for the life of the reference.
228 PyMlirContextRef getRef();
229
230 /// Gets a capsule wrapping the void* within the MlirContext.
231 nanobind::object getCapsule();
232
233 /// Creates a PyMlirContext from the MlirContext wrapped by a capsule.
234 /// Note that PyMlirContext instances are uniqued, so the returned object
235 /// may be a pre-existing object. Ownership of the underlying MlirContext
236 /// is taken by calling this function.
237 static nanobind::object createFromCapsule(nanobind::object capsule);
238
239 /// Gets the count of live context objects. Used for testing.
240 static size_t getLiveCount();
241
242 /// Gets the count of live modules associated with this context.
243 /// Used for testing.
244 size_t getLiveModuleCount();
245
246 /// Enter and exit the context manager.
247 static nanobind::object contextEnter(nanobind::object context);
248 void contextExit(const nanobind::object &excType,
249 const nanobind::object &excVal,
250 const nanobind::object &excTb);
251
252 /// Attaches a Python callback as a diagnostic handler, returning a
253 /// registration object (internally a PyDiagnosticHandler).
254 nanobind::object attachDiagnosticHandler(nanobind::object callback);
255
256 /// Controls whether error diagnostics should be propagated to diagnostic
257 /// handlers, instead of being captured by `ErrorCapture`.
258 void setEmitErrorDiagnostics(bool value) { emitErrorDiagnostics = value; }
259 bool getEmitErrorDiagnostics() { return emitErrorDiagnostics; }
260 struct ErrorCapture;
261
262private:
263 // Interns the mapping of live MlirContext::ptr to PyMlirContext instances,
264 // preserving the relationship that an MlirContext maps to a single
265 // PyMlirContext wrapper. This could be replaced in the future with an
266 // extension mechanism on the MlirContext for stashing user pointers.
267 // Note that this holds a handle, which does not imply ownership.
268 // Mappings will be removed when the context is destructed.
269 using LiveContextMap = std::unordered_map<void *, PyMlirContext *>;
270 static nanobind::ft_mutex live_contexts_mutex;
271 static LiveContextMap &getLiveContexts();
272
273 // Interns all live modules associated with this context. Modules tracked
274 // in this map are valid. When a module is invalidated, it is removed
275 // from this map, and while it still exists as an instance, any
276 // attempt to access it will raise an error.
277 using LiveModuleMap =
278 std::unordered_map<const void *, std::pair<nanobind::handle, PyModule *>>;
279 LiveModuleMap liveModules;
280
281 bool emitErrorDiagnostics = false;
282
283 MlirContext context;
284 friend class PyModule;
285 friend class PyOperation;
286};
287
288/// Used in function arguments when None should resolve to the current context
289/// manager set instance.
291 : public Defaulting<DefaultingPyMlirContext, PyMlirContext> {
292public:
294 static constexpr const char kTypeDescription[] = "_mlir.ir.Context";
295 static PyMlirContext &resolve();
296};
297
298/// Base class for all objects that directly or indirectly depend on an
299/// MlirContext. The lifetime of the context will extend at least to the
300/// lifetime of these instances.
301/// Immutable objects that depend on a context extend this directly.
303public:
304 BaseContextObject(PyMlirContextRef ref) : contextRef(std::move(ref)) {
305 assert(this->contextRef &&
306 "context object constructed with null context ref");
307 }
308
309 /// Accesses the context reference.
310 PyMlirContextRef &getContext() { return contextRef; }
311
312private:
313 PyMlirContextRef contextRef;
314};
315
316/// Wrapper around an MlirLocation.
318public:
319 PyLocation(PyMlirContextRef contextRef, MlirLocation loc)
320 : BaseContextObject(std::move(contextRef)), loc(loc) {}
321
322 operator MlirLocation() const { return loc; }
323 MlirLocation get() const { return loc; }
324
325 /// Enter and exit the context manager.
326 static nanobind::object contextEnter(nanobind::object location);
327 void contextExit(const nanobind::object &excType,
328 const nanobind::object &excVal,
329 const nanobind::object &excTb);
330
331 /// Gets a capsule wrapping the void* within the MlirLocation.
332 nanobind::object getCapsule();
333
334 /// Creates a PyLocation from the MlirLocation wrapped by a capsule.
335 /// Note that PyLocation instances are uniqued, so the returned object
336 /// may be a pre-existing object. Ownership of the underlying MlirLocation
337 /// is taken by calling this function.
338 static PyLocation createFromCapsule(nanobind::object capsule);
339
340private:
341 MlirLocation loc;
342};
343
351
352enum class PyWalkResult : std::underlying_type_t<MlirWalkResult> {
356};
357
358/// Traversal order for operation walk.
359enum class PyWalkOrder : std::underlying_type_t<MlirWalkOrder> {
362};
363
364/// Python class mirroring the C MlirDiagnostic struct. Note that these structs
365/// are only valid for the duration of a diagnostic callback and attempting
366/// to access them outside of that will raise an exception. This applies to
367/// nested diagnostics (in the notes) as well.
369public:
370 PyDiagnostic(MlirDiagnostic diagnostic) : diagnostic(diagnostic) {}
371 void invalidate();
372 bool isValid() { return valid; }
373 PyDiagnosticSeverity getSeverity();
374 PyLocation getLocation();
375 nanobind::str getMessage();
376 nanobind::typed<nanobind::tuple, PyDiagnostic> getNotes();
377
378 /// Materialized diagnostic information. This is safe to access outside the
379 /// diagnostic callback.
383 std::string message;
384 std::vector<DiagnosticInfo> notes;
385 };
387
388private:
389 MlirDiagnostic diagnostic;
390
391 void checkValid();
392 /// If notes have been materialized from the diagnostic, then this will
393 /// be populated with the corresponding objects (all castable to
394 /// PyDiagnostic).
395 std::optional<nanobind::tuple> materializedNotes;
396 bool valid = true;
397};
398
399/// Represents a diagnostic handler attached to the context. The handler's
400/// callback will be invoked with PyDiagnostic instances until the detach()
401/// method is called or the context is destroyed. A diagnostic handler can be
402/// the subject of a `with` block, which will detach it when the block exits.
403///
404/// Since diagnostic handlers can call back into Python code which can do
405/// unsafe things (i.e. recursively emitting diagnostics, raising exceptions,
406/// etc), this is generally not deemed to be a great user-level API. Users
407/// should generally use some form of DiagnosticCollector. If the handler raises
408/// any exceptions, they will just be emitted to stderr and dropped.
409///
410/// The unique usage of this class means that its lifetime management is
411/// different from most other parts of the API. Instances are always created
412/// in an attached state and can transition to a detached state by either:
413/// a) The context being destroyed and unregistering all handlers.
414/// b) An explicit call to detach().
415/// The object may remain live from a Python perspective for an arbitrary time
416/// after detachment, but there is nothing the user can do with it (since there
417/// is no way to attach an existing handler object).
419public:
420 PyDiagnosticHandler(MlirContext context, nanobind::object callback);
422
423 bool isAttached() { return registeredID.has_value(); }
424 bool getHadError() { return hadError; }
425
426 /// Detaches the handler. Does nothing if not attached.
427 void detach();
428
429 nanobind::object contextEnter() { return nanobind::cast(this); }
430 void contextExit(const nanobind::object &excType,
431 const nanobind::object &excVal,
432 const nanobind::object &excTb) {
433 detach();
434 }
435
436private:
437 MlirContext context;
438 nanobind::object callback;
439 std::optional<MlirDiagnosticHandlerID> registeredID;
440 bool hadError = false;
441 friend class PyMlirContext;
442};
443
444/// RAII object that captures any error diagnostics emitted to the provided
445/// context.
448 : ctx(ctx), handlerID(mlirContextAttachDiagnosticHandler(
449 ctx->get(), handler, /*userData=*/this,
450 /*deleteUserData=*/nullptr)) {}
452 mlirContextDetachDiagnosticHandler(ctx->get(), handlerID);
453 assert(errors.empty() && "unhandled captured errors");
454 }
455
456 std::vector<PyDiagnostic::DiagnosticInfo> take() {
457 return std::move(errors);
458 };
459
460private:
462 MlirDiagnosticHandlerID handlerID;
463 std::vector<PyDiagnostic::DiagnosticInfo> errors;
464
465 static MlirLogicalResult handler(MlirDiagnostic diag, void *userData);
466};
467
468/// Wrapper around an MlirDialect. This is exported as `DialectDescriptor` in
469/// order to differentiate it from the `Dialect` base class which is extended by
470/// plugins which extend dialect functionality through extension python code.
471/// This should be seen as the "low-level" object and `Dialect` as the
472/// high-level, user facing object.
474public:
475 PyDialectDescriptor(PyMlirContextRef contextRef, MlirDialect dialect)
476 : BaseContextObject(std::move(contextRef)), dialect(dialect) {}
477
478 MlirDialect get() { return dialect; }
479
480private:
481 MlirDialect dialect;
482};
483
484/// User-level object for accessing dialects with dotted syntax such as:
485/// ctx.dialect.std
487public:
489 : BaseContextObject(std::move(contextRef)) {}
490
491 MlirDialect getDialectForKey(const std::string &key, bool attrError);
492};
493
494/// User-level dialect object. For dialects that have a registered extension,
495/// this will be the base class of the extension dialect type. For un-extended,
496/// objects of this type will be returned directly.
498public:
499 PyDialect(nanobind::object descriptor) : descriptor(std::move(descriptor)) {}
500
501 nanobind::object getDescriptor() { return descriptor; }
502
503private:
504 nanobind::object descriptor;
505};
506
507/// Wrapper around an MlirDialectRegistry.
508/// Upon construction, the Python wrapper takes ownership of the
509/// underlying MlirDialectRegistry.
511public:
513 PyDialectRegistry(MlirDialectRegistry registry) : registry(registry) {}
515 if (!mlirDialectRegistryIsNull(registry))
517 }
520 : registry(other.registry) {
521 other.registry = {nullptr};
522 }
523
524 operator MlirDialectRegistry() const { return registry; }
525 MlirDialectRegistry get() const { return registry; }
526
527 nanobind::object getCapsule();
528 static PyDialectRegistry createFromCapsule(nanobind::object capsule);
529
530private:
531 MlirDialectRegistry registry;
532};
533
534/// Used in function arguments when None should resolve to the current context
535/// manager set instance.
537 : public Defaulting<DefaultingPyLocation, PyLocation> {
538public:
540 static constexpr const char kTypeDescription[] = "_mlir.ir.Location";
541 static PyLocation &resolve();
542
543 operator MlirLocation() const { return *get(); }
544};
545
546/// Wrapper around MlirModule.
547/// This is the top-level, user-owned object that contains regions/ops/blocks.
548class PyModule;
551public:
552 /// Returns a PyModule reference for the given MlirModule. This always returns
553 /// a new object.
554 static PyModuleRef forModule(MlirModule module);
555 PyModule(PyModule &) = delete;
557 ~PyModule();
558
559 /// Gets the backing MlirModule.
560 MlirModule get() { return module; }
561
562 /// Gets a strong reference to this module.
564 return PyModuleRef(this, nanobind::borrow<nanobind::object>(handle));
565 }
566
567 /// Gets a capsule wrapping the void* within the MlirModule.
568 /// Note that the module does not (yet) provide a corresponding factory for
569 /// constructing from a capsule as that would require uniquing PyModule
570 /// instances, which is not currently done.
571 nanobind::object getCapsule();
572
573 /// Creates a PyModule from the MlirModule wrapped by a capsule.
574 /// Note this returns a new object BUT clearMlirModule() must be called to
575 /// prevent double-frees (of the underlying mlir::Module).
576 static nanobind::object createFromCapsule(nanobind::object capsule);
577
578 void clearMlirModule() { module = {nullptr}; }
579
580private:
581 PyModule(PyMlirContextRef contextRef, MlirModule module);
582 MlirModule module;
583 nanobind::handle handle;
584};
585
586class PyAsmState;
587
588/// Base class for PyOperation and PyOpView which exposes the primary, user
589/// visible methods for manipulating it.
591public:
592 virtual ~PyOperationBase() = default;
593 /// Implements the bound 'print' method and helps with others.
594 void print(std::optional<int64_t> largeElementsLimit,
595 std::optional<int64_t> largeResourceLimit, bool enableDebugInfo,
596 bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope,
597 bool useNameLocAsPrefix, bool assumeVerified,
598 nanobind::object fileObject, bool binary, bool skipRegions);
599 void print(PyAsmState &state, nanobind::object fileObject, bool binary);
600
601 nanobind::object
602 getAsm(bool binary, std::optional<int64_t> largeElementsLimit,
603 std::optional<int64_t> largeResourceLimit, bool enableDebugInfo,
604 bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope,
605 bool useNameLocAsPrefix, bool assumeVerified, bool skipRegions);
606
607 // Implement the bound 'writeBytecode' method.
608 void writeBytecode(const nanobind::object &fileObject,
609 std::optional<int64_t> bytecodeVersion);
610
611 // Implement the walk method.
612 void walk(std::function<PyWalkResult(MlirOperation)> callback,
613 PyWalkOrder walkOrder);
614
615 /// Moves the operation before or after the other operation.
616 void moveAfter(PyOperationBase &other);
617 void moveBefore(PyOperationBase &other);
618
619 /// Given an operation 'other' that is within the same parent block, return
620 /// whether the current operation is before 'other' in the operation list
621 /// of the parent block.
622 /// Note: This function has an average complexity of O(1), but worst case may
623 /// take O(N) where N is the number of operations within the parent block.
624 bool isBeforeInBlock(PyOperationBase &other);
625
626 /// Verify the operation. Throws `MLIRError` if verification fails, and
627 /// returns `true` otherwise.
628 bool verify();
629
630 /// Each must provide access to the raw Operation.
631 virtual PyOperation &getOperation() = 0;
632};
633
634/// Wrapper around PyOperation.
635/// Operations exist in either an attached (dependent) or detached (top-level)
636/// state. In the detached state (as on creation), an operation is owned by
637/// the creator and its lifetime extends either until its reference count
638/// drops to zero or it is attached to a parent, at which point its lifetime
639/// is bounded by its top-level parent reference.
640class PyOperation;
641class PyOpView;
644 public BaseContextObject {
645public:
646 ~PyOperation() override;
647 PyOperation &getOperation() override { return *this; }
648
649 /// Returns a PyOperation for the given MlirOperation, optionally associating
650 /// it with a parentKeepAlive.
651 static PyOperationRef
652 forOperation(PyMlirContextRef contextRef, MlirOperation operation,
653 nanobind::object parentKeepAlive = nanobind::object());
654
655 /// Creates a detached operation. The operation must not be associated with
656 /// any existing live operation.
657 static PyOperationRef
658 createDetached(PyMlirContextRef contextRef, MlirOperation operation,
659 nanobind::object parentKeepAlive = nanobind::object());
660
661 /// Parses a source string (either text assembly or bytecode), creating a
662 /// detached operation.
663 static PyOperationRef parse(PyMlirContextRef contextRef,
664 const std::string &sourceStr,
665 const std::string &sourceName);
666
667 /// Detaches the operation from its parent block and updates its state
668 /// accordingly.
669 void detachFromParent();
670
671 /// Gets the backing operation.
672 operator MlirOperation() const { return get(); }
673 MlirOperation get() const;
674
675 PyOperationRef getRef();
676
677 bool isAttached() { return attached; }
678 void setAttached(const nanobind::object &parent = nanobind::object());
679 void setDetached();
680 void checkValid() const;
681
682 /// Gets the owning block or raises an exception if the operation has no
683 /// owning block.
684 PyBlock getBlock();
685
686 /// Gets the parent operation or raises an exception if the operation has
687 /// no parent.
688 std::optional<PyOperationRef> getParentOperation();
689
690 /// Gets a capsule wrapping the void* within the MlirOperation.
691 nanobind::object getCapsule();
692
693 /// Creates a PyOperation from the MlirOperation wrapped by a capsule.
694 /// Ownership of the underlying MlirOperation is taken by calling this
695 /// function.
696 static nanobind::object createFromCapsule(const nanobind::object &capsule);
697
698 /// Creates an operation. See corresponding python docstring.
699 static nanobind::object
700 create(std::string_view name, std::optional<std::vector<PyType *>> results,
701 const MlirValue *operands, size_t numOperands,
702 std::optional<nanobind::dict> attributes,
703 std::optional<std::vector<PyBlock *>> successors, int regions,
704 PyLocation &location, const nanobind::object &ip, bool inferType);
705
706 /// Creates an OpView suitable for this operation.
707 nanobind::object createOpView();
708
709 /// Erases the underlying MlirOperation, removes its pointer from the
710 /// parent context's live operations map, and sets the valid bit false.
711 void erase();
712
713 /// Invalidate the operation.
714 void setInvalid() { valid = false; }
715
716 /// Clones this operation.
717 nanobind::object clone(const nanobind::object &ip);
718
719 PyOperation(PyMlirContextRef contextRef, MlirOperation operation);
720
721private:
722 static PyOperationRef createInstance(PyMlirContextRef contextRef,
723 MlirOperation operation,
724 nanobind::object parentKeepAlive);
725
726 MlirOperation operation;
727 nanobind::handle handle;
728 // Keeps the parent alive, regardless of whether it is an Operation or
729 // Module.
730 // TODO: As implemented, this facility is only sufficient for modeling the
731 // trivial module parent back-reference. Generalize this to also account for
732 // transitions from detached to attached and address TODOs in the
733 // ir_operation.py regarding testing corresponding lifetime guarantees.
734 nanobind::object parentKeepAlive;
735 bool attached = true;
736 bool valid = true;
737
738 friend class PyOperationBase;
739 friend class PySymbolTable;
740};
741
742/// A PyOpView is equivalent to the C++ "Op" wrappers: these are the basis for
743/// providing more instance-specific accessors and serve as the base class for
744/// custom ODS-style operation classes. Since this class is subclass on the
745/// python side, it must present an __init__ method that operates in pure
746/// python types.
748public:
749 PyOpView(const nanobind::object &operationObject);
750 PyOperation &getOperation() override { return operation; }
751
752 nanobind::object getOperationObject() { return operationObject; }
753
754 static nanobind::typed<nanobind::object, PyOperation>
755 buildGeneric(std::string_view name, std::tuple<int, bool> opRegionSpec,
756 nanobind::object operandSegmentSpecObj,
757 nanobind::object resultSegmentSpecObj,
758 std::optional<nanobind::sequence> resultTypeList,
759 nanobind::sequence operandList,
760 std::optional<nanobind::dict> attributes,
761 std::optional<std::vector<PyBlock *>> successors,
762 std::optional<int> regions, PyLocation &location,
763 const nanobind::object &maybeIp);
764
765 /// Construct an instance of a class deriving from OpView, bypassing its
766 /// `__init__` method. The derived class will typically define a constructor
767 /// that provides a convenient builder, but we need to side-step this when
768 /// constructing an `OpView` for an already-built operation.
769 ///
770 /// The caller is responsible for verifying that `operation` is a valid
771 /// operation to construct `cls` with.
772 static nanobind::object constructDerived(const nanobind::object &cls,
773 const nanobind::object &operation);
774
775private:
776 PyOperation &operation; // For efficient, cast-free access from C++
777 nanobind::object operationObject; // Holds the reference.
778};
779
780/// Wrapper around an MlirRegion.
781/// Regions are managed completely by their containing operation. Unlike the
782/// C++ API, the python API does not support detached regions.
784public:
785 PyRegion(PyOperationRef parentOperation, MlirRegion region)
786 : parentOperation(std::move(parentOperation)), region(region) {
787 assert(!mlirRegionIsNull(region) && "python region cannot be null");
788 }
789 operator MlirRegion() const { return region; }
790
791 MlirRegion get() { return region; }
792 PyOperationRef &getParentOperation() { return parentOperation; }
793
794 void checkValid() { return parentOperation->checkValid(); }
795
796private:
797 PyOperationRef parentOperation;
798 MlirRegion region;
799};
800
801/// Wrapper around an MlirAsmState.
803public:
804 PyAsmState(MlirValue value, bool useLocalScope);
805 PyAsmState(PyOperationBase &operation, bool useLocalScope);
807 // Delete copy constructors.
808 PyAsmState(PyAsmState &other) = delete;
809 PyAsmState(const PyAsmState &other) = delete;
810
811 MlirAsmState get() { return state; }
812
813private:
814 MlirAsmState state;
815 MlirOpPrintingFlags flags;
816};
817
818/// Wrapper around an MlirBlock.
819/// Blocks are managed completely by their containing operation. Unlike the
820/// C++ API, the python API does not support detached blocks.
822public:
823 PyBlock(PyOperationRef parentOperation, MlirBlock block)
824 : parentOperation(std::move(parentOperation)), block(block) {
825 assert(!mlirBlockIsNull(block) && "python block cannot be null");
826 }
827
828 MlirBlock get() { return block; }
829 PyOperationRef &getParentOperation() { return parentOperation; }
830
831 void checkValid() { return parentOperation->checkValid(); }
832
833 /// Gets a capsule wrapping the void* within the MlirBlock.
834 nanobind::object getCapsule();
835
836private:
837 PyOperationRef parentOperation;
838 MlirBlock block;
839};
840
841/// An insertion point maintains a pointer to a Block and a reference operation.
842/// Calls to insert() will insert a new operation before the
843/// reference operation. If the reference operation is null, then appends to
844/// the end of the block.
846public:
847 /// Creates an insertion point positioned after the last operation in the
848 /// block, but still inside the block.
849 PyInsertionPoint(const PyBlock &block);
850 /// Creates an insertion point positioned before a reference operation.
851 PyInsertionPoint(PyOperationBase &beforeOperationBase);
852 /// Creates an insertion point positioned before a reference operation.
853 PyInsertionPoint(PyOperationRef beforeOperationRef);
854
855 /// Shortcut to create an insertion point at the beginning of the block.
857 /// Shortcut to create an insertion point before the block terminator.
859 /// Shortcut to create an insertion point to the node after the specified
860 /// operation.
862
863 /// Inserts an operation.
864 void insert(PyOperationBase &operationBase);
865
866 /// Enter and exit the context manager.
867 static nanobind::object contextEnter(nanobind::object insertionPoint);
868 void contextExit(const nanobind::object &excType,
869 const nanobind::object &excVal,
870 const nanobind::object &excTb);
871
872 PyBlock &getBlock() { return block; }
873 std::optional<PyOperationRef> &getRefOperation() { return refOperation; }
874
875private:
876 // Trampoline constructor that avoids null initializing members while
877 // looking up parents.
878 PyInsertionPoint(PyBlock block, std::optional<PyOperationRef> refOperation)
879 : refOperation(std::move(refOperation)), block(std::move(block)) {}
880
881 std::optional<PyOperationRef> refOperation;
882 PyBlock block;
883};
884
885/// Wrapper around the generic MlirType.
886/// The lifetime of a type is bound by the PyContext that created it.
888public:
889 PyType(PyMlirContextRef contextRef, MlirType type)
890 : BaseContextObject(std::move(contextRef)), type(type) {}
891 bool operator==(const PyType &other) const;
892 operator MlirType() const { return type; }
893 MlirType get() const { return type; }
894
895 /// Gets a capsule wrapping the void* within the MlirType.
896 nanobind::object getCapsule();
897
898 /// Creates a PyType from the MlirType wrapped by a capsule.
899 /// Note that PyType instances are uniqued, so the returned object
900 /// may be a pre-existing object. Ownership of the underlying MlirType
901 /// is taken by calling this function.
902 static PyType createFromCapsule(nanobind::object capsule);
903
904 nanobind::typed<nanobind::object, PyType> maybeDownCast();
905
906private:
907 MlirType type;
908};
909
910/// A TypeID provides an efficient and unique identifier for a specific C++
911/// type. This allows for a C++ type to be compared, hashed, and stored in an
912/// opaque context. This class wraps around the generic MlirTypeID.
914public:
915 PyTypeID(MlirTypeID typeID) : typeID(typeID) {}
916 // Note, this tests whether the underlying TypeIDs are the same,
917 // not whether the wrapper MlirTypeIDs are the same, nor whether
918 // the PyTypeID objects are the same (i.e., PyTypeID is a value type).
919 bool operator==(const PyTypeID &other) const;
920 operator MlirTypeID() const { return typeID; }
921 MlirTypeID get() { return typeID; }
922
923 /// Gets a capsule wrapping the void* within the MlirTypeID.
924 nanobind::object getCapsule();
925
926 /// Creates a PyTypeID from the MlirTypeID wrapped by a capsule.
927 static PyTypeID createFromCapsule(nanobind::object capsule);
928
929private:
930 MlirTypeID typeID;
931};
932
933/// CRTP base classes for Python types that subclass Type and should be
934/// castable from it (i.e. via something like IntegerType(t)).
935/// By default, type class hierarchies are one level deep (i.e. a
936/// concrete type class extends PyType); however, intermediate python-visible
937/// base classes can be modeled by specifying a BaseTy.
938template <typename DerivedTy, typename BaseTy = PyType>
940public:
941 // Derived classes must define statics for:
942 // IsAFunctionTy isaFunction
943 // const char *pyClassName
944 using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
945 using IsAFunctionTy = bool (*)(MlirType);
946 using GetTypeIDFunctionTy = MlirTypeID (*)();
948 static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
949 static inline const MlirStringRef name{};
950
951 PyConcreteType() = default;
952 PyConcreteType(PyMlirContextRef contextRef, MlirType t)
953 : BaseTy(std::move(contextRef), t) {}
956
957 static MlirType castFrom(PyType &orig) {
958 if (!DerivedTy::isaFunction(orig)) {
959 auto origRepr =
960 nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
961 throw nanobind::value_error((std::string("Cannot cast type to ") +
962 DerivedTy::pyClassName + " (from " +
963 origRepr + ")")
964 .c_str());
965 }
966 return orig;
967 }
968
969 static void bind(nanobind::module_ &m) {
970 auto cls = ClassTy(m, DerivedTy::pyClassName, nanobind::is_generic());
971 cls.def(nanobind::init<PyType &>(), nanobind::keep_alive<0, 1>(),
972 nanobind::arg("cast_from_type"));
973 cls.def_prop_ro_static("static_typeid", [](nanobind::object & /*class*/) {
974 if (DerivedTy::getTypeIdFunction)
975 return PyTypeID(DerivedTy::getTypeIdFunction());
976 throw nanobind::attribute_error(
977 (DerivedTy::pyClassName + std::string(" has no typeid.")).c_str());
978 });
979 cls.def_prop_ro("typeid", [](PyType &self) {
980 return nanobind::cast<PyTypeID>(nanobind::cast(self).attr("typeid"));
981 });
982 cls.def("__repr__", [](DerivedTy &self) {
983 PyPrintAccumulator printAccum;
984 printAccum.parts.append(DerivedTy::pyClassName);
985 printAccum.parts.append("(");
986 mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData());
987 printAccum.parts.append(")");
988 return printAccum.join();
989 });
990
991 if (DerivedTy::getTypeIdFunction) {
992 PyGlobals::get().registerTypeCaster(
993 DerivedTy::getTypeIdFunction(),
994 nanobind::cast<nanobind::callable>(nanobind::cpp_function(
995 [](PyType pyType) -> DerivedTy { return pyType; })),
996 /*replace*/ true);
997 }
998
999 if (DerivedTy::name.length != 0) {
1000 cls.def_prop_ro_static("type_name", [](nanobind::object & /*self*/) {
1001 return nanobind::str(DerivedTy::name.data, DerivedTy::name.length);
1002 });
1003 }
1004
1005 DerivedTy::bindDerived(cls);
1006 }
1007
1008 /// Implemented by derived classes to add methods to the Python subclass.
1009 static void bindDerived(ClassTy &m) {}
1010};
1011
1012/// Wrapper around the generic MlirAttribute.
1013/// The lifetime of a type is bound by the PyContext that created it.
1015public:
1016 PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
1017 : BaseContextObject(std::move(contextRef)), attr(attr) {}
1018 bool operator==(const PyAttribute &other) const;
1019 operator MlirAttribute() const { return attr; }
1020 MlirAttribute get() const { return attr; }
1021
1022 /// Gets a capsule wrapping the void* within the MlirAttribute.
1023 nanobind::object getCapsule();
1024
1025 /// Creates a PyAttribute from the MlirAttribute wrapped by a capsule.
1026 /// Note that PyAttribute instances are uniqued, so the returned object
1027 /// may be a pre-existing object. Ownership of the underlying MlirAttribute
1028 /// is taken by calling this function.
1029 static PyAttribute createFromCapsule(const nanobind::object &capsule);
1030
1031 nanobind::typed<nanobind::object, PyAttribute> maybeDownCast();
1032
1033private:
1034 MlirAttribute attr;
1035};
1036
1037/// Represents a Python MlirNamedAttr, carrying an optional owned name.
1038/// TODO: Refactor this and the C-API to be based on an Identifier owned
1039/// by the context so as to avoid ownership issues here.
1041public:
1042 /// Constructs a PyNamedAttr that retains an owned name. This should be
1043 /// used in any code that originates an MlirNamedAttribute from a python
1044 /// string.
1045 /// The lifetime of the PyNamedAttr must extend to the lifetime of the
1046 /// passed attribute.
1047 PyNamedAttribute(MlirAttribute attr, std::string ownedName);
1048
1050
1051private:
1052 // Since the MlirNamedAttr contains an internal pointer to the actual
1053 // memory of the owned string, it must be heap allocated to remain valid.
1054 // Otherwise, strings that fit within the small object optimization threshold
1055 // will have their memory address change as the containing object is moved,
1056 // resulting in an invalid aliased pointer.
1057 std::unique_ptr<std::string> ownedName;
1058};
1059
1060/// CRTP base classes for Python attributes that subclass Attribute and should
1061/// be castable from it (i.e. via something like StringAttr(attr)).
1062/// By default, attribute class hierarchies are one level deep (i.e. a
1063/// concrete attribute class extends PyAttribute); however, intermediate
1064/// python-visible base classes can be modeled by specifying a BaseTy.
1065template <typename DerivedTy, typename BaseTy = PyAttribute>
1067public:
1068 // Derived classes must define statics for:
1069 // IsAFunctionTy isaFunction
1070 // const char *pyClassName
1071 using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
1072 using IsAFunctionTy = bool (*)(MlirAttribute);
1073 using GetTypeIDFunctionTy = MlirTypeID (*)();
1074 static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
1075 static inline const MlirStringRef name{};
1077
1079 PyConcreteAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
1080 : BaseTy(std::move(contextRef), attr) {}
1083
1084 static MlirAttribute castFrom(PyAttribute &orig) {
1085 if (!DerivedTy::isaFunction(orig)) {
1086 auto origRepr =
1087 nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
1088 throw nanobind::value_error((std::string("Cannot cast attribute to ") +
1089 DerivedTy::pyClassName + " (from " +
1090 origRepr + ")")
1091 .c_str());
1092 }
1093 return orig;
1094 }
1095
1096 static void bind(nanobind::module_ &m, PyType_Slot *slots = nullptr) {
1097 ClassTy cls;
1098 if (slots) {
1099 cls = ClassTy(m, DerivedTy::pyClassName, nanobind::type_slots(slots),
1100 nanobind::is_generic());
1101 } else {
1102 cls = ClassTy(m, DerivedTy::pyClassName, nanobind::is_generic());
1103 }
1104 cls.def(nanobind::init<PyAttribute &>(), nanobind::keep_alive<0, 1>(),
1105 nanobind::arg("cast_from_attr"));
1106 cls.def_prop_ro(
1107 "type",
1108 [](PyAttribute &attr) -> nanobind::typed<nanobind::object, PyType> {
1109 return PyType(attr.getContext(), mlirAttributeGetType(attr))
1110 .maybeDownCast();
1111 });
1112 cls.def_prop_ro_static("static_typeid", [](nanobind::object & /*class*/) {
1113 if (DerivedTy::getTypeIdFunction)
1114 return PyTypeID(DerivedTy::getTypeIdFunction());
1115 throw nanobind::attribute_error(
1116 (DerivedTy::pyClassName + std::string(" has no typeid.")).c_str());
1117 });
1118 cls.def_prop_ro("typeid", [](PyAttribute &self) {
1119 return nanobind::cast<PyTypeID>(nanobind::cast(self).attr("typeid"));
1120 });
1121 cls.def("__repr__", [](DerivedTy &self) {
1122 PyPrintAccumulator printAccum;
1123 printAccum.parts.append(DerivedTy::pyClassName);
1124 printAccum.parts.append("(");
1125 mlirAttributePrint(self, printAccum.getCallback(),
1126 printAccum.getUserData());
1127 printAccum.parts.append(")");
1128 return printAccum.join();
1129 });
1130
1131 if (DerivedTy::getTypeIdFunction) {
1132 PyGlobals::get().registerTypeCaster(
1133 DerivedTy::getTypeIdFunction(),
1134 nanobind::cast<nanobind::callable>(
1135 nanobind::cpp_function([](PyAttribute pyAttribute) -> DerivedTy {
1136 return pyAttribute;
1137 })),
1138 /*replace*/ true);
1139 }
1140
1141 if (DerivedTy::name.length != 0) {
1142 cls.def_prop_ro_static("attr_name", [](nanobind::object & /*self*/) {
1143 return nanobind::str(DerivedTy::name.data, DerivedTy::name.length);
1144 });
1145 }
1146
1147 DerivedTy::bindDerived(cls);
1148 }
1149
1150 /// Implemented by derived classes to add methods to the Python subclass.
1151 static void bindDerived(ClassTy &m) {}
1152};
1153
1155 : public PyConcreteAttribute<PyStringAttribute> {
1156public:
1158 static constexpr const char *pyClassName = "StringAttr";
1163
1164 static void bindDerived(ClassTy &c);
1165};
1166
1167/// Wrapper around the generic MlirValue.
1168/// Values are managed completely by the operation that resulted in their
1169/// definition. For op result value, this is the operation that defines the
1170/// value. For block argument values, this is the operation that contains the
1171/// block to which the value is an argument (blocks cannot be detached in Python
1172/// bindings so such operation always exists).
1173class PyBlockArgument;
1174class PyOpResult;
1176public:
1177 // The virtual here is "load bearing" in that it enables RTTI
1178 // for PyConcreteValue CRTP classes that support maybeDownCast.
1179 // See PyValue::maybeDownCast.
1180 virtual ~PyValue() = default;
1181 PyValue(PyOperationRef parentOperation, MlirValue value)
1182 : parentOperation(std::move(parentOperation)), value(value) {}
1183 operator MlirValue() const { return value; }
1184
1185 MlirValue get() { return value; }
1186 PyOperationRef &getParentOperation() { return parentOperation; }
1187
1188 void checkValid() { return parentOperation->checkValid(); }
1189
1190 /// Gets a capsule wrapping the void* within the MlirValue.
1191 nanobind::object getCapsule();
1192
1193 nanobind::typed<nanobind::object,
1194 std::variant<PyBlockArgument, PyOpResult, PyValue>>
1195 maybeDownCast();
1196
1197 /// Creates a PyValue from the MlirValue wrapped by a capsule. Ownership of
1198 /// the underlying MlirValue is still tied to the owning operation.
1199 static PyValue createFromCapsule(nanobind::object capsule);
1200
1201private:
1202 PyOperationRef parentOperation;
1203 MlirValue value;
1204};
1205
1206/// Wrapper around MlirAffineExpr. Affine expressions are owned by the context.
1208public:
1209 PyAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr)
1210 : BaseContextObject(std::move(contextRef)), affineExpr(affineExpr) {}
1211 bool operator==(const PyAffineExpr &other) const;
1212 operator MlirAffineExpr() const { return affineExpr; }
1213 MlirAffineExpr get() const { return affineExpr; }
1214
1215 /// Gets a capsule wrapping the void* within the MlirAffineExpr.
1216 nanobind::object getCapsule();
1217
1218 /// Creates a PyAffineExpr from the MlirAffineExpr wrapped by a capsule.
1219 /// Note that PyAffineExpr instances are uniqued, so the returned object
1220 /// may be a pre-existing object. Ownership of the underlying MlirAffineExpr
1221 /// is taken by calling this function.
1222 static PyAffineExpr createFromCapsule(const nanobind::object &capsule);
1223
1224 PyAffineExpr add(const PyAffineExpr &other) const;
1225 PyAffineExpr mul(const PyAffineExpr &other) const;
1227 PyAffineExpr ceilDiv(const PyAffineExpr &other) const;
1228 PyAffineExpr mod(const PyAffineExpr &other) const;
1229
1230 nanobind::typed<nanobind::object, PyAffineExpr> maybeDownCast();
1231
1232private:
1233 MlirAffineExpr affineExpr;
1234};
1235
1237public:
1238 PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap)
1239 : BaseContextObject(std::move(contextRef)), affineMap(affineMap) {}
1240 bool operator==(const PyAffineMap &other) const;
1241 operator MlirAffineMap() const { return affineMap; }
1242 MlirAffineMap get() const { return affineMap; }
1243
1244 /// Gets a capsule wrapping the void* within the MlirAffineMap.
1245 nanobind::object getCapsule();
1246
1247 /// Creates a PyAffineMap from the MlirAffineMap wrapped by a capsule.
1248 /// Note that PyAffineMap instances are uniqued, so the returned object
1249 /// may be a pre-existing object. Ownership of the underlying MlirAffineMap
1250 /// is taken by calling this function.
1251 static PyAffineMap createFromCapsule(const nanobind::object &capsule);
1252
1253private:
1254 MlirAffineMap affineMap;
1255};
1256
1258public:
1259 PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet)
1260 : BaseContextObject(std::move(contextRef)), integerSet(integerSet) {}
1261 bool operator==(const PyIntegerSet &other) const;
1262 operator MlirIntegerSet() const { return integerSet; }
1263 MlirIntegerSet get() const { return integerSet; }
1264
1265 /// Gets a capsule wrapping the void* within the MlirIntegerSet.
1266 nanobind::object getCapsule();
1267
1268 /// Creates a PyIntegerSet from the MlirAffineMap wrapped by a capsule.
1269 /// Note that PyIntegerSet instances may be uniqued, so the returned object
1270 /// may be a pre-existing object. Integer sets are owned by the context.
1271 static PyIntegerSet createFromCapsule(const nanobind::object &capsule);
1272
1273private:
1274 MlirIntegerSet integerSet;
1275};
1276
1277/// Bindings for MLIR symbol tables.
1279public:
1280 /// Constructs a symbol table for the given operation.
1281 explicit PySymbolTable(PyOperationBase &operation);
1282
1283 /// Destroys the symbol table.
1285
1286 /// Returns the symbol (opview) with the given name, throws if there is no
1287 /// such symbol in the table.
1288 nanobind::object dunderGetItem(const std::string &name);
1289
1290 /// Removes the given operation from the symbol table and erases it.
1291 void erase(PyOperationBase &symbol);
1292
1293 /// Removes the operation with the given name from the symbol table and erases
1294 /// it, throws if there is no such symbol in the table.
1295 void dunderDel(const std::string &name);
1296
1297 /// Inserts the given operation into the symbol table. The operation must have
1298 /// the symbol trait.
1299 PyStringAttribute insert(PyOperationBase &symbol);
1300
1301 /// Gets and sets the name of a symbol op.
1302 static PyStringAttribute getSymbolName(PyOperationBase &symbol);
1303 static void setSymbolName(PyOperationBase &symbol, const std::string &name);
1304
1305 /// Gets and sets the visibility of a symbol op.
1306 static PyStringAttribute getVisibility(PyOperationBase &symbol);
1307 static void setVisibility(PyOperationBase &symbol,
1308 const std::string &visibility);
1309
1310 /// Replaces all symbol uses within an operation. See the API
1311 /// mlirSymbolTableReplaceAllSymbolUses for all caveats.
1312 static void replaceAllSymbolUses(const std::string &oldSymbol,
1313 const std::string &newSymbol,
1314 PyOperationBase &from);
1315
1316 /// Walks all symbol tables under and including 'from'.
1317 static void walkSymbolTables(PyOperationBase &from, bool allSymUsesVisible,
1318 nanobind::object callback);
1319
1320 /// Casts the bindings class into the C API structure.
1321 operator MlirSymbolTable() { return symbolTable; }
1322
1323private:
1324 PyOperationRef operation;
1325 MlirSymbolTable symbolTable;
1326};
1327
1328/// Custom exception that allows access to error diagnostic information. This is
1329/// translated to the `ir.MLIRError` python exception when thrown.
1330struct MLIR_PYTHON_API_EXPORTED MLIRError : std::exception {
1331 MLIRError(std::string message,
1332 std::vector<PyDiagnostic::DiagnosticInfo> &&errorDiagnostics = {})
1333 : message(std::move(message)),
1334 errorDiagnostics(std::move(errorDiagnostics)) {}
1335 const char *what() const noexcept override { return message.c_str(); }
1336
1337 /// Bind the MLIRError exception class to the given module.
1338 static void bind(nanobind::module_ &m);
1339
1340 std::string message;
1341 std::vector<PyDiagnostic::DiagnosticInfo> errorDiagnostics;
1342};
1343
1344//------------------------------------------------------------------------------
1345// Utilities.
1346//------------------------------------------------------------------------------
1347
1348inline MlirStringRef toMlirStringRef(const std::string &s) {
1349 return mlirStringRefCreate(s.data(), s.size());
1350}
1351
1352inline MlirStringRef toMlirStringRef(std::string_view s) {
1353 return mlirStringRefCreate(s.data(), s.size());
1354}
1355
1356inline MlirStringRef toMlirStringRef(const nanobind::bytes &s) {
1357 return mlirStringRefCreate(static_cast<const char *>(s.data()), s.size());
1358}
1359
1360/// Create a block, using the current location context if no locations are
1361/// specified.
1363createBlock(const nanobind::typed<nanobind::sequence, PyType> &pyArgTypes,
1364 const std::optional<nanobind::typed<nanobind::sequence, PyLocation>>
1365 &pyArgLocs);
1366
1368 static bool dunderContains(const std::string &attributeKind);
1369 static nanobind::callable
1370 dunderGetItemNamed(const std::string &attributeKind);
1371 static void dunderSetItemNamed(const std::string &attributeKind,
1372 nanobind::callable func, bool replace,
1373 bool allow_existing);
1374
1375 static void bind(nanobind::module_ &m);
1376};
1377
1378//------------------------------------------------------------------------------
1379// Collections.
1380//------------------------------------------------------------------------------
1381
1382/// Regions of an op are fixed length and indexed numerically so are represented
1383/// with a sequence-like container.
1385 : public Sliceable<PyRegionList, PyRegion> {
1386public:
1387 static constexpr const char *pyClassName = "RegionSequence";
1388
1390 intptr_t length = -1, intptr_t step = 1);
1391
1392private:
1393 /// Give the parent CRTP class access to hook implementations below.
1394 friend class Sliceable<PyRegionList, PyRegion>;
1395
1396 intptr_t getRawNumElements();
1397
1398 PyRegion getRawElement(intptr_t pos);
1399
1401
1402 PyOperationRef operation;
1403};
1404
1406public:
1407 PyBlockIterator(PyOperationRef operation, MlirBlock next)
1408 : operation(std::move(operation)), next(next) {}
1409
1410 PyBlockIterator &dunderIter() { return *this; }
1411
1412 nanobind::typed<nanobind::object, PyBlock> dunderNext();
1413
1414 static void bind(nanobind::module_ &m);
1415
1416private:
1417 PyOperationRef operation;
1418 MlirBlock next;
1419};
1420
1421/// Blocks are exposed by the C-API as a forward-only linked list. In Python,
1422/// we present them as a more full-featured list-like container but optimize
1423/// it for forward iteration. Blocks are always owned by a region.
1425public:
1426 PyBlockList(PyOperationRef operation, MlirRegion region)
1427 : operation(std::move(operation)), region(region) {}
1428
1429 PyBlockIterator dunderIter();
1430
1431 intptr_t dunderLen();
1432
1433 PyBlock dunderGetItem(intptr_t index);
1434
1435 PyBlock appendBlock(const nanobind::args &pyArgTypes,
1436 const std::optional<nanobind::sequence> &pyArgLocs);
1437
1438 static void bind(nanobind::module_ &m);
1439
1440private:
1441 PyOperationRef operation;
1442 MlirRegion region;
1443};
1444
1446public:
1447 PyOperationIterator(PyOperationRef parentOperation, MlirOperation next)
1448 : parentOperation(std::move(parentOperation)), next(next) {}
1449
1450 PyOperationIterator &dunderIter() { return *this; }
1451
1452 nanobind::typed<nanobind::object, PyOpView> dunderNext();
1453
1454 static void bind(nanobind::module_ &m);
1455
1456private:
1457 PyOperationRef parentOperation;
1458 MlirOperation next;
1459};
1460
1461/// Operations are exposed by the C-API as a forward-only linked list. In
1462/// Python, we present them as a more full-featured list-like container but
1463/// optimize it for forward iteration. Iterable operations are always owned
1464/// by a block.
1466public:
1467 PyOperationList(PyOperationRef parentOperation, MlirBlock block)
1468 : parentOperation(std::move(parentOperation)), block(block) {}
1469
1470 PyOperationIterator dunderIter();
1471
1472 intptr_t dunderLen();
1473
1474 nanobind::typed<nanobind::object, PyOpView> dunderGetItem(intptr_t index);
1475
1476 static void bind(nanobind::module_ &m);
1477
1478private:
1479 PyOperationRef parentOperation;
1480 MlirBlock block;
1481};
1482
1484public:
1485 PyOpOperand(MlirOpOperand opOperand) : opOperand(opOperand) {}
1486 operator MlirOpOperand() const { return opOperand; }
1487
1488 nanobind::typed<nanobind::object, PyOpView> getOwner() const;
1489
1490 size_t getOperandNumber() const;
1491
1492 static void bind(nanobind::module_ &m);
1493
1494private:
1495 MlirOpOperand opOperand;
1496};
1497
1499public:
1500 PyOpOperandIterator(MlirOpOperand opOperand) : opOperand(opOperand) {}
1501
1502 PyOpOperandIterator &dunderIter() { return *this; }
1503
1504 nanobind::typed<nanobind::object, PyOpOperand> dunderNext();
1505
1506 static void bind(nanobind::module_ &m);
1507
1508private:
1509 MlirOpOperand opOperand;
1510};
1511
1512/// CRTP base class for Python MLIR values that subclass Value and should be
1513/// castable from it. The value hierarchy is one level deep and is not supposed
1514/// to accommodate other levels unless core MLIR changes.
1515template <typename DerivedTy>
1517public:
1518 // Derived classes must define statics for:
1519 // IsAFunctionTy isaFunction
1520 // const char *pyClassName
1521 // and redefine bindDerived.
1522 using ClassTy = nanobind::class_<DerivedTy, PyValue>;
1523 using IsAFunctionTy = bool (*)(MlirValue);
1524 using GetTypeIDFunctionTy = MlirTypeID (*)();
1525 static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
1527
1528 PyConcreteValue() = default;
1529 PyConcreteValue(PyOperationRef operationRef, MlirValue value)
1530 : PyValue(operationRef, value) {}
1533
1534 /// Attempts to cast the original value to the derived type and throws on
1535 /// type mismatches.
1536 static MlirValue castFrom(PyValue &orig) {
1537 if (!DerivedTy::isaFunction(orig.get())) {
1538 auto origRepr =
1539 nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
1540 throw nanobind::value_error((std::string("Cannot cast value to ") +
1541 DerivedTy::pyClassName + " (from " +
1542 origRepr + ")")
1543 .c_str());
1544 }
1545 return orig.get();
1546 }
1547
1548 /// Binds the Python module objects to functions of this class.
1549 static void bind(nanobind::module_ &m) {
1550 auto cls = ClassTy(m, DerivedTy::pyClassName, nanobind::is_generic(),
1551 nanobind::sig((std::string("class ") +
1552 DerivedTy::pyClassName + "(Value[_T])")
1553 .c_str()));
1554 cls.def(nanobind::init<PyValue &>(), nanobind::keep_alive<0, 1>(),
1555 nanobind::arg("value"));
1556 cls.def(
1558 [](DerivedTy &self) -> nanobind::typed<nanobind::object, DerivedTy> {
1559 return self.maybeDownCast();
1560 });
1561 cls.def("__str__", [](PyValue &self) {
1562 PyPrintAccumulator printAccum;
1563 printAccum.parts.append(std::string(DerivedTy::pyClassName) + "(");
1564 mlirValuePrint(self.get(), printAccum.getCallback(),
1565 printAccum.getUserData());
1566 printAccum.parts.append(")");
1567 return printAccum.join();
1568 });
1569
1570 if (DerivedTy::getTypeIdFunction) {
1571 PyGlobals::get().registerValueCaster(
1572 DerivedTy::getTypeIdFunction(),
1573 nanobind::cast<nanobind::callable>(nanobind::cpp_function(
1574 [](PyValue pyValue) -> DerivedTy { return pyValue; })),
1575 /*replace*/ true);
1576 }
1577
1578 DerivedTy::bindDerived(cls);
1579 }
1580
1581 /// Implemented by derived classes to add methods to the Python subclass.
1582 static void bindDerived(ClassTy &m) {}
1583};
1584
1585/// Python wrapper for MlirOpResult.
1587public:
1589 static constexpr const char *pyClassName = "OpResult";
1591
1592 static void bindDerived(ClassTy &c);
1593};
1594
1595/// A list of operation results. Internally, these are stored as consecutive
1596/// elements, random access is cheap. The (returned) result list is associated
1597/// with the operation whose results these are, and thus extends the lifetime of
1598/// this operation.
1600 : public Sliceable<PyOpResultList, PyOpResult> {
1601public:
1602 static constexpr const char *pyClassName = "OpResultList";
1603 static constexpr std::array<const char *, 1> typeParams = {"_T"};
1605
1607 intptr_t length = -1, intptr_t step = 1);
1608
1609 static void bindDerived(ClassTy &c);
1610
1611 PyOperationRef &getOperation() { return operation; }
1612
1613private:
1614 /// Give the parent CRTP class access to hook implementations below.
1615 friend class Sliceable<PyOpResultList, PyOpResult>;
1616
1617 intptr_t getRawNumElements();
1618
1619 PyOpResult getRawElement(intptr_t index);
1620
1621 PyOpResultList slice(intptr_t startIndex, intptr_t length,
1622 intptr_t step) const;
1623
1624 PyOperationRef operation;
1625};
1626
1627/// Python wrapper for MlirBlockArgument.
1629 : public PyConcreteValue<PyBlockArgument> {
1630public:
1632 static constexpr const char *pyClassName = "BlockArgument";
1634
1635 static void bindDerived(ClassTy &c);
1636};
1637
1638/// A list of block arguments. Internally, these are stored as consecutive
1639/// elements, random access is cheap. The argument list is associated with the
1640/// operation that contains the block (detached blocks are not allowed in
1641/// Python bindings) and extends its lifetime.
1643 : public Sliceable<PyBlockArgumentList, PyBlockArgument> {
1644public:
1645 static constexpr const char *pyClassName = "BlockArgumentList";
1647
1648 PyBlockArgumentList(PyOperationRef operation, MlirBlock block,
1650 intptr_t step = 1);
1651
1652 static void bindDerived(ClassTy &c);
1653
1654private:
1655 /// Give the parent CRTP class access to hook implementations below.
1657
1658 /// Returns the number of arguments in the list.
1659 intptr_t getRawNumElements();
1660
1661 /// Returns `pos`-the element in the list.
1662 PyBlockArgument getRawElement(intptr_t pos) const;
1663
1664 /// Returns a sublist of this list.
1666 intptr_t step) const;
1667
1668 PyOperationRef operation;
1669 MlirBlock block;
1670};
1671
1672/// A list of operation operands. Internally, these are stored as consecutive
1673/// elements, random access is cheap. The (returned) operand list is associated
1674/// with the operation whose operands these are, and thus extends the lifetime
1675/// of this operation.
1677 : public Sliceable<PyOpOperandList, PyValue> {
1678public:
1679 static constexpr const char *pyClassName = "OpOperandList";
1680 static constexpr std::array<const char *, 1> typeParams = {"_T"};
1682
1684 intptr_t length = -1, intptr_t step = 1);
1685
1686 void dunderSetItem(intptr_t index, PyValue value);
1687
1688 static void bindDerived(ClassTy &c);
1689
1690private:
1691 /// Give the parent CRTP class access to hook implementations below.
1692 friend class Sliceable<PyOpOperandList, PyValue>;
1693
1694 intptr_t getRawNumElements();
1695
1696 PyValue getRawElement(intptr_t pos);
1697
1699 intptr_t step) const;
1700
1701 PyOperationRef operation;
1702};
1703
1704/// A list of operation successors. Internally, these are stored as consecutive
1705/// elements, random access is cheap. The (returned) successor list is
1706/// associated with the operation whose successors these are, and thus extends
1707/// the lifetime of this operation.
1709 : public Sliceable<PyOpSuccessors, PyBlock> {
1710public:
1711 static constexpr const char *pyClassName = "OpSuccessors";
1712
1714 intptr_t length = -1, intptr_t step = 1);
1715
1716 void dunderSetItem(intptr_t index, PyBlock block);
1717
1718 static void bindDerived(ClassTy &c);
1719
1720private:
1721 /// Give the parent CRTP class access to hook implementations below.
1722 friend class Sliceable<PyOpSuccessors, PyBlock>;
1723
1724 intptr_t getRawNumElements();
1725
1726 PyBlock getRawElement(intptr_t pos);
1727
1729 intptr_t step) const;
1730
1731 PyOperationRef operation;
1732};
1733
1734/// A list of block successors. Internally, these are stored as consecutive
1735/// elements, random access is cheap. The (returned) successor list is
1736/// associated with the operation and block whose successors these are, and thus
1737/// extends the lifetime of this operation and block.
1739 : public Sliceable<PyBlockSuccessors, PyBlock> {
1740public:
1741 static constexpr const char *pyClassName = "BlockSuccessors";
1742
1745 intptr_t step = 1);
1746
1747private:
1748 /// Give the parent CRTP class access to hook implementations below.
1749 friend class Sliceable<PyBlockSuccessors, PyBlock>;
1750
1751 intptr_t getRawNumElements();
1752
1753 PyBlock getRawElement(intptr_t pos);
1754
1756 intptr_t step) const;
1757
1758 PyOperationRef operation;
1759 PyBlock block;
1760};
1761
1762/// A list of block predecessors. The (returned) predecessor list is
1763/// associated with the operation and block whose predecessors these are, and
1764/// thus extends the lifetime of this operation and block.
1765///
1766/// WARNING: This Sliceable is more expensive than the others here because
1767/// mlirBlockGetPredecessor actually iterates the use-def chain (of block
1768/// operands) anew for each indexed access.
1770 : public Sliceable<PyBlockPredecessors, PyBlock> {
1771public:
1772 static constexpr const char *pyClassName = "BlockPredecessors";
1773
1776 intptr_t step = 1);
1777
1778private:
1779 /// Give the parent CRTP class access to hook implementations below.
1780 friend class Sliceable<PyBlockPredecessors, PyBlock>;
1781
1782 intptr_t getRawNumElements();
1783
1784 PyBlock getRawElement(intptr_t pos);
1785
1787 intptr_t step) const;
1788
1789 PyOperationRef operation;
1790 PyBlock block;
1791};
1792
1793/// A list of operation attributes. Can be indexed by name, producing
1794/// attributes, or by index, producing named attributes.
1796public:
1798 : operation(std::move(operation)) {}
1799
1800 nanobind::typed<nanobind::object, PyAttribute>
1801 dunderGetItemNamed(const std::string &name);
1802
1803 PyNamedAttribute dunderGetItemIndexed(intptr_t index);
1804
1805 nanobind::typed<nanobind::object, std::optional<PyAttribute>>
1806 get(const std::string &key, nanobind::object defaultValue);
1807
1808 void dunderSetItem(const std::string &name, const PyAttribute &attr);
1809
1810 void dunderDelItem(const std::string &name);
1811
1812 intptr_t dunderLen();
1813
1814 bool dunderContains(const std::string &name);
1815
1816 static void forEachAttr(MlirOperation op,
1817 std::function<void(MlirStringRef, MlirAttribute)> fn);
1818
1819 static void bind(nanobind::module_ &m);
1820
1821private:
1822 PyOperationRef operation;
1823};
1824
1825/// Base class of operation adaptors.
1827public:
1828 PyOpAdaptor(nanobind::list operands, PyOpAttributeMap attributes)
1829 : operands(std::move(operands)), attributes(std::move(attributes)) {}
1830 PyOpAdaptor(nanobind::list operands, PyOpView &opView)
1831 : operands(std::move(operands)),
1832 attributes(opView.getOperation().getRef()) {}
1833
1834 static void bind(nanobind::module_ &m);
1835
1836private:
1837 nanobind::list operands;
1838 PyOpAttributeMap attributes;
1839};
1840
1842public:
1843 static bool attach(const nanobind::object &opName,
1844 const nanobind::object &target, PyMlirContext &context);
1845
1846 static void bind(nanobind::module_ &m);
1847
1848 static inline const char *typeIDAttr = "_trait_typeid";
1849};
1850
1852
1854public:
1855 static bool attach(const nanobind::object &opName, PyMlirContext &context);
1856 static void bind(nanobind::module_ &m);
1857};
1858
1860public:
1861 static bool attach(const nanobind::object &opName, PyMlirContext &context);
1862 static void bind(nanobind::module_ &m);
1863};
1864
1865} // namespace PyDynamicOpTraits
1866
1867MLIR_PYTHON_API_EXPORTED MlirValue getUniqueResult(MlirOperation operation);
1868MLIR_PYTHON_API_EXPORTED void populateIRCore(nanobind::module_ &m);
1869MLIR_PYTHON_API_EXPORTED void populateRoot(nanobind::module_ &m);
1870
1871/// Helper for creating an @classmethod.
1872template <class Func, typename... Args>
1873inline nanobind::object classmethod(Func f, Args... args) {
1874 nanobind::object cf = nanobind::cpp_function(f, args...);
1875 static SafeInit<nanobind::object> classmethodFn([]() {
1876 return std::make_unique<nanobind::object>(
1877 nanobind::module_::import_("builtins").attr("classmethod"));
1878 });
1879 return classmethodFn.get()(cf);
1880}
1881
1882} // namespace MLIR_BINDINGS_PYTHON_DOMAIN
1883} // namespace python
1884} // namespace mlir
1885
1886namespace nanobind {
1887namespace detail {
1888template <>
1889struct type_caster<
1890 mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::DefaultingPyMlirContext>
1892 mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::DefaultingPyMlirContext> {
1893};
1894template <>
1895struct type_caster<
1896 mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::DefaultingPyLocation>
1898 mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::DefaultingPyLocation> {};
1899
1900} // namespace detail
1901} // namespace nanobind
1902
1903#endif // MLIR_BINDINGS_PYTHON_IRCORE_H
MLIR_FLOAT16_EXPORT bool operator==(const f16 &f1, const f16 &f2)
bool mlirValueIsABlockArgument(MlirValue value)
Definition IR.cpp:1125
MlirType mlirAttributeGetType(MlirAttribute attribute)
Definition IR.cpp:1294
bool mlirValueIsAOpResult(MlirValue value)
Definition IR.cpp:1129
void mlirOpPrintingFlagsDestroy(MlirOpPrintingFlags flags)
Definition IR.cpp:205
void mlirTypePrint(MlirType type, MlirStringCallback callback, void *userData)
Definition IR.cpp:1275
#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
b getContext())
static std::string diag(const llvm::Value &value)
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static sycl::context getDefaultContext()
A CRTP base class for pseudo-containers willing to support Python-type slicing access on top of index...
nanobind::class_< PyOpResultList > ClassTy
Sliceable(intptr_t startIndex, intptr_t length, intptr_t step)
Defaulting()=default
Type casters require the type to be default constructible, but using such an instance is illegal.
PyMlirContextRef & getContext()
Accesses the context reference.
Definition IRCore.h:310
Used in function arguments when None should resolve to the current context manager set instance.
Definition IRCore.h:537
Defaulting()=default
Type casters require the type to be default constructible, but using such an instance is illegal.
Used in function arguments when None should resolve to the current context manager set instance.
Definition IRCore.h:291
Defaulting()=default
Type casters require the type to be default constructible, but using such an instance is illegal.
Wrapper around MlirAffineExpr. Affine expressions are owned by the context.
Definition IRCore.h:1207
PyAffineExpr ceilDiv(const PyAffineExpr &other) const
PyAffineExpr floorDiv(const PyAffineExpr &other) const
PyAffineExpr add(const PyAffineExpr &other) const
PyAffineExpr mod(const PyAffineExpr &other) const
PyAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr)
Definition IRCore.h:1209
nanobind::typed< nanobind::object, PyAffineExpr > maybeDownCast()
Definition IRAffine.cpp:368
PyAffineExpr mul(const PyAffineExpr &other) const
PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap)
Definition IRCore.h:1238
PyAsmState(MlirValue value, bool useLocalScope)
Definition IRCore.cpp:1749
Wrapper around the generic MlirAttribute.
Definition IRCore.h:1014
PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
Definition IRCore.h:1016
Sliceable< PyBlockArgumentList, PyBlockArgument > SliceableT
Definition IRCore.h:1646
PyBlockArgumentList(PyOperationRef operation, MlirBlock block, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2188
Python wrapper for MlirBlockArgument.
Definition IRCore.h:1629
PyBlockIterator(PyOperationRef operation, MlirBlock next)
Definition IRCore.h:1407
PyBlockList(PyOperationRef operation, MlirRegion region)
Definition IRCore.h:1426
PyBlockPredecessors(PyBlock block, PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2348
PyBlockSuccessors(PyBlock block, PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2325
PyBlock(PyOperationRef parentOperation, MlirBlock block)
Definition IRCore.h:823
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition IRCore.h:1074
static void bindDerived(ClassTy &m)
Implemented by derived classes to add methods to the Python subclass.
Definition IRCore.h:1151
PyConcreteAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
Definition IRCore.h:1079
static void bind(nanobind::module_ &m, PyType_Slot *slots=nullptr)
Definition IRCore.h:1096
nanobind::class_< DerivedTy, BaseTy > ClassTy
Definition IRCore.h:1071
static MlirAttribute castFrom(PyAttribute &orig)
Definition IRCore.h:1084
nanobind::class_< DerivedTy, BaseTy > ClassTy
Definition IRCore.h:944
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition IRCore.h:948
PyConcreteType(PyMlirContextRef contextRef, MlirType t)
Definition IRCore.h:952
static void bindDerived(ClassTy &m)
Implemented by derived classes to add methods to the Python subclass.
Definition IRCore.h:1009
PyConcreteValue(PyOperationRef operationRef, MlirValue value)
Definition IRCore.h:1529
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition IRCore.h:1525
static void bind(nanobind::module_ &m)
Binds the Python module objects to functions of this class.
Definition IRCore.h:1549
nanobind::class_< DerivedTy, PyValue > ClassTy
Definition IRCore.h:1522
static MlirValue castFrom(PyValue &orig)
Attempts to cast the original value to the derived type and throws on type mismatches.
Definition IRCore.h:1536
static void bindDerived(ClassTy &m)
Implemented by derived classes to add methods to the Python subclass.
Definition IRCore.h:1582
Represents a diagnostic handler attached to the context.
Definition IRCore.h:418
void detach()
Detaches the handler. Does nothing if not attached.
Definition IRCore.cpp:727
PyDiagnosticHandler(MlirContext context, nanobind::object callback)
Definition IRCore.cpp:721
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition IRCore.h:430
Python class mirroring the C MlirDiagnostic struct.
Definition IRCore.h:368
PyDialectDescriptor(PyMlirContextRef contextRef, MlirDialect dialect)
Definition IRCore.h:475
Wrapper around an MlirDialectRegistry.
Definition IRCore.h:510
PyDialectRegistry(PyDialectRegistry &&other) noexcept
Definition IRCore.h:519
static bool attach(const nanobind::object &opName, const nanobind::object &target, PyMlirContext &context)
Definition IRCore.cpp:2553
static bool attach(const nanobind::object &opName, PyMlirContext &context)
Definition IRCore.cpp:2605
static bool attach(const nanobind::object &opName, PyMlirContext &context)
Definition IRCore.cpp:2624
static PyGlobals & get()
Most code should get the globals via this static accessor.
Definition Globals.cpp:59
An insertion point maintains a pointer to a Block and a reference operation.
Definition IRCore.h:845
void insert(PyOperationBase &operationBase)
Inserts an operation.
Definition IRCore.cpp:1780
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition IRCore.cpp:1845
static PyInsertionPoint atBlockTerminator(PyBlock &block)
Shortcut to create an insertion point before the block terminator.
Definition IRCore.cpp:1819
static PyInsertionPoint after(PyOperationBase &op)
Shortcut to create an insertion point to the node after the specified operation.
Definition IRCore.cpp:1828
std::optional< PyOperationRef > & getRefOperation()
Definition IRCore.h:873
static PyInsertionPoint atBlockBegin(PyBlock &block)
Shortcut to create an insertion point at the beginning of the block.
Definition IRCore.cpp:1806
PyInsertionPoint(const PyBlock &block)
Creates an insertion point positioned after the last operation in the block, but still inside the blo...
Definition IRCore.cpp:1771
static nanobind::object contextEnter(nanobind::object insertionPoint)
Enter and exit the context manager.
Definition IRCore.cpp:1841
PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet)
Definition IRCore.h:1259
PyLocation(PyMlirContextRef contextRef, MlirLocation loc)
Definition IRCore.h:319
static PyMlirContextRef forContext(MlirContext context)
Returns a context reference for the singleton PyMlirContext wrapper for the given context.
Definition IRCore.cpp:460
MlirContext get()
Accesses the underlying MlirContext.
Definition IRCore.h:224
void setEmitErrorDiagnostics(bool value)
Controls whether error diagnostics should be propagated to diagnostic handlers, instead of being capt...
Definition IRCore.h:258
PyModuleRef getRef()
Gets a strong reference to this module.
Definition IRCore.h:563
MlirModule get()
Gets the backing MlirModule.
Definition IRCore.h:560
static PyModuleRef forModule(MlirModule module)
Returns a PyModule reference for the given MlirModule.
Definition IRCore.cpp:872
Represents a Python MlirNamedAttr, carrying an optional owned name.
Definition IRCore.h:1040
PyNamedAttribute(MlirAttribute attr, std::string ownedName)
Constructs a PyNamedAttr that retains an owned name.
Definition IRCore.cpp:1889
Template for a reference to a concrete type which captures a python reference to its underlying pytho...
Definition IRCore.h:66
nanobind::typed< nanobind::object, T > NBTypedT
Definition IRCore.h:122
PyObjectRef & operator=(const PyObjectRef &other)
Definition IRCore.h:81
PyObjectRef(PyObjectRef &&other) noexcept
Definition IRCore.h:74
nanobind::object releaseObject()
Releases the object held by this instance, returning it.
Definition IRCore.h:104
PyObjectRef(T *referrent, nanobind::object object)
Definition IRCore.h:68
PyObjectRef & operator=(PyObjectRef &&other) noexcept
Definition IRCore.h:86
PyOpAdaptor(nanobind::list operands, PyOpAttributeMap attributes)
Definition IRCore.h:1828
PyOpAdaptor(nanobind::list operands, PyOpView &opView)
Definition IRCore.h:1830
Sliceable< PyOpOperandList, PyValue > SliceableT
Definition IRCore.h:1681
static constexpr std::array< const char *, 1 > typeParams
Definition IRCore.h:1680
PyOpOperandList(PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2220
void dunderSetItem(intptr_t index, PyValue value)
Definition IRCore.cpp:2228
Sliceable< PyOpResultList, PyOpResult > SliceableT
Definition IRCore.h:1604
static constexpr std::array< const char *, 1 > typeParams
Definition IRCore.h:1603
PyOpResultList(PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:1399
static constexpr IsAFunctionTy isaFunction
Definition IRCore.h:1588
PyOpSuccessors(PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2292
void dunderSetItem(intptr_t index, PyBlock block)
Definition IRCore.cpp:2300
A PyOpView is equivalent to the C++ "Op" wrappers: these are the basis for providing more instance-sp...
Definition IRCore.h:747
PyOpView(const nanobind::object &operationObject)
Definition IRCore.cpp:1739
PyOperation & getOperation() override
Each must provide access to the raw Operation.
Definition IRCore.h:750
Base class for PyOperation and PyOpView which exposes the primary, user visible methods for manipulat...
Definition IRCore.h:590
bool isBeforeInBlock(PyOperationBase &other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
Definition IRCore.cpp:1163
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:1117
void writeBytecode(const nanobind::object &fileObject, std::optional< int64_t > bytecodeVersion)
Definition IRCore.cpp:1064
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:1145
void walk(std::function< PyWalkResult(MlirOperation)> callback, PyWalkOrder walkOrder)
Definition IRCore.cpp:1085
PyOperationIterator(PyOperationRef parentOperation, MlirOperation next)
Definition IRCore.h:1447
PyOperationList(PyOperationRef parentOperation, MlirBlock block)
Definition IRCore.h:1467
void setInvalid()
Invalidate the operation.
Definition IRCore.h:714
PyOperation & getOperation() override
Each must provide access to the raw Operation.
Definition IRCore.h:647
PyOperation(PyMlirContextRef contextRef, MlirOperation operation)
Definition IRCore.cpp:912
PyRegionList(PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:193
PyRegion(PyOperationRef parentOperation, MlirRegion region)
Definition IRCore.h:785
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition IRCore.h:1160
PySymbolTable(PyOperationBase &operation)
Constructs a symbol table for the given operation.
Definition IRCore.cpp:2005
Tracks an entry in the thread context stack.
Definition IRCore.h:137
PyThreadContextEntry(FrameKind frameKind, nanobind::object context, nanobind::object insertionPoint, nanobind::object location)
Definition IRCore.h:145
A TypeID provides an efficient and unique identifier for a specific C++ type.
Definition IRCore.h:913
Wrapper around the generic MlirType.
Definition IRCore.h:887
PyType(PyMlirContextRef contextRef, MlirType type)
Definition IRCore.h:889
nanobind::typed< nanobind::object, PyType > maybeDownCast()
Definition IRCore.cpp:1917
PyValue(PyOperationRef parentOperation, MlirValue value)
Definition IRCore.h:1181
Safely calls Python initialization code on first use, avoiding deadlocks.
MlirDiagnosticSeverity
Severity of a diagnostic.
Definition Diagnostics.h:32
@ MlirDiagnosticNote
Definition Diagnostics.h:35
@ MlirDiagnosticRemark
Definition Diagnostics.h:36
@ MlirDiagnosticWarning
Definition Diagnostics.h:34
@ MlirDiagnosticError
Definition Diagnostics.h:33
MLIR_CAPI_EXPORTED MlirDiagnosticHandlerID mlirContextAttachDiagnosticHandler(MlirContext context, MlirDiagnosticHandler handler, void *userData, void(*deleteUserData)(void *))
Attaches the diagnostic handler to the context.
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 MlirTypeID mlirStringAttrGetTypeID(void)
Returns the typeID of a String attribute.
MLIR_CAPI_EXPORTED bool mlirAttributeIsAString(MlirAttribute attr)
Checks whether the given attribute is a string attribute.
MLIR_CAPI_EXPORTED MlirStringRef mlirStringAttrGetName(void)
@ MlirWalkPreOrder
Definition IR.h:854
@ MlirWalkPostOrder
Definition IR.h:855
MLIR_CAPI_EXPORTED void mlirDialectRegistryDestroy(MlirDialectRegistry registry)
Takes a dialect registry owned by the caller and destroys it.
Definition IR.cpp:148
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:1313
@ MlirWalkResultInterrupt
Definition IR.h:848
@ MlirWalkResultSkip
Definition IR.h:849
@ MlirWalkResultAdvance
Definition IR.h:847
static bool mlirBlockIsNull(MlirBlock block)
Checks whether a block is null.
Definition IR.h:946
MLIR_CAPI_EXPORTED void mlirSymbolTableDestroy(MlirSymbolTable symbolTable)
Destroys the symbol table created with mlirSymbolTableCreate.
Definition IR.cpp:1364
static bool mlirDialectRegistryIsNull(MlirDialectRegistry registry)
Checks if the dialect registry is null.
Definition IR.h:244
static bool mlirRegionIsNull(MlirRegion region)
Checks whether a region is null.
Definition IR.h:885
MLIR_CAPI_EXPORTED MlirDialectRegistry mlirDialectRegistryCreate(void)
Creates a dialect registry and transfers its ownership to the caller.
Definition IR.cpp:144
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:1171
static MlirStringRef mlirStringRefCreate(const char *str, size_t length)
Constructs a string reference from the pointer and length.
Definition Support.h:87
#define MLIR_PYTHON_API_EXPORTED
Definition Support.h:49
MLIR_PYTHON_API_EXPORTED MlirValue getUniqueResult(MlirOperation operation)
Definition IRCore.cpp:1528
MLIR_PYTHON_API_EXPORTED void populateRoot(nanobind::module_ &m)
PyObjectRef< PyMlirContext > PyMlirContextRef
Wrapper around MlirContext.
Definition IRCore.h:210
PyObjectRef< PyOperation > PyOperationRef
Definition IRCore.h:642
MlirStringRef toMlirStringRef(const std::string &s)
Definition IRCore.h:1348
PyObjectRef< PyModule > PyModuleRef
Definition IRCore.h:549
MlirBlock MLIR_PYTHON_API_EXPORTED createBlock(const nanobind::typed< nanobind::sequence, PyType > &pyArgTypes, const std::optional< nanobind::typed< nanobind::sequence, PyLocation > > &pyArgLocs)
Create a block, using the current location context if no locations are specified.
PyWalkOrder
Traversal order for operation walk.
Definition IRCore.h:359
MLIR_PYTHON_API_EXPORTED void populateIRCore(nanobind::module_ &m)
nanobind::object classmethod(Func f, Args... args)
Helper for creating an @classmethod.
Definition IRCore.h:1873
Include the generated interface declarations.
Operation * clone(OpBuilder &b, Operation *op, TypeRange newResultTypes, ValueRange newOperands)
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:121
Named MLIR attribute.
Definition IR.h:76
A pointer to a sized fragment of a string, not necessarily null-terminated.
Definition Support.h:78
Accumulates into a python string from a method that accepts an MlirStringCallback.
MlirStringCallback getCallback()
MLIRError(std::string message, std::vector< PyDiagnostic::DiagnosticInfo > &&errorDiagnostics={})
Definition IRCore.h:1331
std::vector< PyDiagnostic::DiagnosticInfo > errorDiagnostics
Definition IRCore.h:1341
const char * what() const noexcept override
Definition IRCore.h:1335
static bool dunderContains(const std::string &attributeKind)
Definition IRCore.cpp:145
static nanobind::callable dunderGetItemNamed(const std::string &attributeKind)
Definition IRCore.cpp:150
static void dunderSetItemNamed(const std::string &attributeKind, nanobind::callable func, bool replace, bool allow_existing)
Definition IRCore.cpp:157
Wrapper for the global LLVM debugging flag.
Definition IRCore.h:54
static void set(nanobind::object &o, bool enable)
Definition IRCore.cpp:107
std::vector< PyDiagnostic::DiagnosticInfo > take()
Definition IRCore.h:456