MLIR  22.0.0git
IRModule.h
Go to the documentation of this file.
1 //===- IRModules.h - IR Submodules of pybind module -----------------------===//
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_IRMODULES_H
11 #define MLIR_BINDINGS_PYTHON_IRMODULES_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"
22 #include "mlir-c/Diagnostics.h"
23 #include "mlir-c/IR.h"
24 #include "mlir-c/IntegerSet.h"
25 #include "mlir-c/Transforms.h"
28 #include "llvm/ADT/DenseMap.h"
29 #include "llvm/Support/ThreadPool.h"
30 
31 namespace mlir {
32 namespace python {
33 
34 class PyBlock;
35 class PyDiagnostic;
36 class PyDiagnosticHandler;
37 class PyInsertionPoint;
38 class PyLocation;
39 class DefaultingPyLocation;
40 class PyMlirContext;
41 class DefaultingPyMlirContext;
42 class PyModule;
43 class PyOperation;
44 class PyOperationBase;
45 class PyType;
46 class PySymbolTable;
47 class PyValue;
48 
49 /// Template for a reference to a concrete type which captures a python
50 /// reference to its underlying python object.
51 template <typename T>
52 class PyObjectRef {
53 public:
54  PyObjectRef(T *referrent, nanobind::object object)
55  : referrent(referrent), object(std::move(object)) {
56  assert(this->referrent &&
57  "cannot construct PyObjectRef with null referrent");
58  assert(this->object && "cannot construct PyObjectRef with null object");
59  }
60  PyObjectRef(PyObjectRef &&other) noexcept
61  : referrent(other.referrent), object(std::move(other.object)) {
62  other.referrent = nullptr;
63  assert(!other.object);
64  }
65  PyObjectRef(const PyObjectRef &other)
66  : referrent(other.referrent), object(other.object /* copies */) {}
67  ~PyObjectRef() = default;
68 
69  int getRefCount() {
70  if (!object)
71  return 0;
72  return Py_REFCNT(object.ptr());
73  }
74 
75  /// Releases the object held by this instance, returning it.
76  /// This is the proper thing to return from a function that wants to return
77  /// the reference. Note that this does not work from initializers.
78  nanobind::object releaseObject() {
79  assert(referrent && object);
80  referrent = nullptr;
81  auto stolen = std::move(object);
82  return stolen;
83  }
84 
85  T *get() { return referrent; }
86  T *operator->() {
87  assert(referrent && object);
88  return referrent;
89  }
90  nanobind::object getObject() {
91  assert(referrent && object);
92  return object;
93  }
94  operator bool() const { return referrent && object; }
95 
96 private:
97  T *referrent;
98  nanobind::object object;
99 };
100 
101 /// Tracks an entry in the thread context stack. New entries are pushed onto
102 /// here for each with block that activates a new InsertionPoint, Context or
103 /// Location.
104 ///
105 /// Pushing either a Location or InsertionPoint also pushes its associated
106 /// Context. Pushing a Context will not modify the Location or InsertionPoint
107 /// unless if they are from a different context, in which case, they are
108 /// cleared.
110 public:
111  enum class FrameKind {
112  Context,
114  Location,
115  };
116 
117  PyThreadContextEntry(FrameKind frameKind, nanobind::object context,
118  nanobind::object insertionPoint,
119  nanobind::object location)
120  : context(std::move(context)), insertionPoint(std::move(insertionPoint)),
121  location(std::move(location)), frameKind(frameKind) {}
122 
123  /// Gets the top of stack context and return nullptr if not defined.
125 
126  /// Gets the top of stack insertion point and return nullptr if not defined.
128 
129  /// Gets the top of stack location and returns nullptr if not defined.
130  static PyLocation *getDefaultLocation();
131 
135  FrameKind getFrameKind() { return frameKind; }
136 
137  /// Stack management.
139  static nanobind::object pushContext(nanobind::object context);
140  static void popContext(PyMlirContext &context);
141  static nanobind::object pushInsertionPoint(nanobind::object insertionPoint);
142  static void popInsertionPoint(PyInsertionPoint &insertionPoint);
143  static nanobind::object pushLocation(nanobind::object location);
144  static void popLocation(PyLocation &location);
145 
146  /// Gets the thread local stack.
147  static std::vector<PyThreadContextEntry> &getStack();
148 
149 private:
150  static void push(FrameKind frameKind, nanobind::object context,
151  nanobind::object insertionPoint, nanobind::object location);
152 
153  /// An object reference to the PyContext.
154  nanobind::object context;
155  /// An object reference to the current insertion point.
156  nanobind::object insertionPoint;
157  /// An object reference to the current location.
158  nanobind::object location;
159  // The kind of push that was performed.
160  FrameKind frameKind;
161 };
162 
163 /// Wrapper around MlirLlvmThreadPool
164 /// Python object owns the C++ thread pool
166 public:
168  ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
169  }
170  PyThreadPool(const PyThreadPool &) = delete;
172 
173  int getMaxConcurrency() const { return ownedThreadPool->getMaxConcurrency(); }
174  MlirLlvmThreadPool get() { return wrap(ownedThreadPool.get()); }
175 
176  std::string _mlir_thread_pool_ptr() const {
177  std::stringstream ss;
178  ss << ownedThreadPool.get();
179  return ss.str();
180  }
181 
182 private:
183  std::unique_ptr<llvm::ThreadPoolInterface> ownedThreadPool;
184 };
185 
186 /// Wrapper around MlirContext.
189 public:
190  PyMlirContext() = delete;
191  PyMlirContext(MlirContext context);
192  PyMlirContext(const PyMlirContext &) = delete;
194 
195  /// Returns a context reference for the singleton PyMlirContext wrapper for
196  /// the given context.
197  static PyMlirContextRef forContext(MlirContext context);
198  ~PyMlirContext();
199 
200  /// Accesses the underlying MlirContext.
201  MlirContext get() { return context; }
202 
203  /// Gets a strong reference to this context, which will ensure it is kept
204  /// alive for the life of the reference.
206  return PyMlirContextRef(this, nanobind::cast(this));
207  }
208 
209  /// Gets a capsule wrapping the void* within the MlirContext.
210  nanobind::object getCapsule();
211 
212  /// Creates a PyMlirContext from the MlirContext wrapped by a capsule.
213  /// Note that PyMlirContext instances are uniqued, so the returned object
214  /// may be a pre-existing object. Ownership of the underlying MlirContext
215  /// is taken by calling this function.
216  static nanobind::object createFromCapsule(nanobind::object capsule);
217 
218  /// Gets the count of live context objects. Used for testing.
219  static size_t getLiveCount();
220 
221  /// Get a list of Python objects which are still in the live context map.
222  std::vector<PyOperation *> getLiveOperationObjects();
223 
224  /// Gets the count of live operations associated with this context.
225  /// Used for testing.
226  size_t getLiveOperationCount();
227 
228  /// Clears the live operations map, returning the number of entries which were
229  /// invalidated. To be used as a safety mechanism so that API end-users can't
230  /// corrupt by holding references they shouldn't have accessed in the first
231  /// place.
232  size_t clearLiveOperations();
233 
234  /// Removes an operation from the live operations map and sets it invalid.
235  /// This is useful for when some non-bindings code destroys the operation and
236  /// the bindings need to made aware. For example, in the case when pass
237  /// manager is run.
238  ///
239  /// Note that this does *NOT* clear the nested operations.
240  void clearOperation(MlirOperation op);
241 
242  /// Clears all operations nested inside the given op using
243  /// `clearOperation(MlirOperation)`.
245  void clearOperationsInside(MlirOperation op);
246 
247  /// Clears the operaiton _and_ all operations inside using
248  /// `clearOperation(MlirOperation)`.
250 
251  /// Gets the count of live modules associated with this context.
252  /// Used for testing.
253  size_t getLiveModuleCount();
254 
255  /// Enter and exit the context manager.
256  static nanobind::object contextEnter(nanobind::object context);
257  void contextExit(const nanobind::object &excType,
258  const nanobind::object &excVal,
259  const nanobind::object &excTb);
260 
261  /// Attaches a Python callback as a diagnostic handler, returning a
262  /// registration object (internally a PyDiagnosticHandler).
263  nanobind::object attachDiagnosticHandler(nanobind::object callback);
264 
265  /// Controls whether error diagnostics should be propagated to diagnostic
266  /// handlers, instead of being captured by `ErrorCapture`.
267  void setEmitErrorDiagnostics(bool value) { emitErrorDiagnostics = value; }
268  struct ErrorCapture;
269 
270 private:
271  // Interns the mapping of live MlirContext::ptr to PyMlirContext instances,
272  // preserving the relationship that an MlirContext maps to a single
273  // PyMlirContext wrapper. This could be replaced in the future with an
274  // extension mechanism on the MlirContext for stashing user pointers.
275  // Note that this holds a handle, which does not imply ownership.
276  // Mappings will be removed when the context is destructed.
277  using LiveContextMap = llvm::DenseMap<void *, PyMlirContext *>;
278  static nanobind::ft_mutex live_contexts_mutex;
279  static LiveContextMap &getLiveContexts();
280 
281  // Interns all live modules associated with this context. Modules tracked
282  // in this map are valid. When a module is invalidated, it is removed
283  // from this map, and while it still exists as an instance, any
284  // attempt to access it will raise an error.
285  using LiveModuleMap =
287  LiveModuleMap liveModules;
288 
289  // Interns all live operations associated with this context. Operations
290  // tracked in this map are valid. When an operation is invalidated, it is
291  // removed from this map, and while it still exists as an instance, any
292  // attempt to access it will raise an error.
293  using LiveOperationMap =
295  nanobind::ft_mutex liveOperationsMutex;
296 
297  // Guarded by liveOperationsMutex in free-threading mode.
298  LiveOperationMap liveOperations;
299 
300  bool emitErrorDiagnostics = false;
301 
302  MlirContext context;
303  friend class PyModule;
304  friend class PyOperation;
305 };
306 
307 /// Used in function arguments when None should resolve to the current context
308 /// manager set instance.
310  : public Defaulting<DefaultingPyMlirContext, PyMlirContext> {
311 public:
313  static constexpr const char kTypeDescription[] = "mlir.ir.Context";
314  static PyMlirContext &resolve();
315 };
316 
317 /// Base class for all objects that directly or indirectly depend on an
318 /// MlirContext. The lifetime of the context will extend at least to the
319 /// lifetime of these instances.
320 /// Immutable objects that depend on a context extend this directly.
322 public:
323  BaseContextObject(PyMlirContextRef ref) : contextRef(std::move(ref)) {
324  assert(this->contextRef &&
325  "context object constructed with null context ref");
326  }
327 
328  /// Accesses the context reference.
329  PyMlirContextRef &getContext() { return contextRef; }
330 
331 private:
332  PyMlirContextRef contextRef;
333 };
334 
335 /// Wrapper around an MlirLocation.
337 public:
338  PyLocation(PyMlirContextRef contextRef, MlirLocation loc)
339  : BaseContextObject(std::move(contextRef)), loc(loc) {}
340 
341  operator MlirLocation() const { return loc; }
342  MlirLocation get() const { return loc; }
343 
344  /// Enter and exit the context manager.
345  static nanobind::object contextEnter(nanobind::object location);
346  void contextExit(const nanobind::object &excType,
347  const nanobind::object &excVal,
348  const nanobind::object &excTb);
349 
350  /// Gets a capsule wrapping the void* within the MlirLocation.
351  nanobind::object getCapsule();
352 
353  /// Creates a PyLocation from the MlirLocation wrapped by a capsule.
354  /// Note that PyLocation instances are uniqued, so the returned object
355  /// may be a pre-existing object. Ownership of the underlying MlirLocation
356  /// is taken by calling this function.
357  static PyLocation createFromCapsule(nanobind::object capsule);
358 
359 private:
360  MlirLocation loc;
361 };
362 
363 /// Python class mirroring the C MlirDiagnostic struct. Note that these structs
364 /// are only valid for the duration of a diagnostic callback and attempting
365 /// to access them outside of that will raise an exception. This applies to
366 /// nested diagnostics (in the notes) as well.
368 public:
369  PyDiagnostic(MlirDiagnostic diagnostic) : diagnostic(diagnostic) {}
370  void invalidate();
371  bool isValid() { return valid; }
374  nanobind::str getMessage();
375  nanobind::tuple getNotes();
376 
377  /// Materialized diagnostic information. This is safe to access outside the
378  /// diagnostic callback.
379  struct DiagnosticInfo {
382  std::string message;
383  std::vector<DiagnosticInfo> notes;
384  };
386 
387 private:
388  MlirDiagnostic diagnostic;
389 
390  void checkValid();
391  /// If notes have been materialized from the diagnostic, then this will
392  /// be populated with the corresponding objects (all castable to
393  /// PyDiagnostic).
394  std::optional<nanobind::tuple> materializedNotes;
395  bool valid = true;
396 };
397 
398 /// Represents a diagnostic handler attached to the context. The handler's
399 /// callback will be invoked with PyDiagnostic instances until the detach()
400 /// method is called or the context is destroyed. A diagnostic handler can be
401 /// the subject of a `with` block, which will detach it when the block exits.
402 ///
403 /// Since diagnostic handlers can call back into Python code which can do
404 /// unsafe things (i.e. recursively emitting diagnostics, raising exceptions,
405 /// etc), this is generally not deemed to be a great user-level API. Users
406 /// should generally use some form of DiagnosticCollector. If the handler raises
407 /// any exceptions, they will just be emitted to stderr and dropped.
408 ///
409 /// The unique usage of this class means that its lifetime management is
410 /// different from most other parts of the API. Instances are always created
411 /// in an attached state and can transition to a detached state by either:
412 /// a) The context being destroyed and unregistering all handlers.
413 /// b) An explicit call to detach().
414 /// The object may remain live from a Python perspective for an arbitrary time
415 /// after detachment, but there is nothing the user can do with it (since there
416 /// is no way to attach an existing handler object).
418 public:
419  PyDiagnosticHandler(MlirContext context, nanobind::object callback);
421 
422  bool isAttached() { return registeredID.has_value(); }
423  bool getHadError() { return hadError; }
424 
425  /// Detaches the handler. Does nothing if not attached.
426  void detach();
427 
428  nanobind::object contextEnter() { return nanobind::cast(this); }
429  void contextExit(const nanobind::object &excType,
430  const nanobind::object &excVal,
431  const nanobind::object &excTb) {
432  detach();
433  }
434 
435 private:
436  MlirContext context;
437  nanobind::object callback;
438  std::optional<MlirDiagnosticHandlerID> registeredID;
439  bool hadError = false;
440  friend class PyMlirContext;
441 };
442 
443 /// RAII object that captures any error diagnostics emitted to the provided
444 /// context.
447  : ctx(ctx), handlerID(mlirContextAttachDiagnosticHandler(
448  ctx->get(), handler, /*userData=*/this,
449  /*deleteUserData=*/nullptr)) {}
451  mlirContextDetachDiagnosticHandler(ctx->get(), handlerID);
452  assert(errors.empty() && "unhandled captured errors");
453  }
454 
455  std::vector<PyDiagnostic::DiagnosticInfo> take() {
456  return std::move(errors);
457  };
458 
459 private:
460  PyMlirContextRef ctx;
461  MlirDiagnosticHandlerID handlerID;
462  std::vector<PyDiagnostic::DiagnosticInfo> errors;
463 
464  static MlirLogicalResult handler(MlirDiagnostic diag, void *userData);
465 };
466 
467 /// Wrapper around an MlirDialect. This is exported as `DialectDescriptor` in
468 /// order to differentiate it from the `Dialect` base class which is extended by
469 /// plugins which extend dialect functionality through extension python code.
470 /// This should be seen as the "low-level" object and `Dialect` as the
471 /// high-level, user facing object.
473 public:
474  PyDialectDescriptor(PyMlirContextRef contextRef, MlirDialect dialect)
475  : BaseContextObject(std::move(contextRef)), dialect(dialect) {}
476 
477  MlirDialect get() { return dialect; }
478 
479 private:
480  MlirDialect dialect;
481 };
482 
483 /// User-level object for accessing dialects with dotted syntax such as:
484 /// ctx.dialect.std
486 public:
488  : BaseContextObject(std::move(contextRef)) {}
489 
490  MlirDialect getDialectForKey(const std::string &key, bool attrError);
491 };
492 
493 /// User-level dialect object. For dialects that have a registered extension,
494 /// this will be the base class of the extension dialect type. For un-extended,
495 /// objects of this type will be returned directly.
496 class PyDialect {
497 public:
498  PyDialect(nanobind::object descriptor) : descriptor(std::move(descriptor)) {}
499 
500  nanobind::object getDescriptor() { return descriptor; }
501 
502 private:
503  nanobind::object descriptor;
504 };
505 
506 /// Wrapper around an MlirDialectRegistry.
507 /// Upon construction, the Python wrapper takes ownership of the
508 /// underlying MlirDialectRegistry.
510 public:
512  PyDialectRegistry(MlirDialectRegistry registry) : registry(registry) {}
514  if (!mlirDialectRegistryIsNull(registry))
515  mlirDialectRegistryDestroy(registry);
516  }
519  : registry(other.registry) {
520  other.registry = {nullptr};
521  }
522 
523  operator MlirDialectRegistry() const { return registry; }
524  MlirDialectRegistry get() const { return registry; }
525 
526  nanobind::object getCapsule();
527  static PyDialectRegistry createFromCapsule(nanobind::object capsule);
528 
529 private:
530  MlirDialectRegistry registry;
531 };
532 
533 /// Used in function arguments when None should resolve to the current context
534 /// manager set instance.
536  : public Defaulting<DefaultingPyLocation, PyLocation> {
537 public:
539  static constexpr const char kTypeDescription[] = "mlir.ir.Location";
540  static PyLocation &resolve();
541 
542  operator MlirLocation() const { return *get(); }
543 };
544 
545 /// Wrapper around MlirModule.
546 /// This is the top-level, user-owned object that contains regions/ops/blocks.
547 class PyModule;
549 class PyModule : public BaseContextObject {
550 public:
551  /// Returns a PyModule reference for the given MlirModule. This may return
552  /// a pre-existing or new object.
553  static PyModuleRef forModule(MlirModule module);
554  PyModule(PyModule &) = delete;
555  PyModule(PyMlirContext &&) = delete;
556  ~PyModule();
557 
558  /// Gets the backing MlirModule.
559  MlirModule get() { return module; }
560 
561  /// Gets a strong reference to this module.
563  return PyModuleRef(this, nanobind::borrow<nanobind::object>(handle));
564  }
565 
566  /// Gets a capsule wrapping the void* within the MlirModule.
567  /// Note that the module does not (yet) provide a corresponding factory for
568  /// constructing from a capsule as that would require uniquing PyModule
569  /// instances, which is not currently done.
570  nanobind::object getCapsule();
571 
572  /// Creates a PyModule from the MlirModule wrapped by a capsule.
573  /// Note that PyModule instances are uniqued, so the returned object
574  /// may be a pre-existing object. Ownership of the underlying MlirModule
575  /// is taken by calling this function.
576  static nanobind::object createFromCapsule(nanobind::object capsule);
577 
578 private:
579  PyModule(PyMlirContextRef contextRef, MlirModule module);
580  MlirModule module;
581  nanobind::handle handle;
582 };
583 
584 class PyAsmState;
585 
586 /// Base class for PyOperation and PyOpView which exposes the primary, user
587 /// visible methods for manipulating it.
589 public:
590  virtual ~PyOperationBase() = default;
591  /// Implements the bound 'print' method and helps with others.
592  void print(std::optional<int64_t> largeElementsLimit,
593  std::optional<int64_t> largeResourceLimit, bool enableDebugInfo,
594  bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope,
595  bool useNameLocAsPrefix, bool assumeVerified,
596  nanobind::object fileObject, bool binary, bool skipRegions);
597  void print(PyAsmState &state, nanobind::object fileObject, bool binary);
598 
599  nanobind::object
600  getAsm(bool binary, std::optional<int64_t> largeElementsLimit,
601  std::optional<int64_t> largeResourceLimit, bool enableDebugInfo,
602  bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope,
603  bool useNameLocAsPrefix, bool assumeVerified, bool skipRegions);
604 
605  // Implement the bound 'writeBytecode' method.
606  void writeBytecode(const nanobind::object &fileObject,
607  std::optional<int64_t> bytecodeVersion);
608 
609  // Implement the walk method.
610  void walk(std::function<MlirWalkResult(MlirOperation)> callback,
611  MlirWalkOrder walkOrder);
612 
613  /// Moves the operation before or after the other operation.
614  void moveAfter(PyOperationBase &other);
615  void moveBefore(PyOperationBase &other);
616 
617  /// Given an operation 'other' that is within the same parent block, return
618  /// whether the current operation is before 'other' in the operation list
619  /// of the parent block.
620  /// Note: This function has an average complexity of O(1), but worst case may
621  /// take O(N) where N is the number of operations within the parent block.
622  bool isBeforeInBlock(PyOperationBase &other);
623 
624  /// Verify the operation. Throws `MLIRError` if verification fails, and
625  /// returns `true` otherwise.
626  bool verify();
627 
628  /// Each must provide access to the raw Operation.
629  virtual PyOperation &getOperation() = 0;
630 };
631 
632 /// Wrapper around PyOperation.
633 /// Operations exist in either an attached (dependent) or detached (top-level)
634 /// state. In the detached state (as on creation), an operation is owned by
635 /// the creator and its lifetime extends either until its reference count
636 /// drops to zero or it is attached to a parent, at which point its lifetime
637 /// is bounded by its top-level parent reference.
638 class PyOperation;
641 public:
642  ~PyOperation() override;
643  PyOperation &getOperation() override { return *this; }
644 
645  /// Returns a PyOperation for the given MlirOperation, optionally associating
646  /// it with a parentKeepAlive.
647  static PyOperationRef
648  forOperation(PyMlirContextRef contextRef, MlirOperation operation,
649  nanobind::object parentKeepAlive = nanobind::object());
650 
651  /// Creates a detached operation. The operation must not be associated with
652  /// any existing live operation.
653  static PyOperationRef
654  createDetached(PyMlirContextRef contextRef, MlirOperation operation,
655  nanobind::object parentKeepAlive = nanobind::object());
656 
657  /// Parses a source string (either text assembly or bytecode), creating a
658  /// detached operation.
659  static PyOperationRef parse(PyMlirContextRef contextRef,
660  const std::string &sourceStr,
661  const std::string &sourceName);
662 
663  /// Detaches the operation from its parent block and updates its state
664  /// accordingly.
667  setDetached();
668  parentKeepAlive = nanobind::object();
669  }
670 
671  /// Gets the backing operation.
672  operator MlirOperation() const { return get(); }
673  MlirOperation get() const {
674  checkValid();
675  return operation;
676  }
677 
679  return PyOperationRef(this, nanobind::borrow<nanobind::object>(handle));
680  }
681 
682  bool isAttached() { return attached; }
683  void setAttached(const nanobind::object &parent = nanobind::object()) {
684  assert(!attached && "operation already attached");
685  attached = true;
686  }
687  void setDetached() {
688  assert(attached && "operation already detached");
689  attached = false;
690  }
691  void checkValid() const;
692 
693  /// Gets the owning block or raises an exception if the operation has no
694  /// owning block.
695  PyBlock getBlock();
696 
697  /// Gets the parent operation or raises an exception if the operation has
698  /// no parent.
699  std::optional<PyOperationRef> getParentOperation();
700 
701  /// Gets a capsule wrapping the void* within the MlirOperation.
702  nanobind::object getCapsule();
703 
704  /// Creates a PyOperation from the MlirOperation wrapped by a capsule.
705  /// Ownership of the underlying MlirOperation is taken by calling this
706  /// function.
707  static nanobind::object createFromCapsule(nanobind::object capsule);
708 
709  /// Creates an operation. See corresponding python docstring.
710  static nanobind::object
711  create(std::string_view name, std::optional<std::vector<PyType *>> results,
712  llvm::ArrayRef<MlirValue> operands,
713  std::optional<nanobind::dict> attributes,
714  std::optional<std::vector<PyBlock *>> successors, int regions,
715  PyLocation &location, const nanobind::object &ip, bool inferType);
716 
717  /// Creates an OpView suitable for this operation.
718  nanobind::object createOpView();
719 
720  /// Erases the underlying MlirOperation, removes its pointer from the
721  /// parent context's live operations map, and sets the valid bit false.
722  void erase();
723 
724  /// Invalidate the operation.
725  void setInvalid() { valid = false; }
726 
727  /// Clones this operation.
728  nanobind::object clone(const nanobind::object &ip);
729 
730  PyOperation(PyMlirContextRef contextRef, MlirOperation operation);
731 
732 private:
733  static PyOperationRef createInstance(PyMlirContextRef contextRef,
734  MlirOperation operation,
735  nanobind::object parentKeepAlive);
736 
737  MlirOperation operation;
738  nanobind::handle handle;
739  // Keeps the parent alive, regardless of whether it is an Operation or
740  // Module.
741  // TODO: As implemented, this facility is only sufficient for modeling the
742  // trivial module parent back-reference. Generalize this to also account for
743  // transitions from detached to attached and address TODOs in the
744  // ir_operation.py regarding testing corresponding lifetime guarantees.
745  nanobind::object parentKeepAlive;
746  bool attached = true;
747  bool valid = true;
748 
749  friend class PyOperationBase;
750  friend class PySymbolTable;
751 };
752 
753 /// A PyOpView is equivalent to the C++ "Op" wrappers: these are the basis for
754 /// providing more instance-specific accessors and serve as the base class for
755 /// custom ODS-style operation classes. Since this class is subclass on the
756 /// python side, it must present an __init__ method that operates in pure
757 /// python types.
758 class PyOpView : public PyOperationBase {
759 public:
760  PyOpView(const nanobind::object &operationObject);
761  PyOperation &getOperation() override { return operation; }
762 
763  nanobind::object getOperationObject() { return operationObject; }
764 
765  static nanobind::object
766  buildGeneric(std::string_view name, std::tuple<int, bool> opRegionSpec,
767  nanobind::object operandSegmentSpecObj,
768  nanobind::object resultSegmentSpecObj,
769  std::optional<nanobind::list> resultTypeList,
770  nanobind::list operandList,
771  std::optional<nanobind::dict> attributes,
772  std::optional<std::vector<PyBlock *>> successors,
773  std::optional<int> regions, PyLocation &location,
774  const nanobind::object &maybeIp);
775 
776  /// Construct an instance of a class deriving from OpView, bypassing its
777  /// `__init__` method. The derived class will typically define a constructor
778  /// that provides a convenient builder, but we need to side-step this when
779  /// constructing an `OpView` for an already-built operation.
780  ///
781  /// The caller is responsible for verifying that `operation` is a valid
782  /// operation to construct `cls` with.
783  static nanobind::object constructDerived(const nanobind::object &cls,
784  const nanobind::object &operation);
785 
786 private:
787  PyOperation &operation; // For efficient, cast-free access from C++
788  nanobind::object operationObject; // Holds the reference.
789 };
790 
791 /// Wrapper around an MlirRegion.
792 /// Regions are managed completely by their containing operation. Unlike the
793 /// C++ API, the python API does not support detached regions.
794 class PyRegion {
795 public:
796  PyRegion(PyOperationRef parentOperation, MlirRegion region)
797  : parentOperation(std::move(parentOperation)), region(region) {
798  assert(!mlirRegionIsNull(region) && "python region cannot be null");
799  }
800  operator MlirRegion() const { return region; }
801 
802  MlirRegion get() { return region; }
803  PyOperationRef &getParentOperation() { return parentOperation; }
804 
805  void checkValid() { return parentOperation->checkValid(); }
806 
807 private:
808  PyOperationRef parentOperation;
809  MlirRegion region;
810 };
811 
812 /// Wrapper around an MlirAsmState.
813 class PyAsmState {
814 public:
815  PyAsmState(MlirValue value, bool useLocalScope) {
816  flags = mlirOpPrintingFlagsCreate();
817  // The OpPrintingFlags are not exposed Python side, create locally and
818  // associate lifetime with the state.
819  if (useLocalScope)
821  state = mlirAsmStateCreateForValue(value, flags);
822  }
823 
824  PyAsmState(PyOperationBase &operation, bool useLocalScope) {
825  flags = mlirOpPrintingFlagsCreate();
826  // The OpPrintingFlags are not exposed Python side, create locally and
827  // associate lifetime with the state.
828  if (useLocalScope)
830  state =
831  mlirAsmStateCreateForOperation(operation.getOperation().get(), flags);
832  }
834  // Delete copy constructors.
835  PyAsmState(PyAsmState &other) = delete;
836  PyAsmState(const PyAsmState &other) = delete;
837 
838  MlirAsmState get() { return state; }
839 
840 private:
841  MlirAsmState state;
842  MlirOpPrintingFlags flags;
843 };
844 
845 /// Wrapper around an MlirBlock.
846 /// Blocks are managed completely by their containing operation. Unlike the
847 /// C++ API, the python API does not support detached blocks.
848 class PyBlock {
849 public:
850  PyBlock(PyOperationRef parentOperation, MlirBlock block)
851  : parentOperation(std::move(parentOperation)), block(block) {
852  assert(!mlirBlockIsNull(block) && "python block cannot be null");
853  }
854 
855  MlirBlock get() { return block; }
856  PyOperationRef &getParentOperation() { return parentOperation; }
857 
858  void checkValid() { return parentOperation->checkValid(); }
859 
860  /// Gets a capsule wrapping the void* within the MlirBlock.
861  nanobind::object getCapsule();
862 
863 private:
864  PyOperationRef parentOperation;
865  MlirBlock block;
866 };
867 
868 /// An insertion point maintains a pointer to a Block and a reference operation.
869 /// Calls to insert() will insert a new operation before the
870 /// reference operation. If the reference operation is null, then appends to
871 /// the end of the block.
873 public:
874  /// Creates an insertion point positioned after the last operation in the
875  /// block, but still inside the block.
876  PyInsertionPoint(PyBlock &block);
877  /// Creates an insertion point positioned before a reference operation.
878  PyInsertionPoint(PyOperationBase &beforeOperationBase);
879 
880  /// Shortcut to create an insertion point at the beginning of the block.
881  static PyInsertionPoint atBlockBegin(PyBlock &block);
882  /// Shortcut to create an insertion point before the block terminator.
884 
885  /// Inserts an operation.
886  void insert(PyOperationBase &operationBase);
887 
888  /// Enter and exit the context manager.
889  static nanobind::object contextEnter(nanobind::object insertionPoint);
890  void contextExit(const nanobind::object &excType,
891  const nanobind::object &excVal,
892  const nanobind::object &excTb);
893 
894  PyBlock &getBlock() { return block; }
895  std::optional<PyOperationRef> &getRefOperation() { return refOperation; }
896 
897 private:
898  // Trampoline constructor that avoids null initializing members while
899  // looking up parents.
900  PyInsertionPoint(PyBlock block, std::optional<PyOperationRef> refOperation)
901  : refOperation(std::move(refOperation)), block(std::move(block)) {}
902 
903  std::optional<PyOperationRef> refOperation;
904  PyBlock block;
905 };
906 /// Wrapper around the generic MlirType.
907 /// The lifetime of a type is bound by the PyContext that created it.
908 class PyType : public BaseContextObject {
909 public:
910  PyType(PyMlirContextRef contextRef, MlirType type)
911  : BaseContextObject(std::move(contextRef)), type(type) {}
912  bool operator==(const PyType &other) const;
913  operator MlirType() const { return type; }
914  MlirType get() const { return type; }
915 
916  /// Gets a capsule wrapping the void* within the MlirType.
917  nanobind::object getCapsule();
918 
919  /// Creates a PyType from the MlirType wrapped by a capsule.
920  /// Note that PyType instances are uniqued, so the returned object
921  /// may be a pre-existing object. Ownership of the underlying MlirType
922  /// is taken by calling this function.
923  static PyType createFromCapsule(nanobind::object capsule);
924 
925 private:
926  MlirType type;
927 };
928 
929 /// A TypeID provides an efficient and unique identifier for a specific C++
930 /// type. This allows for a C++ type to be compared, hashed, and stored in an
931 /// opaque context. This class wraps around the generic MlirTypeID.
932 class PyTypeID {
933 public:
934  PyTypeID(MlirTypeID typeID) : typeID(typeID) {}
935  // Note, this tests whether the underlying TypeIDs are the same,
936  // not whether the wrapper MlirTypeIDs are the same, nor whether
937  // the PyTypeID objects are the same (i.e., PyTypeID is a value type).
938  bool operator==(const PyTypeID &other) const;
939  operator MlirTypeID() const { return typeID; }
940  MlirTypeID get() { return typeID; }
941 
942  /// Gets a capsule wrapping the void* within the MlirTypeID.
943  nanobind::object getCapsule();
944 
945  /// Creates a PyTypeID from the MlirTypeID wrapped by a capsule.
946  static PyTypeID createFromCapsule(nanobind::object capsule);
947 
948 private:
949  MlirTypeID typeID;
950 };
951 
952 /// CRTP base classes for Python types that subclass Type and should be
953 /// castable from it (i.e. via something like IntegerType(t)).
954 /// By default, type class hierarchies are one level deep (i.e. a
955 /// concrete type class extends PyType); however, intermediate python-visible
956 /// base classes can be modeled by specifying a BaseTy.
957 template <typename DerivedTy, typename BaseTy = PyType>
958 class PyConcreteType : public BaseTy {
959 public:
960  // Derived classes must define statics for:
961  // IsAFunctionTy isaFunction
962  // const char *pyClassName
963  using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
964  using IsAFunctionTy = bool (*)(MlirType);
965  using GetTypeIDFunctionTy = MlirTypeID (*)();
966  static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
967 
968  PyConcreteType() = default;
969  PyConcreteType(PyMlirContextRef contextRef, MlirType t)
970  : BaseTy(std::move(contextRef), t) {}
972  : PyConcreteType(orig.getContext(), castFrom(orig)) {}
973 
974  static MlirType castFrom(PyType &orig) {
975  if (!DerivedTy::isaFunction(orig)) {
976  auto origRepr =
977  nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
978  throw nanobind::value_error((llvm::Twine("Cannot cast type to ") +
979  DerivedTy::pyClassName + " (from " +
980  origRepr + ")")
981  .str()
982  .c_str());
983  }
984  return orig;
985  }
986 
987  static void bind(nanobind::module_ &m) {
988  auto cls = ClassTy(m, DerivedTy::pyClassName);
989  cls.def(nanobind::init<PyType &>(), nanobind::keep_alive<0, 1>(),
990  nanobind::arg("cast_from_type"));
991  cls.def_static(
992  "isinstance",
993  [](PyType &otherType) -> bool {
994  return DerivedTy::isaFunction(otherType);
995  },
996  nanobind::arg("other"));
997  cls.def_prop_ro_static(
998  "static_typeid", [](nanobind::object & /*class*/) -> MlirTypeID {
999  if (DerivedTy::getTypeIdFunction)
1000  return DerivedTy::getTypeIdFunction();
1001  throw nanobind::attribute_error(
1002  (DerivedTy::pyClassName + llvm::Twine(" has no typeid."))
1003  .str()
1004  .c_str());
1005  });
1006  cls.def_prop_ro("typeid", [](PyType &self) {
1007  return nanobind::cast<MlirTypeID>(nanobind::cast(self).attr("typeid"));
1008  });
1009  cls.def("__repr__", [](DerivedTy &self) {
1010  PyPrintAccumulator printAccum;
1011  printAccum.parts.append(DerivedTy::pyClassName);
1012  printAccum.parts.append("(");
1013  mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData());
1014  printAccum.parts.append(")");
1015  return printAccum.join();
1016  });
1017 
1018  if (DerivedTy::getTypeIdFunction) {
1020  DerivedTy::getTypeIdFunction(),
1021  nanobind::cast<nanobind::callable>(nanobind::cpp_function(
1022  [](PyType pyType) -> DerivedTy { return pyType; })));
1023  }
1024 
1025  DerivedTy::bindDerived(cls);
1026  }
1027 
1028  /// Implemented by derived classes to add methods to the Python subclass.
1029  static void bindDerived(ClassTy &m) {}
1030 };
1031 
1032 /// Wrapper around the generic MlirAttribute.
1033 /// The lifetime of a type is bound by the PyContext that created it.
1035 public:
1036  PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
1037  : BaseContextObject(std::move(contextRef)), attr(attr) {}
1038  bool operator==(const PyAttribute &other) const;
1039  operator MlirAttribute() const { return attr; }
1040  MlirAttribute get() const { return attr; }
1041 
1042  /// Gets a capsule wrapping the void* within the MlirAttribute.
1043  nanobind::object getCapsule();
1044 
1045  /// Creates a PyAttribute from the MlirAttribute wrapped by a capsule.
1046  /// Note that PyAttribute instances are uniqued, so the returned object
1047  /// may be a pre-existing object. Ownership of the underlying MlirAttribute
1048  /// is taken by calling this function.
1049  static PyAttribute createFromCapsule(nanobind::object capsule);
1050 
1051 private:
1052  MlirAttribute attr;
1053 };
1054 
1055 /// Represents a Python MlirNamedAttr, carrying an optional owned name.
1056 /// TODO: Refactor this and the C-API to be based on an Identifier owned
1057 /// by the context so as to avoid ownership issues here.
1059 public:
1060  /// Constructs a PyNamedAttr that retains an owned name. This should be
1061  /// used in any code that originates an MlirNamedAttribute from a python
1062  /// string.
1063  /// The lifetime of the PyNamedAttr must extend to the lifetime of the
1064  /// passed attribute.
1065  PyNamedAttribute(MlirAttribute attr, std::string ownedName);
1066 
1068 
1069 private:
1070  // Since the MlirNamedAttr contains an internal pointer to the actual
1071  // memory of the owned string, it must be heap allocated to remain valid.
1072  // Otherwise, strings that fit within the small object optimization threshold
1073  // will have their memory address change as the containing object is moved,
1074  // resulting in an invalid aliased pointer.
1075  std::unique_ptr<std::string> ownedName;
1076 };
1077 
1078 /// CRTP base classes for Python attributes that subclass Attribute and should
1079 /// be castable from it (i.e. via something like StringAttr(attr)).
1080 /// By default, attribute class hierarchies are one level deep (i.e. a
1081 /// concrete attribute class extends PyAttribute); however, intermediate
1082 /// python-visible base classes can be modeled by specifying a BaseTy.
1083 template <typename DerivedTy, typename BaseTy = PyAttribute>
1084 class PyConcreteAttribute : public BaseTy {
1085 public:
1086  // Derived classes must define statics for:
1087  // IsAFunctionTy isaFunction
1088  // const char *pyClassName
1089  using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
1090  using IsAFunctionTy = bool (*)(MlirAttribute);
1091  using GetTypeIDFunctionTy = MlirTypeID (*)();
1092  static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
1093 
1094  PyConcreteAttribute() = default;
1095  PyConcreteAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
1096  : BaseTy(std::move(contextRef), attr) {}
1098  : PyConcreteAttribute(orig.getContext(), castFrom(orig)) {}
1099 
1100  static MlirAttribute castFrom(PyAttribute &orig) {
1101  if (!DerivedTy::isaFunction(orig)) {
1102  auto origRepr =
1103  nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
1104  throw nanobind::value_error((llvm::Twine("Cannot cast attribute to ") +
1105  DerivedTy::pyClassName + " (from " +
1106  origRepr + ")")
1107  .str()
1108  .c_str());
1109  }
1110  return orig;
1111  }
1112 
1113  static void bind(nanobind::module_ &m, PyType_Slot *slots = nullptr) {
1114  ClassTy cls;
1115  if (slots) {
1116  cls = ClassTy(m, DerivedTy::pyClassName, nanobind::type_slots(slots));
1117  } else {
1118  cls = ClassTy(m, DerivedTy::pyClassName);
1119  }
1120  cls.def(nanobind::init<PyAttribute &>(), nanobind::keep_alive<0, 1>(),
1121  nanobind::arg("cast_from_attr"));
1122  cls.def_static(
1123  "isinstance",
1124  [](PyAttribute &otherAttr) -> bool {
1125  return DerivedTy::isaFunction(otherAttr);
1126  },
1127  nanobind::arg("other"));
1128  cls.def_prop_ro(
1129  "type", [](PyAttribute &attr) { return mlirAttributeGetType(attr); });
1130  cls.def_prop_ro_static(
1131  "static_typeid", [](nanobind::object & /*class*/) -> MlirTypeID {
1132  if (DerivedTy::getTypeIdFunction)
1133  return DerivedTy::getTypeIdFunction();
1134  throw nanobind::attribute_error(
1135  (DerivedTy::pyClassName + llvm::Twine(" has no typeid."))
1136  .str()
1137  .c_str());
1138  });
1139  cls.def_prop_ro("typeid", [](PyAttribute &self) {
1140  return nanobind::cast<MlirTypeID>(nanobind::cast(self).attr("typeid"));
1141  });
1142  cls.def("__repr__", [](DerivedTy &self) {
1143  PyPrintAccumulator printAccum;
1144  printAccum.parts.append(DerivedTy::pyClassName);
1145  printAccum.parts.append("(");
1146  mlirAttributePrint(self, printAccum.getCallback(),
1147  printAccum.getUserData());
1148  printAccum.parts.append(")");
1149  return printAccum.join();
1150  });
1151 
1152  if (DerivedTy::getTypeIdFunction) {
1154  DerivedTy::getTypeIdFunction(),
1155  nanobind::cast<nanobind::callable>(
1156  nanobind::cpp_function([](PyAttribute pyAttribute) -> DerivedTy {
1157  return pyAttribute;
1158  })));
1159  }
1160 
1161  DerivedTy::bindDerived(cls);
1162  }
1163 
1164  /// Implemented by derived classes to add methods to the Python subclass.
1165  static void bindDerived(ClassTy &m) {}
1166 };
1167 
1168 /// Wrapper around the generic MlirValue.
1169 /// Values are managed completely by the operation that resulted in their
1170 /// definition. For op result value, this is the operation that defines the
1171 /// value. For block argument values, this is the operation that contains the
1172 /// block to which the value is an argument (blocks cannot be detached in Python
1173 /// bindings so such operation always exists).
1174 class PyValue {
1175 public:
1176  // The virtual here is "load bearing" in that it enables RTTI
1177  // for PyConcreteValue CRTP classes that support maybeDownCast.
1178  // See PyValue::maybeDownCast.
1179  virtual ~PyValue() = default;
1180  PyValue(PyOperationRef parentOperation, MlirValue value)
1181  : parentOperation(std::move(parentOperation)), value(value) {}
1182  operator MlirValue() const { return value; }
1183 
1184  MlirValue get() { return value; }
1185  PyOperationRef &getParentOperation() { return parentOperation; }
1186 
1187  void checkValid() { return parentOperation->checkValid(); }
1188 
1189  /// Gets a capsule wrapping the void* within the MlirValue.
1190  nanobind::object getCapsule();
1191 
1192  nanobind::object maybeDownCast();
1193 
1194  /// Creates a PyValue from the MlirValue wrapped by a capsule. Ownership of
1195  /// the underlying MlirValue is still tied to the owning operation.
1196  static PyValue createFromCapsule(nanobind::object capsule);
1197 
1198 private:
1199  PyOperationRef parentOperation;
1200  MlirValue value;
1201 };
1202 
1203 /// Wrapper around MlirAffineExpr. Affine expressions are owned by the context.
1205 public:
1206  PyAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr)
1207  : BaseContextObject(std::move(contextRef)), affineExpr(affineExpr) {}
1208  bool operator==(const PyAffineExpr &other) const;
1209  operator MlirAffineExpr() const { return affineExpr; }
1210  MlirAffineExpr get() const { return affineExpr; }
1211 
1212  /// Gets a capsule wrapping the void* within the MlirAffineExpr.
1213  nanobind::object getCapsule();
1214 
1215  /// Creates a PyAffineExpr from the MlirAffineExpr wrapped by a capsule.
1216  /// Note that PyAffineExpr instances are uniqued, so the returned object
1217  /// may be a pre-existing object. Ownership of the underlying MlirAffineExpr
1218  /// is taken by calling this function.
1219  static PyAffineExpr createFromCapsule(const nanobind::object &capsule);
1220 
1221  PyAffineExpr add(const PyAffineExpr &other) const;
1222  PyAffineExpr mul(const PyAffineExpr &other) const;
1223  PyAffineExpr floorDiv(const PyAffineExpr &other) const;
1224  PyAffineExpr ceilDiv(const PyAffineExpr &other) const;
1225  PyAffineExpr mod(const PyAffineExpr &other) const;
1226 
1227 private:
1228  MlirAffineExpr affineExpr;
1229 };
1230 
1232 public:
1233  PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap)
1234  : BaseContextObject(std::move(contextRef)), affineMap(affineMap) {}
1235  bool operator==(const PyAffineMap &other) const;
1236  operator MlirAffineMap() const { return affineMap; }
1237  MlirAffineMap get() const { return affineMap; }
1238 
1239  /// Gets a capsule wrapping the void* within the MlirAffineMap.
1240  nanobind::object getCapsule();
1241 
1242  /// Creates a PyAffineMap from the MlirAffineMap wrapped by a capsule.
1243  /// Note that PyAffineMap instances are uniqued, so the returned object
1244  /// may be a pre-existing object. Ownership of the underlying MlirAffineMap
1245  /// is taken by calling this function.
1246  static PyAffineMap createFromCapsule(const nanobind::object &capsule);
1247 
1248 private:
1249  MlirAffineMap affineMap;
1250 };
1251 
1253 public:
1254  PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet)
1255  : BaseContextObject(std::move(contextRef)), integerSet(integerSet) {}
1256  bool operator==(const PyIntegerSet &other) const;
1257  operator MlirIntegerSet() const { return integerSet; }
1258  MlirIntegerSet get() const { return integerSet; }
1259 
1260  /// Gets a capsule wrapping the void* within the MlirIntegerSet.
1261  nanobind::object getCapsule();
1262 
1263  /// Creates a PyIntegerSet from the MlirAffineMap wrapped by a capsule.
1264  /// Note that PyIntegerSet instances may be uniqued, so the returned object
1265  /// may be a pre-existing object. Integer sets are owned by the context.
1266  static PyIntegerSet createFromCapsule(const nanobind::object &capsule);
1267 
1268 private:
1269  MlirIntegerSet integerSet;
1270 };
1271 
1272 /// Bindings for MLIR symbol tables.
1274 public:
1275  /// Constructs a symbol table for the given operation.
1276  explicit PySymbolTable(PyOperationBase &operation);
1277 
1278  /// Destroys the symbol table.
1280 
1281  /// Returns the symbol (opview) with the given name, throws if there is no
1282  /// such symbol in the table.
1283  nanobind::object dunderGetItem(const std::string &name);
1284 
1285  /// Removes the given operation from the symbol table and erases it.
1286  void erase(PyOperationBase &symbol);
1287 
1288  /// Removes the operation with the given name from the symbol table and erases
1289  /// it, throws if there is no such symbol in the table.
1290  void dunderDel(const std::string &name);
1291 
1292  /// Inserts the given operation into the symbol table. The operation must have
1293  /// the symbol trait.
1294  MlirAttribute insert(PyOperationBase &symbol);
1295 
1296  /// Gets and sets the name of a symbol op.
1297  static MlirAttribute getSymbolName(PyOperationBase &symbol);
1298  static void setSymbolName(PyOperationBase &symbol, const std::string &name);
1299 
1300  /// Gets and sets the visibility of a symbol op.
1301  static MlirAttribute getVisibility(PyOperationBase &symbol);
1302  static void setVisibility(PyOperationBase &symbol,
1303  const std::string &visibility);
1304 
1305  /// Replaces all symbol uses within an operation. See the API
1306  /// mlirSymbolTableReplaceAllSymbolUses for all caveats.
1307  static void replaceAllSymbolUses(const std::string &oldSymbol,
1308  const std::string &newSymbol,
1309  PyOperationBase &from);
1310 
1311  /// Walks all symbol tables under and including 'from'.
1312  static void walkSymbolTables(PyOperationBase &from, bool allSymUsesVisible,
1313  nanobind::object callback);
1314 
1315  /// Casts the bindings class into the C API structure.
1316  operator MlirSymbolTable() { return symbolTable; }
1317 
1318 private:
1319  PyOperationRef operation;
1320  MlirSymbolTable symbolTable;
1321 };
1322 
1323 /// Custom exception that allows access to error diagnostic information. This is
1324 /// converted to the `ir.MLIRError` python exception when thrown.
1325 struct MLIRError {
1326  MLIRError(llvm::Twine message,
1327  std::vector<PyDiagnostic::DiagnosticInfo> &&errorDiagnostics = {})
1328  : message(message.str()), errorDiagnostics(std::move(errorDiagnostics)) {}
1329  std::string message;
1330  std::vector<PyDiagnostic::DiagnosticInfo> errorDiagnostics;
1331 };
1332 
1333 void populateIRAffine(nanobind::module_ &m);
1334 void populateIRAttributes(nanobind::module_ &m);
1335 void populateIRCore(nanobind::module_ &m);
1336 void populateIRInterfaces(nanobind::module_ &m);
1337 void populateIRTypes(nanobind::module_ &m);
1338 
1339 } // namespace python
1340 } // namespace mlir
1341 
1342 namespace nanobind {
1343 namespace detail {
1344 
1345 template <>
1346 struct type_caster<mlir::python::DefaultingPyMlirContext>
1347  : MlirDefaultingCaster<mlir::python::DefaultingPyMlirContext> {};
1348 template <>
1349 struct type_caster<mlir::python::DefaultingPyLocation>
1350  : MlirDefaultingCaster<mlir::python::DefaultingPyLocation> {};
1351 
1352 } // namespace detail
1353 } // namespace nanobind
1354 
1355 #endif // MLIR_BINDINGS_PYTHON_IRMODULES_H
static std::string diag(const llvm::Value &value)
Base class for all objects that directly or indirectly depend on an MlirContext.
Definition: IRModule.h:321
PyMlirContextRef & getContext()
Accesses the context reference.
Definition: IRModule.h:329
BaseContextObject(PyMlirContextRef ref)
Definition: IRModule.h:323
Used in function arguments when None should resolve to the current context manager set instance.
Definition: IRModule.h:536
static PyLocation & resolve()
Definition: IRCore.cpp:1136
static constexpr const char kTypeDescription[]
Definition: IRModule.h:539
Used in function arguments when None should resolve to the current context manager set instance.
Definition: IRModule.h:310
static constexpr const char kTypeDescription[]
Definition: IRModule.h:313
static PyMlirContext & resolve()
Definition: IRCore.cpp:857
CRTP template for special wrapper types that are allowed to be passed in as 'None' function arguments...
Definition: NanobindUtils.h:52
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: IRModule.h:1204
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirAffineExpr.
Definition: IRAffine.cpp:365
static PyAffineExpr createFromCapsule(const nanobind::object &capsule)
Creates a PyAffineExpr from the MlirAffineExpr wrapped by a capsule.
Definition: IRAffine.cpp:369
PyAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr)
Definition: IRModule.h:1206
PyAffineExpr ceilDiv(const PyAffineExpr &other) const
PyAffineExpr mul(const PyAffineExpr &other) const
PyAffineExpr mod(const PyAffineExpr &other) const
PyAffineExpr floorDiv(const PyAffineExpr &other) const
bool operator==(const PyAffineExpr &other) const
Definition: IRAffine.cpp:361
PyAffineExpr add(const PyAffineExpr &other) const
MlirAffineExpr get() const
Definition: IRModule.h:1210
PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap)
Definition: IRModule.h:1233
bool operator==(const PyAffineMap &other) const
Definition: IRAffine.cpp:419
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirAffineMap.
Definition: IRAffine.cpp:423
MlirAffineMap get() const
Definition: IRModule.h:1237
static PyAffineMap createFromCapsule(const nanobind::object &capsule)
Creates a PyAffineMap from the MlirAffineMap wrapped by a capsule.
Definition: IRAffine.cpp:427
Wrapper around an MlirAsmState.
Definition: IRModule.h:813
PyAsmState(PyOperationBase &operation, bool useLocalScope)
Definition: IRModule.h:824
PyAsmState(MlirValue value, bool useLocalScope)
Definition: IRModule.h:815
PyAsmState(PyAsmState &other)=delete
PyAsmState(const PyAsmState &other)=delete
MlirAsmState get()
Definition: IRModule.h:838
Wrapper around the generic MlirAttribute.
Definition: IRModule.h:1034
PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
Definition: IRModule.h:1036
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirAttribute.
Definition: IRCore.cpp:2205
static PyAttribute createFromCapsule(nanobind::object capsule)
Creates a PyAttribute from the MlirAttribute wrapped by a capsule.
Definition: IRCore.cpp:2209
MlirAttribute get() const
Definition: IRModule.h:1040
bool operator==(const PyAttribute &other) const
Definition: IRCore.cpp:2201
Wrapper around an MlirBlock.
Definition: IRModule.h:848
MlirBlock get()
Definition: IRModule.h:855
PyOperationRef & getParentOperation()
Definition: IRModule.h:856
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirBlock.
Definition: IRCore.cpp:326
PyBlock(PyOperationRef parentOperation, MlirBlock block)
Definition: IRModule.h:850
CRTP base classes for Python attributes that subclass Attribute and should be castable from it (i....
Definition: IRModule.h:1084
MlirTypeID(*)() GetTypeIDFunctionTy
Definition: IRModule.h:1091
static MlirAttribute castFrom(PyAttribute &orig)
Definition: IRModule.h:1100
nanobind::class_< DerivedTy, BaseTy > ClassTy
Definition: IRModule.h:1089
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition: IRModule.h:1092
static void bind(nanobind::module_ &m, PyType_Slot *slots=nullptr)
Definition: IRModule.h:1113
bool(*)(MlirAttribute) IsAFunctionTy
Definition: IRModule.h:1090
PyConcreteAttribute(PyAttribute &orig)
Definition: IRModule.h:1097
PyConcreteAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
Definition: IRModule.h:1095
static void bindDerived(ClassTy &m)
Implemented by derived classes to add methods to the Python subclass.
Definition: IRModule.h:1165
CRTP base classes for Python types that subclass Type and should be castable from it (i....
Definition: IRModule.h:958
nanobind::class_< DerivedTy, BaseTy > ClassTy
Definition: IRModule.h:963
static void bind(nanobind::module_ &m)
Definition: IRModule.h:987
PyConcreteType(PyType &orig)
Definition: IRModule.h:971
MlirTypeID(*)() GetTypeIDFunctionTy
Definition: IRModule.h:965
bool(*)(MlirType) IsAFunctionTy
Definition: IRModule.h:964
static void bindDerived(ClassTy &m)
Implemented by derived classes to add methods to the Python subclass.
Definition: IRModule.h:1029
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition: IRModule.h:966
PyConcreteType(PyMlirContextRef contextRef, MlirType t)
Definition: IRModule.h:969
static MlirType castFrom(PyType &orig)
Definition: IRModule.h:974
Represents a diagnostic handler attached to the context.
Definition: IRModule.h:417
PyDiagnosticHandler(MlirContext context, nanobind::object callback)
Definition: IRCore.cpp:1013
nanobind::object contextEnter()
Definition: IRModule.h:428
void detach()
Detaches the handler. Does nothing if not attached.
Definition: IRCore.cpp:1019
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition: IRModule.h:429
Python class mirroring the C MlirDiagnostic struct.
Definition: IRModule.h:367
PyLocation getLocation()
Definition: IRCore.cpp:1042
nanobind::tuple getNotes()
Definition: IRCore.cpp:1057
nanobind::str getMessage()
Definition: IRCore.cpp:1049
DiagnosticInfo getInfo()
Definition: IRCore.cpp:1073
PyDiagnostic(MlirDiagnostic diagnostic)
Definition: IRModule.h:369
MlirDiagnosticSeverity getSeverity()
Definition: IRCore.cpp:1037
Wrapper around an MlirDialect.
Definition: IRModule.h:472
PyDialectDescriptor(PyMlirContextRef contextRef, MlirDialect dialect)
Definition: IRModule.h:474
Wrapper around an MlirDialectRegistry.
Definition: IRModule.h:509
PyDialectRegistry(PyDialectRegistry &&other) noexcept
Definition: IRModule.h:518
nanobind::object getCapsule()
Definition: IRCore.cpp:1098
PyDialectRegistry(PyDialectRegistry &)=delete
static PyDialectRegistry createFromCapsule(nanobind::object capsule)
Definition: IRCore.cpp:1102
MlirDialectRegistry get() const
Definition: IRModule.h:524
PyDialectRegistry(MlirDialectRegistry registry)
Definition: IRModule.h:512
User-level dialect object.
Definition: IRModule.h:496
PyDialect(nanobind::object descriptor)
Definition: IRModule.h:498
nanobind::object getDescriptor()
Definition: IRModule.h:500
User-level object for accessing dialects with dotted syntax such as: ctx.dialect.std.
Definition: IRModule.h:485
PyDialects(PyMlirContextRef contextRef)
Definition: IRModule.h:487
MlirDialect getDialectForKey(const std::string &key, bool attrError)
Definition: IRCore.cpp:1085
void registerTypeCaster(MlirTypeID mlirTypeID, nanobind::callable typeCaster, bool replace=false)
Adds a user-friendly type caster.
Definition: IRModule.cpp:87
static PyGlobals & get()
Most code should get the globals via this static accessor.
Definition: Globals.h:38
An insertion point maintains a pointer to a Block and a reference operation.
Definition: IRModule.h:872
static PyInsertionPoint atBlockTerminator(PyBlock &block)
Shortcut to create an insertion point before the block terminator.
Definition: IRCore.cpp:2178
PyInsertionPoint(PyBlock &block)
Creates an insertion point positioned after the last operation in the block, but still inside the blo...
Definition: IRCore.cpp:2133
static PyInsertionPoint atBlockBegin(PyBlock &block)
Shortcut to create an insertion point at the beginning of the block.
Definition: IRCore.cpp:2165
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition: IRCore.cpp:2191
void insert(PyOperationBase &operationBase)
Inserts an operation.
Definition: IRCore.cpp:2139
std::optional< PyOperationRef > & getRefOperation()
Definition: IRModule.h:895
static nanobind::object contextEnter(nanobind::object insertionPoint)
Enter and exit the context manager.
Definition: IRCore.cpp:2187
static PyIntegerSet createFromCapsule(const nanobind::object &capsule)
Creates a PyIntegerSet from the MlirAffineMap wrapped by a capsule.
Definition: IRAffine.cpp:503
MlirIntegerSet get() const
Definition: IRModule.h:1258
bool operator==(const PyIntegerSet &other) const
Definition: IRAffine.cpp:495
PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet)
Definition: IRModule.h:1254
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirIntegerSet.
Definition: IRAffine.cpp:499
Wrapper around an MlirLocation.
Definition: IRModule.h:336
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirLocation.
Definition: IRCore.cpp:1114
PyLocation(PyMlirContextRef contextRef, MlirLocation loc)
Definition: IRModule.h:338
static PyLocation createFromCapsule(nanobind::object capsule)
Creates a PyLocation from the MlirLocation wrapped by a capsule.
Definition: IRCore.cpp:1118
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition: IRCore.cpp:1130
static nanobind::object contextEnter(nanobind::object location)
Enter and exit the context manager.
Definition: IRCore.cpp:1126
MlirLocation get() const
Definition: IRModule.h:342
PyMlirContext(const PyMlirContext &)=delete
PyMlirContext(PyMlirContext &&)=delete
MlirContext get()
Accesses the underlying MlirContext.
Definition: IRModule.h:201
PyMlirContextRef getRef()
Gets a strong reference to this context, which will ensure it is kept alive for the life of the refer...
Definition: IRModule.h:205
void clearOperationsInside(PyOperationBase &op)
Clears all operations nested inside the given op using clearOperation(MlirOperation).
Definition: IRCore.cpp:745
static size_t getLiveCount()
Gets the count of live context objects. Used for testing.
Definition: IRCore.cpp:700
void clearOperationAndInside(PyOperationBase &op)
Clears the operaiton and all operations inside using clearOperation(MlirOperation).
Definition: IRCore.cpp:770
size_t getLiveModuleCount()
Gets the count of live modules associated with this context.
Definition: IRCore.cpp:781
nanobind::object attachDiagnosticHandler(nanobind::object callback)
Attaches a Python callback as a diagnostic handler, returning a registration object (internally a PyD...
Definition: IRCore.cpp:793
size_t clearLiveOperations()
Clears the live operations map, returning the number of entries which were invalidated.
Definition: IRCore.cpp:718
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirContext.
Definition: IRCore.cpp:664
std::vector< PyOperation * > getLiveOperationObjects()
Get a list of Python objects which are still in the live context map.
Definition: IRCore.cpp:710
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition: IRCore.cpp:787
void clearOperation(MlirOperation op)
Removes an operation from the live operations map and sets it invalid.
Definition: IRCore.cpp:731
static PyMlirContextRef forContext(MlirContext context)
Returns a context reference for the singleton PyMlirContext wrapper for the given context.
Definition: IRCore.cpp:675
static nanobind::object createFromCapsule(nanobind::object capsule)
Creates a PyMlirContext from the MlirContext wrapped by a capsule.
Definition: IRCore.cpp:668
size_t getLiveOperationCount()
Gets the count of live operations associated with this context.
Definition: IRCore.cpp:705
static nanobind::object contextEnter(nanobind::object context)
Enter and exit the context manager.
Definition: IRCore.cpp:783
void setEmitErrorDiagnostics(bool value)
Controls whether error diagnostics should be propagated to diagnostic handlers, instead of being capt...
Definition: IRModule.h:267
MlirModule get()
Gets the backing MlirModule.
Definition: IRModule.h:559
static PyModuleRef forModule(MlirModule module)
Returns a PyModule reference for the given MlirModule.
Definition: IRCore.cpp:1163
static nanobind::object createFromCapsule(nanobind::object capsule)
Creates a PyModule from the MlirModule wrapped by a capsule.
Definition: IRCore.cpp:1188
PyModuleRef getRef()
Gets a strong reference to this module.
Definition: IRModule.h:562
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirModule.
Definition: IRCore.cpp:1195
PyModule(PyModule &)=delete
PyModule(PyMlirContext &&)=delete
Represents a Python MlirNamedAttr, carrying an optional owned name.
Definition: IRModule.h:1058
PyNamedAttribute(MlirAttribute attr, std::string ownedName)
Constructs a PyNamedAttr that retains an owned name.
Definition: IRCore.cpp:2221
MlirNamedAttribute namedAttr
Definition: IRModule.h:1067
Template for a reference to a concrete type which captures a python reference to its underlying pytho...
Definition: IRModule.h:52
nanobind::object getObject()
Definition: IRModule.h:90
PyObjectRef(T *referrent, nanobind::object object)
Definition: IRModule.h:54
nanobind::object releaseObject()
Releases the object held by this instance, returning it.
Definition: IRModule.h:78
PyObjectRef(PyObjectRef &&other) noexcept
Definition: IRModule.h:60
PyObjectRef(const PyObjectRef &other)
Definition: IRModule.h:65
A PyOpView is equivalent to the C++ "Op" wrappers: these are the basis for providing more instance-sp...
Definition: IRModule.h:758
static nanobind::object constructDerived(const nanobind::object &cls, const nanobind::object &operation)
Construct an instance of a class deriving from OpView, bypassing its __init__ method.
Definition: IRCore.cpp:2115
nanobind::object getOperationObject()
Definition: IRModule.h:763
static nanobind::object buildGeneric(std::string_view name, std::tuple< int, bool > opRegionSpec, nanobind::object operandSegmentSpecObj, nanobind::object resultSegmentSpecObj, std::optional< nanobind::list > resultTypeList, nanobind::list operandList, std::optional< nanobind::dict > attributes, std::optional< std::vector< PyBlock * >> successors, std::optional< int > regions, PyLocation &location, const nanobind::object &maybeIp)
Definition: IRCore.cpp:1931
PyOpView(const nanobind::object &operationObject)
Definition: IRCore.cpp:2123
PyOperation & getOperation() override
Each must provide access to the raw Operation.
Definition: IRModule.h:761
Base class for PyOperation and PyOpView which exposes the primary, user visible methods for manipulat...
Definition: IRModule.h:588
void walk(std::function< MlirWalkResult(MlirOperation)> callback, MlirWalkOrder walkOrder)
Definition: IRCore.cpp:1376
bool isBeforeInBlock(PyOperationBase &other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
Definition: IRCore.cpp:1454
virtual PyOperation & getOperation()=0
Each must provide access to the raw Operation.
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:1408
void print(PyAsmState &state, nanobind::object fileObject, bool binary)
virtual ~PyOperationBase()=default
void moveAfter(PyOperationBase &other)
Moves the operation before or after the other operation.
Definition: IRCore.cpp:1436
void print(std::optional< int64_t > largeElementsLimit, std::optional< int64_t > largeResourceLimit, bool enableDebugInfo, bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope, bool useNameLocAsPrefix, bool assumeVerified, nanobind::object fileObject, bool binary, bool skipRegions)
Implements the bound 'print' method and helps with others.
void writeBytecode(const nanobind::object &fileObject, std::optional< int64_t > bytecodeVersion)
Definition: IRCore.cpp:1354
void moveBefore(PyOperationBase &other)
Definition: IRCore.cpp:1445
bool verify()
Verify the operation.
Definition: IRCore.cpp:1462
void detachFromParent()
Detaches the operation from its parent block and updates its state accordingly.
Definition: IRModule.h:665
PyOperation(PyMlirContextRef contextRef, MlirOperation operation)
Definition: IRCore.cpp:1203
void erase()
Erases the underlying MlirOperation, removes its pointer from the parent context's live operations ma...
Definition: IRCore.cpp:1653
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirOperation.
Definition: IRCore.cpp:1489
static PyOperationRef createDetached(PyMlirContextRef contextRef, MlirOperation operation, nanobind::object parentKeepAlive=nanobind::object())
Creates a detached operation.
Definition: IRCore.cpp:1272
nanobind::object clone(const nanobind::object &ip)
Clones this operation.
Definition: IRCore.cpp:1633
PyOperation & getOperation() override
Each must provide access to the raw Operation.
Definition: IRModule.h:643
PyOperationRef getRef()
Definition: IRModule.h:678
static nanobind::object createFromCapsule(nanobind::object capsule)
Creates a PyOperation from the MlirOperation wrapped by a capsule.
Definition: IRCore.cpp:1494
MlirOperation get() const
Definition: IRModule.h:673
static PyOperationRef forOperation(PyMlirContextRef contextRef, MlirOperation operation, nanobind::object parentKeepAlive=nanobind::object())
Returns a PyOperation for the given MlirOperation, optionally associating it with a parentKeepAlive.
Definition: IRCore.cpp:1252
void setAttached(const nanobind::object &parent=nanobind::object())
Definition: IRModule.h:683
std::optional< PyOperationRef > getParentOperation()
Gets the parent operation or raises an exception if the operation has no parent.
Definition: IRCore.cpp:1470
static nanobind::object create(std::string_view name, std::optional< std::vector< PyType * >> results, llvm::ArrayRef< MlirValue > operands, std::optional< nanobind::dict > attributes, std::optional< std::vector< PyBlock * >> successors, int regions, PyLocation &location, const nanobind::object &ip, bool inferType)
Creates an operation. See corresponding python docstring.
Definition: IRCore.cpp:1518
nanobind::object createOpView()
Creates an OpView suitable for this operation.
Definition: IRCore.cpp:1642
PyBlock getBlock()
Gets the owning block or raises an exception if the operation has no owning block.
Definition: IRCore.cpp:1480
static PyOperationRef parse(PyMlirContextRef contextRef, const std::string &sourceStr, const std::string &sourceName)
Parses a source string (either text assembly or bytecode), creating a detached operation.
Definition: IRCore.cpp:1288
void checkValid() const
Definition: IRCore.cpp:1300
void setInvalid()
Invalidate the operation.
Definition: IRModule.h:725
Wrapper around an MlirRegion.
Definition: IRModule.h:794
PyRegion(PyOperationRef parentOperation, MlirRegion region)
Definition: IRModule.h:796
PyOperationRef & getParentOperation()
Definition: IRModule.h:803
MlirRegion get()
Definition: IRModule.h:802
Bindings for MLIR symbol tables.
Definition: IRModule.h:1273
void dunderDel(const std::string &name)
Removes the operation with the given name from the symbol table and erases it, throws if there is no ...
Definition: IRCore.cpp:2342
static void walkSymbolTables(PyOperationBase &from, bool allSymUsesVisible, nanobind::object callback)
Walks all symbol tables under and including 'from'.
Definition: IRCore.cpp:2425
static void replaceAllSymbolUses(const std::string &oldSymbol, const std::string &newSymbol, PyOperationBase &from)
Replaces all symbol uses within an operation.
Definition: IRCore.cpp:2413
static void setVisibility(PyOperationBase &symbol, const std::string &visibility)
Definition: IRCore.cpp:2395
static void setSymbolName(PyOperationBase &symbol, const std::string &name)
Definition: IRCore.cpp:2369
~PySymbolTable()
Destroys the symbol table.
Definition: IRModule.h:1279
MlirAttribute insert(PyOperationBase &symbol)
Inserts the given operation into the symbol table.
Definition: IRCore.cpp:2347
void erase(PyOperationBase &symbol)
Removes the given operation from the symbol table and erases it.
Definition: IRCore.cpp:2332
PySymbolTable(PyOperationBase &operation)
Constructs a symbol table for the given operation.
Definition: IRCore.cpp:2311
static MlirAttribute getSymbolName(PyOperationBase &symbol)
Gets and sets the name of a symbol op.
Definition: IRCore.cpp:2357
nanobind::object dunderGetItem(const std::string &name)
Returns the symbol (opview) with the given name, throws if there is no such symbol in the table.
Definition: IRCore.cpp:2319
static MlirAttribute getVisibility(PyOperationBase &symbol)
Gets and sets the visibility of a symbol op.
Definition: IRCore.cpp:2384
Tracks an entry in the thread context stack.
Definition: IRModule.h:109
static PyThreadContextEntry * getTopOfStack()
Stack management.
Definition: IRCore.cpp:877
static void popLocation(PyLocation &location)
Definition: IRCore.cpp:989
static nanobind::object pushLocation(nanobind::object location)
Definition: IRCore.cpp:980
static nanobind::object pushContext(nanobind::object context)
Definition: IRCore.cpp:939
static PyLocation * getDefaultLocation()
Gets the top of stack location and returns nullptr if not defined.
Definition: IRCore.cpp:934
static void popInsertionPoint(PyInsertionPoint &insertionPoint)
Definition: IRCore.cpp:969
static nanobind::object pushInsertionPoint(nanobind::object insertionPoint)
Definition: IRCore.cpp:957
static void popContext(PyMlirContext &context)
Definition: IRCore.cpp:946
static PyInsertionPoint * getDefaultInsertionPoint()
Gets the top of stack insertion point and return nullptr if not defined.
Definition: IRCore.cpp:929
PyMlirContext * getContext()
Definition: IRCore.cpp:906
static PyMlirContext * getDefaultContext()
Gets the top of stack context and return nullptr if not defined.
Definition: IRCore.cpp:924
static std::vector< PyThreadContextEntry > & getStack()
Gets the thread local stack.
Definition: IRCore.cpp:872
PyThreadContextEntry(FrameKind frameKind, nanobind::object context, nanobind::object insertionPoint, nanobind::object location)
Definition: IRModule.h:117
PyInsertionPoint * getInsertionPoint()
Definition: IRCore.cpp:912
Wrapper around MlirLlvmThreadPool Python object owns the C++ thread pool.
Definition: IRModule.h:165
std::string _mlir_thread_pool_ptr() const
Definition: IRModule.h:176
PyThreadPool(const PyThreadPool &)=delete
int getMaxConcurrency() const
Definition: IRModule.h:173
PyThreadPool(PyThreadPool &&)=delete
MlirLlvmThreadPool get()
Definition: IRModule.h:174
A TypeID provides an efficient and unique identifier for a specific C++ type.
Definition: IRModule.h:932
MlirTypeID get()
Definition: IRModule.h:940
static PyTypeID createFromCapsule(nanobind::object capsule)
Creates a PyTypeID from the MlirTypeID wrapped by a capsule.
Definition: IRCore.cpp:2257
bool operator==(const PyTypeID &other) const
Definition: IRCore.cpp:2263
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirTypeID.
Definition: IRCore.cpp:2253
PyTypeID(MlirTypeID typeID)
Definition: IRModule.h:934
Wrapper around the generic MlirType.
Definition: IRModule.h:908
PyType(PyMlirContextRef contextRef, MlirType type)
Definition: IRModule.h:910
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirType.
Definition: IRCore.cpp:2237
MlirType get() const
Definition: IRModule.h:914
static PyType createFromCapsule(nanobind::object capsule)
Creates a PyType from the MlirType wrapped by a capsule.
Definition: IRCore.cpp:2241
bool operator==(const PyType &other) const
Definition: IRCore.cpp:2233
Wrapper around the generic MlirValue.
Definition: IRModule.h:1174
PyValue(PyOperationRef parentOperation, MlirValue value)
Definition: IRModule.h:1180
static PyValue createFromCapsule(nanobind::object capsule)
Creates a PyValue from the MlirValue wrapped by a capsule.
Definition: IRCore.cpp:2290
nanobind::object maybeDownCast()
Definition: IRCore.cpp:2275
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirValue.
Definition: IRCore.cpp:2271
virtual ~PyValue()=default
PyOperationRef & getParentOperation()
Definition: IRModule.h:1185
MlirDiagnosticSeverity
Severity of a diagnostic.
Definition: Diagnostics.h:32
MLIR_CAPI_EXPORTED MlirDiagnosticHandlerID mlirContextAttachDiagnosticHandler(MlirContext context, MlirDiagnosticHandler handler, void *userData, void(*deleteUserData)(void *))
Attaches the diagnostic handler to the context.
Definition: Diagnostics.cpp:56
MLIR_CAPI_EXPORTED void mlirContextDetachDiagnosticHandler(MlirContext context, MlirDiagnosticHandlerID id)
Detaches an attached diagnostic handler from the context given its identifier.
Definition: Diagnostics.cpp:72
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
MlirWalkOrder
Traversal order for operation walk.
Definition: IR.h:831
MLIR_CAPI_EXPORTED void mlirOpPrintingFlagsUseLocalScope(MlirOpPrintingFlags flags)
Use local scope when printing the operation.
Definition: IR.cpp:233
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 MlirType mlirAttributeGetType(MlirAttribute attribute)
Gets the type of this attribute.
Definition: IR.cpp:1258
MLIR_CAPI_EXPORTED void mlirTypePrint(MlirType type, MlirStringCallback callback, void *userData)
Prints a location by sending chunks of the string representation and forwarding userData tocallback`.
Definition: IR.cpp:1239
MLIR_CAPI_EXPORTED void mlirAttributePrint(MlirAttribute attr, MlirStringCallback callback, void *userData)
Prints an attribute by sending chunks of the string representation and forwarding userData tocallback...
Definition: IR.cpp:1277
MlirWalkResult
Operation walk result.
Definition: IR.h:824
MLIR_CAPI_EXPORTED MlirAsmState mlirAsmStateCreateForOperation(MlirOperation op, MlirOpPrintingFlags flags)
Creates new AsmState, as with AsmState the IR should not be mutated in-between using this state.
Definition: IR.cpp:157
static bool mlirBlockIsNull(MlirBlock block)
Checks whether a block is null.
Definition: IR.h:920
MLIR_CAPI_EXPORTED void mlirSymbolTableDestroy(MlirSymbolTable symbolTable)
Destroys the symbol table created with mlirSymbolTableCreate.
Definition: IR.cpp:1328
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:859
MLIR_CAPI_EXPORTED void mlirOpPrintingFlagsDestroy(MlirOpPrintingFlags flags)
Destroys printing flags created with mlirOpPrintingFlagsCreate.
Definition: IR.cpp:206
MLIR_CAPI_EXPORTED MlirDialectRegistry mlirDialectRegistryCreate(void)
Creates a dialect registry and transfers its ownership to the caller.
Definition: IR.cpp:145
MLIR_CAPI_EXPORTED void mlirOperationRemoveFromParent(MlirOperation op)
Removes the given operation from its parent block.
Definition: IR.cpp:633
MLIR_CAPI_EXPORTED MlirOpPrintingFlags mlirOpPrintingFlagsCreate(void)
Creates new printing flags with defaults, intended for customization.
Definition: IR.cpp:202
MLIR_CAPI_EXPORTED MlirAsmState mlirAsmStateCreateForValue(MlirValue value, MlirOpPrintingFlags flags)
Creates new AsmState from value.
Definition: IR.cpp:178
PyObjectRef< PyMlirContext > PyMlirContextRef
Wrapper around MlirContext.
Definition: IRModule.h:187
void populateIRAttributes(nanobind::module_ &m)
void populateIRInterfaces(nb::module_ &m)
PyObjectRef< PyModule > PyModuleRef
Definition: IRModule.h:548
void populateIRAffine(nanobind::module_ &m)
void populateIRTypes(nanobind::module_ &m)
void populateIRCore(nanobind::module_ &m)
PyObjectRef< PyOperation > PyOperationRef
Definition: IRModule.h:639
Include the generated interface declarations.
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:116
Named MLIR attribute.
Definition: IR.h:76
Accumulates into a python string from a method that accepts an MlirStringCallback.
MlirStringCallback getCallback()
Custom exception that allows access to error diagnostic information.
Definition: IRModule.h:1325
MLIRError(llvm::Twine message, std::vector< PyDiagnostic::DiagnosticInfo > &&errorDiagnostics={})
Definition: IRModule.h:1326
std::vector< PyDiagnostic::DiagnosticInfo > errorDiagnostics
Definition: IRModule.h:1330
Materialized diagnostic information.
Definition: IRModule.h:379
std::vector< DiagnosticInfo > notes
Definition: IRModule.h:383
RAII object that captures any error diagnostics emitted to the provided context.
Definition: IRModule.h:445
std::vector< PyDiagnostic::DiagnosticInfo > take()
Definition: IRModule.h:455
ErrorCapture(PyMlirContextRef ctx)
Definition: IRModule.h:446