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