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