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