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