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