MLIR 22.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
339
345
346/// Traversal order for operation walk.
347enum 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,
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((llvm::Twine("Cannot cast type to ") +
950 DerivedTy::pyClassName + " (from " +
951 origRepr + ")")
952 .str()
953 .c_str());
954 }
955 return orig;
956 }
957
958 static void bind(nanobind::module_ &m) {
959 auto cls = ClassTy(m, DerivedTy::pyClassName);
960 cls.def(nanobind::init<PyType &>(), nanobind::keep_alive<0, 1>(),
961 nanobind::arg("cast_from_type"));
962 cls.def_prop_ro_static(
963 "static_typeid",
964 [](nanobind::object & /*class*/) {
965 if (DerivedTy::getTypeIdFunction)
966 return PyTypeID(DerivedTy::getTypeIdFunction());
967 throw nanobind::attribute_error(
968 (DerivedTy::pyClassName + llvm::Twine(" has no typeid."))
969 .str()
970 .c_str());
971 },
972 nanobind::sig("def static_typeid(/) -> TypeID"));
973 cls.def_prop_ro("typeid", [](PyType &self) {
974 return nanobind::cast<PyTypeID>(nanobind::cast(self).attr("typeid"));
975 });
976 cls.def("__repr__", [](DerivedTy &self) {
977 PyPrintAccumulator printAccum;
978 printAccum.parts.append(DerivedTy::pyClassName);
979 printAccum.parts.append("(");
980 mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData());
981 printAccum.parts.append(")");
982 return printAccum.join();
983 });
984
985 if (DerivedTy::getTypeIdFunction) {
986 PyGlobals::get().registerTypeCaster(
987 DerivedTy::getTypeIdFunction(),
988 nanobind::cast<nanobind::callable>(nanobind::cpp_function(
989 [](PyType pyType) -> DerivedTy { return pyType; })),
990 /*replace*/ true);
991 }
992
993 if (DerivedTy::name.length != 0) {
994 cls.def_prop_ro_static("type_name", [](nanobind::object & /*self*/) {
995 return nanobind::str(DerivedTy::name.data, DerivedTy::name.length);
996 });
997 }
998
999 DerivedTy::bindDerived(cls);
1000 }
1001
1002 /// Implemented by derived classes to add methods to the Python subclass.
1003 static void bindDerived(ClassTy &m) {}
1004};
1005
1006/// Wrapper around the generic MlirAttribute.
1007/// The lifetime of a type is bound by the PyContext that created it.
1009public:
1010 PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
1011 : BaseContextObject(std::move(contextRef)), attr(attr) {}
1012 bool operator==(const PyAttribute &other) const;
1013 operator MlirAttribute() const { return attr; }
1014 MlirAttribute get() const { return attr; }
1015
1016 /// Gets a capsule wrapping the void* within the MlirAttribute.
1017 nanobind::object getCapsule();
1018
1019 /// Creates a PyAttribute from the MlirAttribute wrapped by a capsule.
1020 /// Note that PyAttribute instances are uniqued, so the returned object
1021 /// may be a pre-existing object. Ownership of the underlying MlirAttribute
1022 /// is taken by calling this function.
1023 static PyAttribute createFromCapsule(const nanobind::object &capsule);
1024
1025 nanobind::typed<nanobind::object, PyAttribute> maybeDownCast();
1026
1027private:
1028 MlirAttribute attr;
1029};
1030
1031/// Represents a Python MlirNamedAttr, carrying an optional owned name.
1032/// TODO: Refactor this and the C-API to be based on an Identifier owned
1033/// by the context so as to avoid ownership issues here.
1035public:
1036 /// Constructs a PyNamedAttr that retains an owned name. This should be
1037 /// used in any code that originates an MlirNamedAttribute from a python
1038 /// string.
1039 /// The lifetime of the PyNamedAttr must extend to the lifetime of the
1040 /// passed attribute.
1041 PyNamedAttribute(MlirAttribute attr, std::string ownedName);
1042
1044
1045private:
1046 // Since the MlirNamedAttr contains an internal pointer to the actual
1047 // memory of the owned string, it must be heap allocated to remain valid.
1048 // Otherwise, strings that fit within the small object optimization threshold
1049 // will have their memory address change as the containing object is moved,
1050 // resulting in an invalid aliased pointer.
1051 std::unique_ptr<std::string> ownedName;
1052};
1053
1054/// CRTP base classes for Python attributes that subclass Attribute and should
1055/// be castable from it (i.e. via something like StringAttr(attr)).
1056/// By default, attribute class hierarchies are one level deep (i.e. a
1057/// concrete attribute class extends PyAttribute); however, intermediate
1058/// python-visible base classes can be modeled by specifying a BaseTy.
1059template <typename DerivedTy, typename BaseTy = PyAttribute>
1061public:
1062 // Derived classes must define statics for:
1063 // IsAFunctionTy isaFunction
1064 // const char *pyClassName
1065 using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
1066 using IsAFunctionTy = bool (*)(MlirAttribute);
1067 using GetTypeIDFunctionTy = MlirTypeID (*)();
1068 static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
1069 static inline const MlirStringRef name{};
1071
1073 PyConcreteAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
1074 : BaseTy(std::move(contextRef), attr) {}
1077
1078 static MlirAttribute castFrom(PyAttribute &orig) {
1079 if (!DerivedTy::isaFunction(orig)) {
1080 auto origRepr =
1081 nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
1082 throw nanobind::value_error((llvm::Twine("Cannot cast attribute to ") +
1083 DerivedTy::pyClassName + " (from " +
1084 origRepr + ")")
1085 .str()
1086 .c_str());
1087 }
1088 return orig;
1089 }
1090
1091 static void bind(nanobind::module_ &m, PyType_Slot *slots = nullptr) {
1092 ClassTy cls;
1093 if (slots) {
1094 cls = ClassTy(m, DerivedTy::pyClassName, nanobind::type_slots(slots));
1095 } else {
1096 cls = ClassTy(m, DerivedTy::pyClassName);
1097 }
1098 cls.def(nanobind::init<PyAttribute &>(), nanobind::keep_alive<0, 1>(),
1099 nanobind::arg("cast_from_attr"));
1100 cls.def_prop_ro(
1101 "type",
1102 [](PyAttribute &attr) -> nanobind::typed<nanobind::object, PyType> {
1103 return PyType(attr.getContext(), mlirAttributeGetType(attr))
1104 .maybeDownCast();
1105 });
1106 cls.def_prop_ro_static(
1107 "static_typeid",
1108 [](nanobind::object & /*class*/) -> PyTypeID {
1109 if (DerivedTy::getTypeIdFunction)
1110 return PyTypeID(DerivedTy::getTypeIdFunction());
1111 throw nanobind::attribute_error(
1112 (DerivedTy::pyClassName + llvm::Twine(" has no typeid."))
1113 .str()
1114 .c_str());
1115 },
1116 nanobind::sig("def static_typeid(/) -> TypeID"));
1117 cls.def_prop_ro("typeid", [](PyAttribute &self) {
1118 return nanobind::cast<PyTypeID>(nanobind::cast(self).attr("typeid"));
1119 });
1120 cls.def("__repr__", [](DerivedTy &self) {
1121 PyPrintAccumulator printAccum;
1122 printAccum.parts.append(DerivedTy::pyClassName);
1123 printAccum.parts.append("(");
1124 mlirAttributePrint(self, printAccum.getCallback(),
1125 printAccum.getUserData());
1126 printAccum.parts.append(")");
1127 return printAccum.join();
1128 });
1129
1130 if (DerivedTy::getTypeIdFunction) {
1131 PyGlobals::get().registerTypeCaster(
1132 DerivedTy::getTypeIdFunction(),
1133 nanobind::cast<nanobind::callable>(
1134 nanobind::cpp_function([](PyAttribute pyAttribute) -> DerivedTy {
1135 return pyAttribute;
1136 })),
1137 /*replace*/ true);
1138 }
1139
1140 if (DerivedTy::name.length != 0) {
1141 cls.def_prop_ro_static("attr_name", [](nanobind::object & /*self*/) {
1142 return nanobind::str(DerivedTy::name.data, DerivedTy::name.length);
1143 });
1144 }
1145
1146 DerivedTy::bindDerived(cls);
1147 }
1148
1149 /// Implemented by derived classes to add methods to the Python subclass.
1150 static void bindDerived(ClassTy &m) {}
1151};
1152
1154 : public PyConcreteAttribute<PyStringAttribute> {
1155public:
1157 static constexpr const char *pyClassName = "StringAttr";
1162
1163 static void bindDerived(ClassTy &c);
1164};
1165
1166/// Wrapper around the generic MlirValue.
1167/// Values are managed completely by the operation that resulted in their
1168/// definition. For op result value, this is the operation that defines the
1169/// value. For block argument values, this is the operation that contains the
1170/// block to which the value is an argument (blocks cannot be detached in Python
1171/// bindings so such operation always exists).
1173public:
1174 // The virtual here is "load bearing" in that it enables RTTI
1175 // for PyConcreteValue CRTP classes that support maybeDownCast.
1176 // See PyValue::maybeDownCast.
1177 virtual ~PyValue() = default;
1178 PyValue(PyOperationRef parentOperation, MlirValue value)
1179 : parentOperation(std::move(parentOperation)), value(value) {}
1180 operator MlirValue() const { return value; }
1181
1182 MlirValue get() { return value; }
1183 PyOperationRef &getParentOperation() { return parentOperation; }
1184
1185 void checkValid() { return parentOperation->checkValid(); }
1186
1187 /// Gets a capsule wrapping the void* within the MlirValue.
1188 nanobind::object getCapsule();
1189
1190 nanobind::typed<nanobind::object, PyValue> maybeDownCast();
1191
1192 /// Creates a PyValue from the MlirValue wrapped by a capsule. Ownership of
1193 /// the underlying MlirValue is still tied to the owning operation.
1194 static PyValue createFromCapsule(nanobind::object capsule);
1195
1196private:
1197 PyOperationRef parentOperation;
1198 MlirValue value;
1199};
1200
1201/// Wrapper around MlirAffineExpr. Affine expressions are owned by the context.
1203public:
1204 PyAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr)
1205 : BaseContextObject(std::move(contextRef)), affineExpr(affineExpr) {}
1206 bool operator==(const PyAffineExpr &other) const;
1207 operator MlirAffineExpr() const { return affineExpr; }
1208 MlirAffineExpr get() const { return affineExpr; }
1209
1210 /// Gets a capsule wrapping the void* within the MlirAffineExpr.
1211 nanobind::object getCapsule();
1212
1213 /// Creates a PyAffineExpr from the MlirAffineExpr wrapped by a capsule.
1214 /// Note that PyAffineExpr instances are uniqued, so the returned object
1215 /// may be a pre-existing object. Ownership of the underlying MlirAffineExpr
1216 /// is taken by calling this function.
1217 static PyAffineExpr createFromCapsule(const nanobind::object &capsule);
1218
1219 PyAffineExpr add(const PyAffineExpr &other) const;
1220 PyAffineExpr mul(const PyAffineExpr &other) const;
1222 PyAffineExpr ceilDiv(const PyAffineExpr &other) const;
1223 PyAffineExpr mod(const PyAffineExpr &other) const;
1224
1225private:
1226 MlirAffineExpr affineExpr;
1227};
1228
1230public:
1231 PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap)
1232 : BaseContextObject(std::move(contextRef)), affineMap(affineMap) {}
1233 bool operator==(const PyAffineMap &other) const;
1234 operator MlirAffineMap() const { return affineMap; }
1235 MlirAffineMap get() const { return affineMap; }
1236
1237 /// Gets a capsule wrapping the void* within the MlirAffineMap.
1238 nanobind::object getCapsule();
1239
1240 /// Creates a PyAffineMap from the MlirAffineMap wrapped by a capsule.
1241 /// Note that PyAffineMap instances are uniqued, so the returned object
1242 /// may be a pre-existing object. Ownership of the underlying MlirAffineMap
1243 /// is taken by calling this function.
1244 static PyAffineMap createFromCapsule(const nanobind::object &capsule);
1245
1246private:
1247 MlirAffineMap affineMap;
1248};
1249
1251public:
1252 PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet)
1253 : BaseContextObject(std::move(contextRef)), integerSet(integerSet) {}
1254 bool operator==(const PyIntegerSet &other) const;
1255 operator MlirIntegerSet() const { return integerSet; }
1256 MlirIntegerSet get() const { return integerSet; }
1257
1258 /// Gets a capsule wrapping the void* within the MlirIntegerSet.
1259 nanobind::object getCapsule();
1260
1261 /// Creates a PyIntegerSet from the MlirAffineMap wrapped by a capsule.
1262 /// Note that PyIntegerSet instances may be uniqued, so the returned object
1263 /// may be a pre-existing object. Integer sets are owned by the context.
1264 static PyIntegerSet createFromCapsule(const nanobind::object &capsule);
1265
1266private:
1267 MlirIntegerSet integerSet;
1268};
1269
1270/// Bindings for MLIR symbol tables.
1272public:
1273 /// Constructs a symbol table for the given operation.
1274 explicit PySymbolTable(PyOperationBase &operation);
1275
1276 /// Destroys the symbol table.
1278
1279 /// Returns the symbol (opview) with the given name, throws if there is no
1280 /// such symbol in the table.
1281 nanobind::object dunderGetItem(const std::string &name);
1282
1283 /// Removes the given operation from the symbol table and erases it.
1284 void erase(PyOperationBase &symbol);
1285
1286 /// Removes the operation with the given name from the symbol table and erases
1287 /// it, throws if there is no such symbol in the table.
1288 void dunderDel(const std::string &name);
1289
1290 /// Inserts the given operation into the symbol table. The operation must have
1291 /// the symbol trait.
1292 PyStringAttribute insert(PyOperationBase &symbol);
1293
1294 /// Gets and sets the name of a symbol op.
1295 static PyStringAttribute getSymbolName(PyOperationBase &symbol);
1296 static void setSymbolName(PyOperationBase &symbol, const std::string &name);
1297
1298 /// Gets and sets the visibility of a symbol op.
1299 static PyStringAttribute getVisibility(PyOperationBase &symbol);
1300 static void setVisibility(PyOperationBase &symbol,
1301 const std::string &visibility);
1302
1303 /// Replaces all symbol uses within an operation. See the API
1304 /// mlirSymbolTableReplaceAllSymbolUses for all caveats.
1305 static void replaceAllSymbolUses(const std::string &oldSymbol,
1306 const std::string &newSymbol,
1307 PyOperationBase &from);
1308
1309 /// Walks all symbol tables under and including 'from'.
1310 static void walkSymbolTables(PyOperationBase &from, bool allSymUsesVisible,
1311 nanobind::object callback);
1312
1313 /// Casts the bindings class into the C API structure.
1314 operator MlirSymbolTable() { return symbolTable; }
1315
1316private:
1317 PyOperationRef operation;
1318 MlirSymbolTable symbolTable;
1319};
1320
1321/// Custom exception that allows access to error diagnostic information. This is
1322/// converted to the `ir.MLIRError` python exception when thrown.
1324 MLIRError(llvm::Twine message,
1325 std::vector<PyDiagnostic::DiagnosticInfo> &&errorDiagnostics = {})
1326 : message(message.str()), errorDiagnostics(std::move(errorDiagnostics)) {}
1327 std::string message;
1328 std::vector<PyDiagnostic::DiagnosticInfo> errorDiagnostics;
1329};
1330
1331//------------------------------------------------------------------------------
1332// Utilities.
1333//------------------------------------------------------------------------------
1334
1335inline MlirStringRef toMlirStringRef(const std::string &s) {
1336 return mlirStringRefCreate(s.data(), s.size());
1337}
1338
1339inline MlirStringRef toMlirStringRef(std::string_view s) {
1340 return mlirStringRefCreate(s.data(), s.size());
1341}
1342
1343inline MlirStringRef toMlirStringRef(const nanobind::bytes &s) {
1344 return mlirStringRefCreate(static_cast<const char *>(s.data()), s.size());
1345}
1346
1347/// Create a block, using the current location context if no locations are
1348/// specified.
1350createBlock(const nanobind::sequence &pyArgTypes,
1351 const std::optional<nanobind::sequence> &pyArgLocs);
1352
1354 static bool dunderContains(const std::string &attributeKind);
1355 static nanobind::callable
1356 dunderGetItemNamed(const std::string &attributeKind);
1357 static void dunderSetItemNamed(const std::string &attributeKind,
1358 nanobind::callable func, bool replace);
1359
1360 static void bind(nanobind::module_ &m);
1361};
1362
1363//------------------------------------------------------------------------------
1364// Collections.
1365//------------------------------------------------------------------------------
1366
1368public:
1369 PyRegionIterator(PyOperationRef operation, int nextIndex)
1370 : operation(std::move(operation)), nextIndex(nextIndex) {}
1371
1372 PyRegionIterator &dunderIter() { return *this; }
1373
1374 PyRegion dunderNext();
1375
1376 static void bind(nanobind::module_ &m);
1377
1378private:
1379 PyOperationRef operation;
1380 intptr_t nextIndex = 0;
1381};
1382
1383/// Regions of an op are fixed length and indexed numerically so are represented
1384/// with a sequence-like container.
1386 : public Sliceable<PyRegionList, PyRegion> {
1387public:
1388 static constexpr const char *pyClassName = "RegionSequence";
1389
1391 intptr_t length = -1, intptr_t step = 1);
1392
1394
1395 static void bindDerived(ClassTy &c);
1396
1397private:
1398 /// Give the parent CRTP class access to hook implementations below.
1399 friend class Sliceable<PyRegionList, PyRegion>;
1400
1401 intptr_t getRawNumElements();
1402
1403 PyRegion getRawElement(intptr_t pos);
1404
1406
1407 PyOperationRef operation;
1408};
1409
1411public:
1412 PyBlockIterator(PyOperationRef operation, MlirBlock next)
1413 : operation(std::move(operation)), next(next) {}
1414
1415 PyBlockIterator &dunderIter() { return *this; }
1416
1417 PyBlock dunderNext();
1418
1419 static void bind(nanobind::module_ &m);
1420
1421private:
1422 PyOperationRef operation;
1423 MlirBlock next;
1424};
1425
1426/// Blocks are exposed by the C-API as a forward-only linked list. In Python,
1427/// we present them as a more full-featured list-like container but optimize
1428/// it for forward iteration. Blocks are always owned by a region.
1430public:
1431 PyBlockList(PyOperationRef operation, MlirRegion region)
1432 : operation(std::move(operation)), region(region) {}
1433
1434 PyBlockIterator dunderIter();
1435
1436 intptr_t dunderLen();
1437
1438 PyBlock dunderGetItem(intptr_t index);
1439
1440 PyBlock appendBlock(const nanobind::args &pyArgTypes,
1441 const std::optional<nanobind::sequence> &pyArgLocs);
1442
1443 static void bind(nanobind::module_ &m);
1444
1445private:
1446 PyOperationRef operation;
1447 MlirRegion region;
1448};
1449
1451public:
1452 PyOperationIterator(PyOperationRef parentOperation, MlirOperation next)
1453 : parentOperation(std::move(parentOperation)), next(next) {}
1454
1455 PyOperationIterator &dunderIter() { return *this; }
1456
1457 nanobind::typed<nanobind::object, PyOpView> dunderNext();
1458
1459 static void bind(nanobind::module_ &m);
1460
1461private:
1462 PyOperationRef parentOperation;
1463 MlirOperation next;
1464};
1465
1466/// Operations are exposed by the C-API as a forward-only linked list. In
1467/// Python, we present them as a more full-featured list-like container but
1468/// optimize it for forward iteration. Iterable operations are always owned
1469/// by a block.
1471public:
1472 PyOperationList(PyOperationRef parentOperation, MlirBlock block)
1473 : parentOperation(std::move(parentOperation)), block(block) {}
1474
1475 PyOperationIterator dunderIter();
1476
1477 intptr_t dunderLen();
1478
1479 nanobind::typed<nanobind::object, PyOpView> dunderGetItem(intptr_t index);
1480
1481 static void bind(nanobind::module_ &m);
1482
1483private:
1484 PyOperationRef parentOperation;
1485 MlirBlock block;
1486};
1487
1489public:
1490 PyOpOperand(MlirOpOperand opOperand) : opOperand(opOperand) {}
1491
1492 nanobind::typed<nanobind::object, PyOpView> getOwner() const;
1493
1494 size_t getOperandNumber() const;
1495
1496 static void bind(nanobind::module_ &m);
1497
1498private:
1499 MlirOpOperand opOperand;
1500};
1501
1503public:
1504 PyOpOperandIterator(MlirOpOperand opOperand) : opOperand(opOperand) {}
1505
1506 PyOpOperandIterator &dunderIter() { return *this; }
1507
1508 PyOpOperand dunderNext();
1509
1510 static void bind(nanobind::module_ &m);
1511
1512private:
1513 MlirOpOperand opOperand;
1514};
1515
1516/// CRTP base class for Python MLIR values that subclass Value and should be
1517/// castable from it. The value hierarchy is one level deep and is not supposed
1518/// to accommodate other levels unless core MLIR changes.
1519template <typename DerivedTy>
1521public:
1522 // Derived classes must define statics for:
1523 // IsAFunctionTy isaFunction
1524 // const char *pyClassName
1525 // and redefine bindDerived.
1526 using ClassTy = nanobind::class_<DerivedTy, PyValue>;
1527 using IsAFunctionTy = bool (*)(MlirValue);
1528 using GetTypeIDFunctionTy = MlirTypeID (*)();
1529 static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
1531
1532 PyConcreteValue() = default;
1533 PyConcreteValue(PyOperationRef operationRef, MlirValue value)
1534 : PyValue(operationRef, value) {}
1537
1538 /// Attempts to cast the original value to the derived type and throws on
1539 /// type mismatches.
1540 static MlirValue castFrom(PyValue &orig) {
1541 if (!DerivedTy::isaFunction(orig.get())) {
1542 auto origRepr =
1543 nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
1544 throw nanobind::value_error((Twine("Cannot cast value to ") +
1545 DerivedTy::pyClassName + " (from " +
1546 origRepr + ")")
1547 .str()
1548 .c_str());
1549 }
1550 return orig.get();
1551 }
1552
1553 /// Binds the Python module objects to functions of this class.
1554 static void bind(nanobind::module_ &m) {
1555 auto cls = ClassTy(
1556 m, DerivedTy::pyClassName, nanobind::is_generic(),
1557 nanobind::sig((Twine("class ") + DerivedTy::pyClassName + "(Value[_T])")
1558 .str()
1559 .c_str()));
1560 cls.def(nanobind::init<PyValue &>(), nanobind::keep_alive<0, 1>(),
1561 nanobind::arg("value"));
1562 cls.def(
1564 [](DerivedTy &self) -> nanobind::typed<nanobind::object, DerivedTy> {
1565 return self.maybeDownCast();
1566 });
1567
1568 if (DerivedTy::getTypeIdFunction) {
1569 PyGlobals::get().registerValueCaster(
1570 DerivedTy::getTypeIdFunction(),
1571 nanobind::cast<nanobind::callable>(nanobind::cpp_function(
1572 [](PyValue pyValue) -> DerivedTy { return pyValue; })),
1573 /*replace*/ true);
1574 }
1575
1576 DerivedTy::bindDerived(cls);
1577 }
1578
1579 /// Implemented by derived classes to add methods to the Python subclass.
1580 static void bindDerived(ClassTy &m) {}
1581};
1582
1583/// Python wrapper for MlirOpResult.
1585public:
1587 static constexpr const char *pyClassName = "OpResult";
1589
1590 static void bindDerived(ClassTy &c);
1591};
1592
1593/// A list of operation results. Internally, these are stored as consecutive
1594/// elements, random access is cheap. The (returned) result list is associated
1595/// with the operation whose results these are, and thus extends the lifetime of
1596/// this operation.
1598 : public Sliceable<PyOpResultList, PyOpResult> {
1599public:
1600 static constexpr const char *pyClassName = "OpResultList";
1602
1604 intptr_t length = -1, intptr_t step = 1);
1605
1606 static void bindDerived(ClassTy &c);
1607
1608 PyOperationRef &getOperation() { return operation; }
1609
1610private:
1611 /// Give the parent CRTP class access to hook implementations below.
1612 friend class Sliceable<PyOpResultList, PyOpResult>;
1613
1614 intptr_t getRawNumElements();
1615
1616 PyOpResult getRawElement(intptr_t index);
1617
1618 PyOpResultList slice(intptr_t startIndex, intptr_t length,
1619 intptr_t step) const;
1620
1621 PyOperationRef operation;
1622};
1623
1624/// Python wrapper for MlirBlockArgument.
1626 : public PyConcreteValue<PyBlockArgument> {
1627public:
1629 static constexpr const char *pyClassName = "BlockArgument";
1631
1632 static void bindDerived(ClassTy &c);
1633};
1634
1635/// A list of block arguments. Internally, these are stored as consecutive
1636/// elements, random access is cheap. The argument list is associated with the
1637/// operation that contains the block (detached blocks are not allowed in
1638/// Python bindings) and extends its lifetime.
1640 : public Sliceable<PyBlockArgumentList, PyBlockArgument> {
1641public:
1642 static constexpr const char *pyClassName = "BlockArgumentList";
1644
1645 PyBlockArgumentList(PyOperationRef operation, MlirBlock block,
1647 intptr_t step = 1);
1648
1649 static void bindDerived(ClassTy &c);
1650
1651private:
1652 /// Give the parent CRTP class access to hook implementations below.
1654
1655 /// Returns the number of arguments in the list.
1656 intptr_t getRawNumElements();
1657
1658 /// Returns `pos`-the element in the list.
1659 PyBlockArgument getRawElement(intptr_t pos) const;
1660
1661 /// Returns a sublist of this list.
1663 intptr_t step) const;
1664
1665 PyOperationRef operation;
1666 MlirBlock block;
1667};
1668
1669/// A list of operation operands. Internally, these are stored as consecutive
1670/// elements, random access is cheap. The (returned) operand list is associated
1671/// with the operation whose operands these are, and thus extends the lifetime
1672/// of this operation.
1674 : public Sliceable<PyOpOperandList, PyValue> {
1675public:
1676 static constexpr const char *pyClassName = "OpOperandList";
1678
1680 intptr_t length = -1, intptr_t step = 1);
1681
1682 void dunderSetItem(intptr_t index, PyValue value);
1683
1684 static void bindDerived(ClassTy &c);
1685
1686private:
1687 /// Give the parent CRTP class access to hook implementations below.
1688 friend class Sliceable<PyOpOperandList, PyValue>;
1689
1690 intptr_t getRawNumElements();
1691
1692 PyValue getRawElement(intptr_t pos);
1693
1695 intptr_t step) const;
1696
1697 PyOperationRef operation;
1698};
1699
1700/// A list of operation successors. Internally, these are stored as consecutive
1701/// elements, random access is cheap. The (returned) successor list is
1702/// associated with the operation whose successors these are, and thus extends
1703/// the lifetime of this operation.
1705 : public Sliceable<PyOpSuccessors, PyBlock> {
1706public:
1707 static constexpr const char *pyClassName = "OpSuccessors";
1708
1710 intptr_t length = -1, intptr_t step = 1);
1711
1712 void dunderSetItem(intptr_t index, PyBlock block);
1713
1714 static void bindDerived(ClassTy &c);
1715
1716private:
1717 /// Give the parent CRTP class access to hook implementations below.
1718 friend class Sliceable<PyOpSuccessors, PyBlock>;
1719
1720 intptr_t getRawNumElements();
1721
1722 PyBlock getRawElement(intptr_t pos);
1723
1725 intptr_t step) const;
1726
1727 PyOperationRef operation;
1728};
1729
1730/// A list of block successors. Internally, these are stored as consecutive
1731/// elements, random access is cheap. The (returned) successor list is
1732/// associated with the operation and block whose successors these are, and thus
1733/// extends the lifetime of this operation and block.
1735 : public Sliceable<PyBlockSuccessors, PyBlock> {
1736public:
1737 static constexpr const char *pyClassName = "BlockSuccessors";
1738
1741 intptr_t step = 1);
1742
1743private:
1744 /// Give the parent CRTP class access to hook implementations below.
1745 friend class Sliceable<PyBlockSuccessors, PyBlock>;
1746
1747 intptr_t getRawNumElements();
1748
1749 PyBlock getRawElement(intptr_t pos);
1750
1752 intptr_t step) const;
1753
1754 PyOperationRef operation;
1755 PyBlock block;
1756};
1757
1758/// A list of block predecessors. The (returned) predecessor list is
1759/// associated with the operation and block whose predecessors these are, and
1760/// thus extends the lifetime of this operation and block.
1761///
1762/// WARNING: This Sliceable is more expensive than the others here because
1763/// mlirBlockGetPredecessor actually iterates the use-def chain (of block
1764/// operands) anew for each indexed access.
1766 : public Sliceable<PyBlockPredecessors, PyBlock> {
1767public:
1768 static constexpr const char *pyClassName = "BlockPredecessors";
1769
1772 intptr_t step = 1);
1773
1774private:
1775 /// Give the parent CRTP class access to hook implementations below.
1776 friend class Sliceable<PyBlockPredecessors, PyBlock>;
1777
1778 intptr_t getRawNumElements();
1779
1780 PyBlock getRawElement(intptr_t pos);
1781
1783 intptr_t step) const;
1784
1785 PyOperationRef operation;
1786 PyBlock block;
1787};
1788
1789/// A list of operation attributes. Can be indexed by name, producing
1790/// attributes, or by index, producing named attributes.
1792public:
1794 : operation(std::move(operation)) {}
1795
1796 nanobind::typed<nanobind::object, PyAttribute>
1797 dunderGetItemNamed(const std::string &name);
1798
1799 PyNamedAttribute dunderGetItemIndexed(intptr_t index);
1800
1801 void dunderSetItem(const std::string &name, const PyAttribute &attr);
1802
1803 void dunderDelItem(const std::string &name);
1804
1805 intptr_t dunderLen();
1806
1807 bool dunderContains(const std::string &name);
1808
1809 static void
1810 forEachAttr(MlirOperation op,
1811 llvm::function_ref<void(MlirStringRef, MlirAttribute)> fn);
1812
1813 static void bind(nanobind::module_ &m);
1814
1815private:
1816 PyOperationRef operation;
1817};
1818
1819MLIR_PYTHON_API_EXPORTED MlirValue getUniqueResult(MlirOperation operation);
1820MLIR_PYTHON_API_EXPORTED void populateIRCore(nanobind::module_ &m);
1821MLIR_PYTHON_API_EXPORTED void populateRoot(nanobind::module_ &m);
1822} // namespace MLIR_BINDINGS_PYTHON_DOMAIN
1823} // namespace python
1824} // namespace mlir
1825
1826namespace nanobind {
1827namespace detail {
1828
1829template <>
1830struct type_caster<
1831 mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::DefaultingPyMlirContext>
1833 mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::DefaultingPyMlirContext> {
1834};
1835template <>
1836struct type_caster<
1837 mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::DefaultingPyLocation>
1839 mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::DefaultingPyLocation> {};
1840
1841} // namespace detail
1842} // namespace nanobind
1843
1844#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: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: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:1202
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:1204
PyAffineExpr mul(const PyAffineExpr &other) const
PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap)
Definition IRCore.h:1231
PyAsmState(MlirValue value, bool useLocalScope)
Definition IRCore.cpp:1793
Wrapper around the generic MlirAttribute.
Definition IRCore.h:1008
PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
Definition IRCore.h:1010
Sliceable< PyBlockArgumentList, PyBlockArgument > SliceableT
Definition IRCore.h:1643
PyBlockArgumentList(PyOperationRef operation, MlirBlock block, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2220
Python wrapper for MlirBlockArgument.
Definition IRCore.h:1626
PyBlockIterator(PyOperationRef operation, MlirBlock next)
Definition IRCore.h:1412
PyBlockList(PyOperationRef operation, MlirRegion region)
Definition IRCore.h:1431
PyBlockPredecessors(PyBlock block, PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2350
PyBlockSuccessors(PyBlock block, PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2327
PyBlock(PyOperationRef parentOperation, MlirBlock block)
Definition IRCore.h:811
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition IRCore.h:1068
static void bindDerived(ClassTy &m)
Implemented by derived classes to add methods to the Python subclass.
Definition IRCore.h:1150
PyConcreteAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
Definition IRCore.h:1073
static void bind(nanobind::module_ &m, PyType_Slot *slots=nullptr)
Definition IRCore.h:1091
nanobind::class_< DerivedTy, BaseTy > ClassTy
Definition IRCore.h:1065
static MlirAttribute castFrom(PyAttribute &orig)
Definition IRCore.h:1078
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:1003
PyConcreteValue(PyOperationRef operationRef, MlirValue value)
Definition IRCore.h:1533
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition IRCore.h:1529
static void bind(nanobind::module_ &m)
Binds the Python module objects to functions of this class.
Definition IRCore.h:1554
nanobind::class_< DerivedTy, PyValue > ClassTy
Definition IRCore.h:1526
static MlirValue castFrom(PyValue &orig)
Attempts to cast the original value to the derived type and throws on type mismatches.
Definition IRCore.h:1540
static void bindDerived(ClassTy &m)
Implemented by derived classes to add methods to the Python subclass.
Definition IRCore.h:1580
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:744
PyDiagnosticHandler(MlirContext context, nanobind::object callback)
Definition IRCore.cpp:738
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition IRCore.h: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 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:833
void insert(PyOperationBase &operationBase)
Inserts an operation.
Definition IRCore.cpp:1824
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition IRCore.cpp:1889
static PyInsertionPoint atBlockTerminator(PyBlock &block)
Shortcut to create an insertion point before the block terminator.
Definition IRCore.cpp:1863
static PyInsertionPoint after(PyOperationBase &op)
Shortcut to create an insertion point to the node after the specified operation.
Definition IRCore.cpp:1872
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:1850
PyInsertionPoint(const PyBlock &block)
Creates an insertion point positioned after the last operation in the block, but still inside the blo...
Definition IRCore.cpp:1815
static nanobind::object contextEnter(nanobind::object insertionPoint)
Enter and exit the context manager.
Definition IRCore.cpp:1885
PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet)
Definition IRCore.h:1252
PyLocation(PyMlirContextRef contextRef, MlirLocation loc)
Definition IRCore.h:308
static PyMlirContextRef forContext(MlirContext context)
Returns a context reference for the singleton PyMlirContext wrapper for the given context.
Definition IRCore.cpp:477
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: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:889
Represents a Python MlirNamedAttr, carrying an optional owned name.
Definition IRCore.h:1034
PyNamedAttribute(MlirAttribute attr, std::string ownedName)
Constructs a PyNamedAttr that retains an owned name.
Definition IRCore.cpp:1933
Template for a reference to a concrete type which captures a python reference to its underlying pytho...
Definition IRCore.h:68
nanobind::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:1677
PyOpOperandList(PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2252
void dunderSetItem(intptr_t index, PyValue value)
Definition IRCore.cpp:2260
Sliceable< PyOpResultList, PyOpResult > SliceableT
Definition IRCore.h:1601
PyOpResultList(PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:1418
static constexpr IsAFunctionTy isaFunction
Definition IRCore.h:1586
PyOpSuccessors(PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:2294
void dunderSetItem(intptr_t index, PyBlock block)
Definition IRCore.cpp:2302
A PyOpView is equivalent to the C++ "Op" wrappers: these are the basis for providing more instance-sp...
Definition IRCore.h:735
PyOpView(const nanobind::object &operationObject)
Definition IRCore.cpp:1783
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:1181
nanobind::object getAsm(bool binary, std::optional< int64_t > largeElementsLimit, std::optional< int64_t > largeResourceLimit, bool enableDebugInfo, bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope, bool useNameLocAsPrefix, bool assumeVerified, bool skipRegions)
Definition IRCore.cpp:1135
void writeBytecode(const nanobind::object &fileObject, std::optional< int64_t > bytecodeVersion)
Definition IRCore.cpp:1081
virtual PyOperation & getOperation()=0
Each must provide access to the raw Operation.
void moveAfter(PyOperationBase &other)
Moves the operation before or after the other operation.
Definition IRCore.cpp:1163
void walk(std::function< PyWalkResult(MlirOperation)> callback, PyWalkOrder walkOrder)
Definition IRCore.cpp:1103
PyOperationIterator(PyOperationRef parentOperation, MlirOperation next)
Definition IRCore.h:1452
PyOperationList(PyOperationRef parentOperation, MlirBlock block)
Definition IRCore.h:1472
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:929
PyRegionIterator(PyOperationRef operation, int nextIndex)
Definition IRCore.h:1369
PyRegionList(PyOperationRef operation, intptr_t startIndex=0, intptr_t length=-1, intptr_t step=1)
Definition IRCore.cpp:214
PyRegion(PyOperationRef parentOperation, MlirRegion region)
Definition IRCore.h:773
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition IRCore.h:1159
PySymbolTable(PyOperationBase &operation)
Constructs a symbol table for the given operation.
Definition IRCore.cpp:2037
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: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:1961
Wrapper around the generic MlirValue.
Definition IRCore.h:1172
PyValue(PyOperationRef parentOperation, MlirValue value)
Definition IRCore.h:1178
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)
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
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
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:1557
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:630
MlirStringRef toMlirStringRef(const std::string &s)
Definition IRCore.h:1335
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)
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:1324
std::vector< PyDiagnostic::DiagnosticInfo > errorDiagnostics
Definition IRCore.h:1328
static bool dunderContains(const std::string &attributeKind)
Definition IRCore.cpp:151
static nanobind::callable dunderGetItemNamed(const std::string &attributeKind)
Definition IRCore.cpp:156
static void dunderSetItemNamed(const std::string &attributeKind, nanobind::callable func, bool replace)
Definition IRCore.cpp:163
Wrapper for the global LLVM debugging flag.
Definition IRCore.h:56
static void set(nanobind::object &o, bool enable)
Definition IRCore.cpp:113
std::vector< PyDiagnostic::DiagnosticInfo > take()
Definition IRCore.h:444