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[] = "Context";
277  static PyMlirContext &resolve();
278 };
279 
280 /// Base class for all objects that directly or indirectly depend on an
281 /// MlirContext. The lifetime of the context will extend at least to the
282 /// lifetime of these instances.
283 /// Immutable objects that depend on a context extend this directly.
285 public:
286  BaseContextObject(PyMlirContextRef ref) : contextRef(std::move(ref)) {
287  assert(this->contextRef &&
288  "context object constructed with null context ref");
289  }
290 
291  /// Accesses the context reference.
292  PyMlirContextRef &getContext() { return contextRef; }
293 
294 private:
295  PyMlirContextRef contextRef;
296 };
297 
298 /// Wrapper around an MlirLocation.
300 public:
301  PyLocation(PyMlirContextRef contextRef, MlirLocation loc)
302  : BaseContextObject(std::move(contextRef)), loc(loc) {}
303 
304  operator MlirLocation() const { return loc; }
305  MlirLocation get() const { return loc; }
306 
307  /// Enter and exit the context manager.
308  static nanobind::object contextEnter(nanobind::object location);
309  void contextExit(const nanobind::object &excType,
310  const nanobind::object &excVal,
311  const nanobind::object &excTb);
312 
313  /// Gets a capsule wrapping the void* within the MlirLocation.
314  nanobind::object getCapsule();
315 
316  /// Creates a PyLocation from the MlirLocation wrapped by a capsule.
317  /// Note that PyLocation instances are uniqued, so the returned object
318  /// may be a pre-existing object. Ownership of the underlying MlirLocation
319  /// is taken by calling this function.
320  static PyLocation createFromCapsule(nanobind::object capsule);
321 
322 private:
323  MlirLocation loc;
324 };
325 
326 /// Python class mirroring the C MlirDiagnostic struct. Note that these structs
327 /// are only valid for the duration of a diagnostic callback and attempting
328 /// to access them outside of that will raise an exception. This applies to
329 /// nested diagnostics (in the notes) as well.
331 public:
332  PyDiagnostic(MlirDiagnostic diagnostic) : diagnostic(diagnostic) {}
333  void invalidate();
334  bool isValid() { return valid; }
337  nanobind::str getMessage();
338  nanobind::tuple getNotes();
339 
340  /// Materialized diagnostic information. This is safe to access outside the
341  /// diagnostic callback.
342  struct DiagnosticInfo {
345  std::string message;
346  std::vector<DiagnosticInfo> notes;
347  };
349 
350 private:
351  MlirDiagnostic diagnostic;
352 
353  void checkValid();
354  /// If notes have been materialized from the diagnostic, then this will
355  /// be populated with the corresponding objects (all castable to
356  /// PyDiagnostic).
357  std::optional<nanobind::tuple> materializedNotes;
358  bool valid = true;
359 };
360 
361 /// Represents a diagnostic handler attached to the context. The handler's
362 /// callback will be invoked with PyDiagnostic instances until the detach()
363 /// method is called or the context is destroyed. A diagnostic handler can be
364 /// the subject of a `with` block, which will detach it when the block exits.
365 ///
366 /// Since diagnostic handlers can call back into Python code which can do
367 /// unsafe things (i.e. recursively emitting diagnostics, raising exceptions,
368 /// etc), this is generally not deemed to be a great user-level API. Users
369 /// should generally use some form of DiagnosticCollector. If the handler raises
370 /// any exceptions, they will just be emitted to stderr and dropped.
371 ///
372 /// The unique usage of this class means that its lifetime management is
373 /// different from most other parts of the API. Instances are always created
374 /// in an attached state and can transition to a detached state by either:
375 /// a) The context being destroyed and unregistering all handlers.
376 /// b) An explicit call to detach().
377 /// The object may remain live from a Python perspective for an arbitrary time
378 /// after detachment, but there is nothing the user can do with it (since there
379 /// is no way to attach an existing handler object).
381 public:
382  PyDiagnosticHandler(MlirContext context, nanobind::object callback);
384 
385  bool isAttached() { return registeredID.has_value(); }
386  bool getHadError() { return hadError; }
387 
388  /// Detaches the handler. Does nothing if not attached.
389  void detach();
390 
391  nanobind::object contextEnter() { return nanobind::cast(this); }
392  void contextExit(const nanobind::object &excType,
393  const nanobind::object &excVal,
394  const nanobind::object &excTb) {
395  detach();
396  }
397 
398 private:
399  MlirContext context;
400  nanobind::object callback;
401  std::optional<MlirDiagnosticHandlerID> registeredID;
402  bool hadError = false;
403  friend class PyMlirContext;
404 };
405 
406 /// RAII object that captures any error diagnostics emitted to the provided
407 /// context.
410  : ctx(ctx), handlerID(mlirContextAttachDiagnosticHandler(
411  ctx->get(), handler, /*userData=*/this,
412  /*deleteUserData=*/nullptr)) {}
414  mlirContextDetachDiagnosticHandler(ctx->get(), handlerID);
415  assert(errors.empty() && "unhandled captured errors");
416  }
417 
418  std::vector<PyDiagnostic::DiagnosticInfo> take() {
419  return std::move(errors);
420  };
421 
422 private:
423  PyMlirContextRef ctx;
424  MlirDiagnosticHandlerID handlerID;
425  std::vector<PyDiagnostic::DiagnosticInfo> errors;
426 
427  static MlirLogicalResult handler(MlirDiagnostic diag, void *userData);
428 };
429 
430 /// Wrapper around an MlirDialect. This is exported as `DialectDescriptor` in
431 /// order to differentiate it from the `Dialect` base class which is extended by
432 /// plugins which extend dialect functionality through extension python code.
433 /// This should be seen as the "low-level" object and `Dialect` as the
434 /// high-level, user facing object.
436 public:
437  PyDialectDescriptor(PyMlirContextRef contextRef, MlirDialect dialect)
438  : BaseContextObject(std::move(contextRef)), dialect(dialect) {}
439 
440  MlirDialect get() { return dialect; }
441 
442 private:
443  MlirDialect dialect;
444 };
445 
446 /// User-level object for accessing dialects with dotted syntax such as:
447 /// ctx.dialect.std
449 public:
451  : BaseContextObject(std::move(contextRef)) {}
452 
453  MlirDialect getDialectForKey(const std::string &key, bool attrError);
454 };
455 
456 /// User-level dialect object. For dialects that have a registered extension,
457 /// this will be the base class of the extension dialect type. For un-extended,
458 /// objects of this type will be returned directly.
459 class PyDialect {
460 public:
461  PyDialect(nanobind::object descriptor) : descriptor(std::move(descriptor)) {}
462 
463  nanobind::object getDescriptor() { return descriptor; }
464 
465 private:
466  nanobind::object descriptor;
467 };
468 
469 /// Wrapper around an MlirDialectRegistry.
470 /// Upon construction, the Python wrapper takes ownership of the
471 /// underlying MlirDialectRegistry.
473 public:
475  PyDialectRegistry(MlirDialectRegistry registry) : registry(registry) {}
477  if (!mlirDialectRegistryIsNull(registry))
478  mlirDialectRegistryDestroy(registry);
479  }
482  : registry(other.registry) {
483  other.registry = {nullptr};
484  }
485 
486  operator MlirDialectRegistry() const { return registry; }
487  MlirDialectRegistry get() const { return registry; }
488 
489  nanobind::object getCapsule();
490  static PyDialectRegistry createFromCapsule(nanobind::object capsule);
491 
492 private:
493  MlirDialectRegistry registry;
494 };
495 
496 /// Used in function arguments when None should resolve to the current context
497 /// manager set instance.
499  : public Defaulting<DefaultingPyLocation, PyLocation> {
500 public:
502  static constexpr const char kTypeDescription[] = "Location";
503  static PyLocation &resolve();
504 
505  operator MlirLocation() const { return *get(); }
506 };
507 
508 /// Wrapper around MlirModule.
509 /// This is the top-level, user-owned object that contains regions/ops/blocks.
510 class PyModule;
512 class PyModule : public BaseContextObject {
513 public:
514  /// Returns a PyModule reference for the given MlirModule. This always returns
515  /// a new object.
516  static PyModuleRef forModule(MlirModule module);
517  PyModule(PyModule &) = delete;
518  PyModule(PyMlirContext &&) = delete;
519  ~PyModule();
520 
521  /// Gets the backing MlirModule.
522  MlirModule get() { return module; }
523 
524  /// Gets a strong reference to this module.
526  return PyModuleRef(this, nanobind::borrow<nanobind::object>(handle));
527  }
528 
529  /// Gets a capsule wrapping the void* within the MlirModule.
530  /// Note that the module does not (yet) provide a corresponding factory for
531  /// constructing from a capsule as that would require uniquing PyModule
532  /// instances, which is not currently done.
533  nanobind::object getCapsule();
534 
535  /// Creates a PyModule from the MlirModule wrapped by a capsule.
536  /// Note this returns a new object BUT clearMlirModule() must be called to
537  /// prevent double-frees (of the underlying mlir::Module).
538  static nanobind::object createFromCapsule(nanobind::object capsule);
539 
540  void clearMlirModule() { module = {nullptr}; }
541 
542 private:
543  PyModule(PyMlirContextRef contextRef, MlirModule module);
544  MlirModule module;
545  nanobind::handle handle;
546 };
547 
548 class PyAsmState;
549 
550 /// Base class for PyOperation and PyOpView which exposes the primary, user
551 /// visible methods for manipulating it.
553 public:
554  virtual ~PyOperationBase() = default;
555  /// Implements the bound 'print' method and helps with others.
556  void print(std::optional<int64_t> largeElementsLimit,
557  std::optional<int64_t> largeResourceLimit, bool enableDebugInfo,
558  bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope,
559  bool useNameLocAsPrefix, bool assumeVerified,
560  nanobind::object fileObject, bool binary, bool skipRegions);
561  void print(PyAsmState &state, nanobind::object fileObject, bool binary);
562 
563  nanobind::object
564  getAsm(bool binary, std::optional<int64_t> largeElementsLimit,
565  std::optional<int64_t> largeResourceLimit, bool enableDebugInfo,
566  bool prettyDebugInfo, bool printGenericOpForm, bool useLocalScope,
567  bool useNameLocAsPrefix, bool assumeVerified, bool skipRegions);
568 
569  // Implement the bound 'writeBytecode' method.
570  void writeBytecode(const nanobind::object &fileObject,
571  std::optional<int64_t> bytecodeVersion);
572 
573  // Implement the walk method.
574  void walk(std::function<MlirWalkResult(MlirOperation)> callback,
575  MlirWalkOrder walkOrder);
576 
577  /// Moves the operation before or after the other operation.
578  void moveAfter(PyOperationBase &other);
579  void moveBefore(PyOperationBase &other);
580 
581  /// Given an operation 'other' that is within the same parent block, return
582  /// whether the current operation is before 'other' in the operation list
583  /// of the parent block.
584  /// Note: This function has an average complexity of O(1), but worst case may
585  /// take O(N) where N is the number of operations within the parent block.
586  bool isBeforeInBlock(PyOperationBase &other);
587 
588  /// Verify the operation. Throws `MLIRError` if verification fails, and
589  /// returns `true` otherwise.
590  bool verify();
591 
592  /// Each must provide access to the raw Operation.
593  virtual PyOperation &getOperation() = 0;
594 };
595 
596 /// Wrapper around PyOperation.
597 /// Operations exist in either an attached (dependent) or detached (top-level)
598 /// state. In the detached state (as on creation), an operation is owned by
599 /// the creator and its lifetime extends either until its reference count
600 /// drops to zero or it is attached to a parent, at which point its lifetime
601 /// is bounded by its top-level parent reference.
602 class PyOperation;
603 class PyOpView;
606 public:
607  ~PyOperation() override;
608  PyOperation &getOperation() override { return *this; }
609 
610  /// Returns a PyOperation for the given MlirOperation, optionally associating
611  /// it with a parentKeepAlive.
612  static PyOperationRef
613  forOperation(PyMlirContextRef contextRef, MlirOperation operation,
614  nanobind::object parentKeepAlive = nanobind::object());
615 
616  /// Creates a detached operation. The operation must not be associated with
617  /// any existing live operation.
618  static PyOperationRef
619  createDetached(PyMlirContextRef contextRef, MlirOperation operation,
620  nanobind::object parentKeepAlive = nanobind::object());
621 
622  /// Parses a source string (either text assembly or bytecode), creating a
623  /// detached operation.
624  static PyOperationRef parse(PyMlirContextRef contextRef,
625  const std::string &sourceStr,
626  const std::string &sourceName);
627 
628  /// Detaches the operation from its parent block and updates its state
629  /// accordingly.
632  setDetached();
633  parentKeepAlive = nanobind::object();
634  }
635 
636  /// Gets the backing operation.
637  operator MlirOperation() const { return get(); }
638  MlirOperation get() const {
639  checkValid();
640  return operation;
641  }
642 
644  return PyOperationRef(this, nanobind::borrow<nanobind::object>(handle));
645  }
646 
647  bool isAttached() { return attached; }
648  void setAttached(const nanobind::object &parent = nanobind::object()) {
649  assert(!attached && "operation already attached");
650  attached = true;
651  }
652  void setDetached() {
653  assert(attached && "operation already detached");
654  attached = false;
655  }
656  void checkValid() const;
657 
658  /// Gets the owning block or raises an exception if the operation has no
659  /// owning block.
660  PyBlock getBlock();
661 
662  /// Gets the parent operation or raises an exception if the operation has
663  /// no parent.
664  std::optional<PyOperationRef> getParentOperation();
665 
666  /// Gets a capsule wrapping the void* within the MlirOperation.
667  nanobind::object getCapsule();
668 
669  /// Creates a PyOperation from the MlirOperation wrapped by a capsule.
670  /// Ownership of the underlying MlirOperation is taken by calling this
671  /// function.
672  static nanobind::object createFromCapsule(const nanobind::object &capsule);
673 
674  /// Creates an operation. See corresponding python docstring.
675  static nanobind::object
676  create(std::string_view name, std::optional<std::vector<PyType *>> results,
677  llvm::ArrayRef<MlirValue> operands,
678  std::optional<nanobind::dict> attributes,
679  std::optional<std::vector<PyBlock *>> successors, int regions,
680  PyLocation &location, const nanobind::object &ip, bool inferType);
681 
682  /// Creates an OpView suitable for this operation.
683  nanobind::object createOpView();
684 
685  /// Erases the underlying MlirOperation, removes its pointer from the
686  /// parent context's live operations map, and sets the valid bit false.
687  void erase();
688 
689  /// Invalidate the operation.
690  void setInvalid() { valid = false; }
691 
692  /// Clones this operation.
693  nanobind::object clone(const nanobind::object &ip);
694 
695  PyOperation(PyMlirContextRef contextRef, MlirOperation operation);
696 
697 private:
698  static PyOperationRef createInstance(PyMlirContextRef contextRef,
699  MlirOperation operation,
700  nanobind::object parentKeepAlive);
701 
702  MlirOperation operation;
703  nanobind::handle handle;
704  // Keeps the parent alive, regardless of whether it is an Operation or
705  // Module.
706  // TODO: As implemented, this facility is only sufficient for modeling the
707  // trivial module parent back-reference. Generalize this to also account for
708  // transitions from detached to attached and address TODOs in the
709  // ir_operation.py regarding testing corresponding lifetime guarantees.
710  nanobind::object parentKeepAlive;
711  bool attached = true;
712  bool valid = true;
713 
714  friend class PyOperationBase;
715  friend class PySymbolTable;
716 };
717 
718 /// A PyOpView is equivalent to the C++ "Op" wrappers: these are the basis for
719 /// providing more instance-specific accessors and serve as the base class for
720 /// custom ODS-style operation classes. Since this class is subclass on the
721 /// python side, it must present an __init__ method that operates in pure
722 /// python types.
723 class PyOpView : public PyOperationBase {
724 public:
725  PyOpView(const nanobind::object &operationObject);
726  PyOperation &getOperation() override { return operation; }
727 
728  nanobind::object getOperationObject() { return operationObject; }
729 
730  static nanobind::object
731  buildGeneric(std::string_view name, std::tuple<int, bool> opRegionSpec,
732  nanobind::object operandSegmentSpecObj,
733  nanobind::object resultSegmentSpecObj,
734  std::optional<nanobind::list> resultTypeList,
735  nanobind::list operandList,
736  std::optional<nanobind::dict> attributes,
737  std::optional<std::vector<PyBlock *>> successors,
738  std::optional<int> regions, PyLocation &location,
739  const nanobind::object &maybeIp);
740 
741  /// Construct an instance of a class deriving from OpView, bypassing its
742  /// `__init__` method. The derived class will typically define a constructor
743  /// that provides a convenient builder, but we need to side-step this when
744  /// constructing an `OpView` for an already-built operation.
745  ///
746  /// The caller is responsible for verifying that `operation` is a valid
747  /// operation to construct `cls` with.
748  static nanobind::object constructDerived(const nanobind::object &cls,
749  const nanobind::object &operation);
750 
751 private:
752  PyOperation &operation; // For efficient, cast-free access from C++
753  nanobind::object operationObject; // Holds the reference.
754 };
755 
756 /// Wrapper around an MlirRegion.
757 /// Regions are managed completely by their containing operation. Unlike the
758 /// C++ API, the python API does not support detached regions.
759 class PyRegion {
760 public:
761  PyRegion(PyOperationRef parentOperation, MlirRegion region)
762  : parentOperation(std::move(parentOperation)), region(region) {
763  assert(!mlirRegionIsNull(region) && "python region cannot be null");
764  }
765  operator MlirRegion() const { return region; }
766 
767  MlirRegion get() { return region; }
768  PyOperationRef &getParentOperation() { return parentOperation; }
769 
770  void checkValid() { return parentOperation->checkValid(); }
771 
772 private:
773  PyOperationRef parentOperation;
774  MlirRegion region;
775 };
776 
777 /// Wrapper around an MlirAsmState.
778 class PyAsmState {
779 public:
780  PyAsmState(MlirValue value, bool useLocalScope) {
781  flags = mlirOpPrintingFlagsCreate();
782  // The OpPrintingFlags are not exposed Python side, create locally and
783  // associate lifetime with the state.
784  if (useLocalScope)
786  state = mlirAsmStateCreateForValue(value, flags);
787  }
788 
789  PyAsmState(PyOperationBase &operation, bool useLocalScope) {
790  flags = mlirOpPrintingFlagsCreate();
791  // The OpPrintingFlags are not exposed Python side, create locally and
792  // associate lifetime with the state.
793  if (useLocalScope)
795  state =
796  mlirAsmStateCreateForOperation(operation.getOperation().get(), flags);
797  }
799  // Delete copy constructors.
800  PyAsmState(PyAsmState &other) = delete;
801  PyAsmState(const PyAsmState &other) = delete;
802 
803  MlirAsmState get() { return state; }
804 
805 private:
806  MlirAsmState state;
807  MlirOpPrintingFlags flags;
808 };
809 
810 /// Wrapper around an MlirBlock.
811 /// Blocks are managed completely by their containing operation. Unlike the
812 /// C++ API, the python API does not support detached blocks.
813 class PyBlock {
814 public:
815  PyBlock(PyOperationRef parentOperation, MlirBlock block)
816  : parentOperation(std::move(parentOperation)), block(block) {
817  assert(!mlirBlockIsNull(block) && "python block cannot be null");
818  }
819 
820  MlirBlock get() { return block; }
821  PyOperationRef &getParentOperation() { return parentOperation; }
822 
823  void checkValid() { return parentOperation->checkValid(); }
824 
825  /// Gets a capsule wrapping the void* within the MlirBlock.
826  nanobind::object getCapsule();
827 
828 private:
829  PyOperationRef parentOperation;
830  MlirBlock block;
831 };
832 
833 /// An insertion point maintains a pointer to a Block and a reference operation.
834 /// Calls to insert() will insert a new operation before the
835 /// reference operation. If the reference operation is null, then appends to
836 /// the end of the block.
838 public:
839  /// Creates an insertion point positioned after the last operation in the
840  /// block, but still inside the block.
841  PyInsertionPoint(const PyBlock &block);
842  /// Creates an insertion point positioned before a reference operation.
843  PyInsertionPoint(PyOperationBase &beforeOperationBase);
844  /// Creates an insertion point positioned before a reference operation.
845  PyInsertionPoint(PyOperationRef beforeOperationRef);
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(const 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(
1105  "type",
1106  [](PyAttribute &attr) -> nanobind::typed<nanobind::object, PyType> {
1107  return PyType(attr.getContext(), mlirAttributeGetType(attr))
1108  .maybeDownCast();
1109  });
1110  cls.def_prop_ro_static(
1111  "static_typeid",
1112  [](nanobind::object & /*class*/) -> PyTypeID {
1113  if (DerivedTy::getTypeIdFunction)
1114  return PyTypeID(DerivedTy::getTypeIdFunction());
1115  throw nanobind::attribute_error(
1116  (DerivedTy::pyClassName + llvm::Twine(" has no typeid."))
1117  .str()
1118  .c_str());
1119  },
1120  nanobind::sig("def static_typeid(/) -> TypeID"));
1121  cls.def_prop_ro("typeid", [](PyAttribute &self) {
1122  return nanobind::cast<PyTypeID>(nanobind::cast(self).attr("typeid"));
1123  });
1124  cls.def("__repr__", [](DerivedTy &self) {
1125  PyPrintAccumulator printAccum;
1126  printAccum.parts.append(DerivedTy::pyClassName);
1127  printAccum.parts.append("(");
1128  mlirAttributePrint(self, printAccum.getCallback(),
1129  printAccum.getUserData());
1130  printAccum.parts.append(")");
1131  return printAccum.join();
1132  });
1133 
1134  if (DerivedTy::getTypeIdFunction) {
1136  DerivedTy::getTypeIdFunction(),
1137  nanobind::cast<nanobind::callable>(
1138  nanobind::cpp_function([](PyAttribute pyAttribute) -> DerivedTy {
1139  return pyAttribute;
1140  })));
1141  }
1142 
1143  DerivedTy::bindDerived(cls);
1144  }
1145 
1146  /// Implemented by derived classes to add methods to the Python subclass.
1147  static void bindDerived(ClassTy &m) {}
1148 };
1149 
1150 class PyStringAttribute : public PyConcreteAttribute<PyStringAttribute> {
1151 public:
1153  static constexpr const char *pyClassName = "StringAttr";
1157 
1158  static void bindDerived(ClassTy &c);
1159 };
1160 
1161 /// Wrapper around the generic MlirValue.
1162 /// Values are managed completely by the operation that resulted in their
1163 /// definition. For op result value, this is the operation that defines the
1164 /// value. For block argument values, this is the operation that contains the
1165 /// block to which the value is an argument (blocks cannot be detached in Python
1166 /// bindings so such operation always exists).
1167 class PyValue {
1168 public:
1169  // The virtual here is "load bearing" in that it enables RTTI
1170  // for PyConcreteValue CRTP classes that support maybeDownCast.
1171  // See PyValue::maybeDownCast.
1172  virtual ~PyValue() = default;
1173  PyValue(PyOperationRef parentOperation, MlirValue value)
1174  : parentOperation(std::move(parentOperation)), value(value) {}
1175  operator MlirValue() const { return value; }
1176 
1177  MlirValue get() { return value; }
1178  PyOperationRef &getParentOperation() { return parentOperation; }
1179 
1180  void checkValid() { return parentOperation->checkValid(); }
1181 
1182  /// Gets a capsule wrapping the void* within the MlirValue.
1183  nanobind::object getCapsule();
1184 
1185  nanobind::object maybeDownCast();
1186 
1187  /// Creates a PyValue from the MlirValue wrapped by a capsule. Ownership of
1188  /// the underlying MlirValue is still tied to the owning operation.
1189  static PyValue createFromCapsule(nanobind::object capsule);
1190 
1191 private:
1192  PyOperationRef parentOperation;
1193  MlirValue value;
1194 };
1195 
1196 /// Wrapper around MlirAffineExpr. Affine expressions are owned by the context.
1198 public:
1199  PyAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr)
1200  : BaseContextObject(std::move(contextRef)), affineExpr(affineExpr) {}
1201  bool operator==(const PyAffineExpr &other) const;
1202  operator MlirAffineExpr() const { return affineExpr; }
1203  MlirAffineExpr get() const { return affineExpr; }
1204 
1205  /// Gets a capsule wrapping the void* within the MlirAffineExpr.
1206  nanobind::object getCapsule();
1207 
1208  /// Creates a PyAffineExpr from the MlirAffineExpr wrapped by a capsule.
1209  /// Note that PyAffineExpr instances are uniqued, so the returned object
1210  /// may be a pre-existing object. Ownership of the underlying MlirAffineExpr
1211  /// is taken by calling this function.
1212  static PyAffineExpr createFromCapsule(const nanobind::object &capsule);
1213 
1214  PyAffineExpr add(const PyAffineExpr &other) const;
1215  PyAffineExpr mul(const PyAffineExpr &other) const;
1216  PyAffineExpr floorDiv(const PyAffineExpr &other) const;
1217  PyAffineExpr ceilDiv(const PyAffineExpr &other) const;
1218  PyAffineExpr mod(const PyAffineExpr &other) const;
1219 
1220 private:
1221  MlirAffineExpr affineExpr;
1222 };
1223 
1225 public:
1226  PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap)
1227  : BaseContextObject(std::move(contextRef)), affineMap(affineMap) {}
1228  bool operator==(const PyAffineMap &other) const;
1229  operator MlirAffineMap() const { return affineMap; }
1230  MlirAffineMap get() const { return affineMap; }
1231 
1232  /// Gets a capsule wrapping the void* within the MlirAffineMap.
1233  nanobind::object getCapsule();
1234 
1235  /// Creates a PyAffineMap from the MlirAffineMap wrapped by a capsule.
1236  /// Note that PyAffineMap instances are uniqued, so the returned object
1237  /// may be a pre-existing object. Ownership of the underlying MlirAffineMap
1238  /// is taken by calling this function.
1239  static PyAffineMap createFromCapsule(const nanobind::object &capsule);
1240 
1241 private:
1242  MlirAffineMap affineMap;
1243 };
1244 
1246 public:
1247  PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet)
1248  : BaseContextObject(std::move(contextRef)), integerSet(integerSet) {}
1249  bool operator==(const PyIntegerSet &other) const;
1250  operator MlirIntegerSet() const { return integerSet; }
1251  MlirIntegerSet get() const { return integerSet; }
1252 
1253  /// Gets a capsule wrapping the void* within the MlirIntegerSet.
1254  nanobind::object getCapsule();
1255 
1256  /// Creates a PyIntegerSet from the MlirAffineMap wrapped by a capsule.
1257  /// Note that PyIntegerSet instances may be uniqued, so the returned object
1258  /// may be a pre-existing object. Integer sets are owned by the context.
1259  static PyIntegerSet createFromCapsule(const nanobind::object &capsule);
1260 
1261 private:
1262  MlirIntegerSet integerSet;
1263 };
1264 
1265 /// Bindings for MLIR symbol tables.
1267 public:
1268  /// Constructs a symbol table for the given operation.
1269  explicit PySymbolTable(PyOperationBase &operation);
1270 
1271  /// Destroys the symbol table.
1273 
1274  /// Returns the symbol (opview) with the given name, throws if there is no
1275  /// such symbol in the table.
1276  nanobind::object dunderGetItem(const std::string &name);
1277 
1278  /// Removes the given operation from the symbol table and erases it.
1279  void erase(PyOperationBase &symbol);
1280 
1281  /// Removes the operation with the given name from the symbol table and erases
1282  /// it, throws if there is no such symbol in the table.
1283  void dunderDel(const std::string &name);
1284 
1285  /// Inserts the given operation into the symbol table. The operation must have
1286  /// the symbol trait.
1288 
1289  /// Gets and sets the name of a symbol op.
1291  static void setSymbolName(PyOperationBase &symbol, const std::string &name);
1292 
1293  /// Gets and sets the visibility of a symbol op.
1295  static void setVisibility(PyOperationBase &symbol,
1296  const std::string &visibility);
1297 
1298  /// Replaces all symbol uses within an operation. See the API
1299  /// mlirSymbolTableReplaceAllSymbolUses for all caveats.
1300  static void replaceAllSymbolUses(const std::string &oldSymbol,
1301  const std::string &newSymbol,
1302  PyOperationBase &from);
1303 
1304  /// Walks all symbol tables under and including 'from'.
1305  static void walkSymbolTables(PyOperationBase &from, bool allSymUsesVisible,
1306  nanobind::object callback);
1307 
1308  /// Casts the bindings class into the C API structure.
1309  operator MlirSymbolTable() { return symbolTable; }
1310 
1311 private:
1312  PyOperationRef operation;
1313  MlirSymbolTable symbolTable;
1314 };
1315 
1316 /// Custom exception that allows access to error diagnostic information. This is
1317 /// converted to the `ir.MLIRError` python exception when thrown.
1318 struct MLIRError {
1319  MLIRError(llvm::Twine message,
1320  std::vector<PyDiagnostic::DiagnosticInfo> &&errorDiagnostics = {})
1321  : message(message.str()), errorDiagnostics(std::move(errorDiagnostics)) {}
1322  std::string message;
1323  std::vector<PyDiagnostic::DiagnosticInfo> errorDiagnostics;
1324 };
1325 
1326 void populateIRAffine(nanobind::module_ &m);
1327 void populateIRAttributes(nanobind::module_ &m);
1328 void populateIRCore(nanobind::module_ &m);
1329 void populateIRInterfaces(nanobind::module_ &m);
1330 void populateIRTypes(nanobind::module_ &m);
1331 
1332 } // namespace python
1333 } // namespace mlir
1334 
1335 namespace nanobind {
1336 namespace detail {
1337 
1338 template <>
1339 struct type_caster<mlir::python::DefaultingPyMlirContext>
1340  : MlirDefaultingCaster<mlir::python::DefaultingPyMlirContext> {};
1341 template <>
1342 struct type_caster<mlir::python::DefaultingPyLocation>
1343  : MlirDefaultingCaster<mlir::python::DefaultingPyLocation> {};
1344 
1345 } // namespace detail
1346 } // namespace nanobind
1347 
1348 #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:284
PyMlirContextRef & getContext()
Accesses the context reference.
Definition: IRModule.h:292
BaseContextObject(PyMlirContextRef ref)
Definition: IRModule.h:286
Used in function arguments when None should resolve to the current context manager set instance.
Definition: IRModule.h:499
static PyLocation & resolve()
Definition: IRCore.cpp:1064
static constexpr const char kTypeDescription[]
Definition: IRModule.h:502
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:1197
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:1199
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:1203
PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap)
Definition: IRModule.h:1226
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:1230
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:778
PyAsmState(PyOperationBase &operation, bool useLocalScope)
Definition: IRModule.h:789
PyAsmState(MlirValue value, bool useLocalScope)
Definition: IRModule.h:780
PyAsmState(PyAsmState &other)=delete
PyAsmState(const PyAsmState &other)=delete
MlirAsmState get()
Definition: IRModule.h:803
Wrapper around the generic MlirAttribute.
Definition: IRModule.h:1008
static PyAttribute createFromCapsule(const nanobind::object &capsule)
Creates a PyAttribute from the MlirAttribute wrapped by a capsule.
Definition: IRCore.cpp:2135
PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
Definition: IRModule.h:1010
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirAttribute.
Definition: IRCore.cpp:2131
nanobind::object maybeDownCast()
Definition: IRCore.cpp:2143
MlirAttribute get() const
Definition: IRModule.h:1014
bool operator==(const PyAttribute &other) const
Definition: IRCore.cpp:2127
Wrapper around an MlirBlock.
Definition: IRModule.h:813
MlirBlock get()
Definition: IRModule.h:820
PyOperationRef & getParentOperation()
Definition: IRModule.h:821
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirBlock.
Definition: IRCore.cpp:332
PyBlock(PyOperationRef parentOperation, MlirBlock block)
Definition: IRModule.h:815
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:1147
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:380
PyDiagnosticHandler(MlirContext context, nanobind::object callback)
Definition: IRCore.cpp:941
nanobind::object contextEnter()
Definition: IRModule.h:391
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:392
Python class mirroring the C MlirDiagnostic struct.
Definition: IRModule.h:330
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:332
MlirDiagnosticSeverity getSeverity()
Definition: IRCore.cpp:965
Wrapper around an MlirDialect.
Definition: IRModule.h:435
PyDialectDescriptor(PyMlirContextRef contextRef, MlirDialect dialect)
Definition: IRModule.h:437
Wrapper around an MlirDialectRegistry.
Definition: IRModule.h:472
PyDialectRegistry(PyDialectRegistry &&other) noexcept
Definition: IRModule.h:481
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:487
PyDialectRegistry(MlirDialectRegistry registry)
Definition: IRModule.h:475
User-level dialect object.
Definition: IRModule.h:459
PyDialect(nanobind::object descriptor)
Definition: IRModule.h:461
nanobind::object getDescriptor()
Definition: IRModule.h:463
User-level object for accessing dialects with dotted syntax such as: ctx.dialect.std.
Definition: IRModule.h:448
PyDialects(PyMlirContextRef contextRef)
Definition: IRModule.h:450
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:39
An insertion point maintains a pointer to a Block and a reference operation.
Definition: IRModule.h:837
static PyInsertionPoint atBlockTerminator(PyBlock &block)
Shortcut to create an insertion point before the block terminator.
Definition: IRCore.cpp:2091
static PyInsertionPoint atBlockBegin(PyBlock &block)
Shortcut to create an insertion point at the beginning of the block.
Definition: IRCore.cpp:2078
void contextExit(const nanobind::object &excType, const nanobind::object &excVal, const nanobind::object &excTb)
Definition: IRCore.cpp:2117
static PyInsertionPoint after(PyOperationBase &op)
Shortcut to create an insertion point to the node after the specified operation.
Definition: IRCore.cpp:2100
PyInsertionPoint(const PyBlock &block)
Creates an insertion point positioned after the last operation in the block, but still inside the blo...
Definition: IRCore.cpp:2043
void insert(PyOperationBase &operationBase)
Inserts an operation.
Definition: IRCore.cpp:2052
std::optional< PyOperationRef > & getRefOperation()
Definition: IRModule.h:865
static nanobind::object contextEnter(nanobind::object insertionPoint)
Enter and exit the context manager.
Definition: IRCore.cpp:2113
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:1251
bool operator==(const PyIntegerSet &other) const
Definition: IRAffine.cpp:495
PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet)
Definition: IRModule.h:1247
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirIntegerSet.
Definition: IRAffine.cpp:499
Wrapper around an MlirLocation.
Definition: IRModule.h:299
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirLocation.
Definition: IRCore.cpp:1042
PyLocation(PyMlirContextRef contextRef, MlirLocation loc)
Definition: IRModule.h:301
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:305
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:2111
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:522
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:525
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:2161
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:723
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:2025
nanobind::object getOperationObject()
Definition: IRModule.h:728
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:1841
PyOpView(const nanobind::object &operationObject)
Definition: IRCore.cpp:2033
PyOperation & getOperation() override
Each must provide access to the raw Operation.
Definition: IRModule.h:726
Base class for PyOperation and PyOpView which exposes the primary, user visible methods for manipulat...
Definition: IRModule.h:552
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:630
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
static nanobind::object createFromCapsule(const nanobind::object &capsule)
Creates a PyOperation from the MlirOperation wrapped by a capsule.
Definition: IRCore.cpp:1398
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:608
PyOperationRef getRef()
Definition: IRModule.h:643
MlirOperation get() const
Definition: IRModule.h:638
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:648
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:690
Wrapper around an MlirRegion.
Definition: IRModule.h:759
PyRegion(PyOperationRef parentOperation, MlirRegion region)
Definition: IRModule.h:761
PyOperationRef & getParentOperation()
Definition: IRModule.h:768
MlirRegion get()
Definition: IRModule.h:767
static constexpr GetTypeIDFunctionTy getTypeIdFunction
Definition: IRModule.h:1155
static constexpr IsAFunctionTy isaFunction
Definition: IRModule.h:1152
static constexpr const char * pyClassName
Definition: IRModule.h:1153
static void bindDerived(ClassTy &c)
Bindings for MLIR symbol tables.
Definition: IRModule.h:1266
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:2296
static void walkSymbolTables(PyOperationBase &from, bool allSymUsesVisible, nanobind::object callback)
Walks all symbol tables under and including 'from'.
Definition: IRCore.cpp:2382
static void replaceAllSymbolUses(const std::string &oldSymbol, const std::string &newSymbol, PyOperationBase &from)
Replaces all symbol uses within an operation.
Definition: IRCore.cpp:2370
static void setVisibility(PyOperationBase &symbol, const std::string &visibility)
Definition: IRCore.cpp:2352
static void setSymbolName(PyOperationBase &symbol, const std::string &name)
Definition: IRCore.cpp:2326
~PySymbolTable()
Destroys the symbol table.
Definition: IRModule.h:1272
PyStringAttribute insert(PyOperationBase &symbol)
Inserts the given operation into the symbol table.
Definition: IRCore.cpp:2301
void erase(PyOperationBase &symbol)
Removes the given operation from the symbol table and erases it.
Definition: IRCore.cpp:2286
PySymbolTable(PyOperationBase &operation)
Constructs a symbol table for the given operation.
Definition: IRCore.cpp:2265
static PyStringAttribute getSymbolName(PyOperationBase &symbol)
Gets and sets the name of a symbol op.
Definition: IRCore.cpp:2313
static PyStringAttribute getVisibility(PyOperationBase &symbol)
Gets and sets the visibility of a symbol op.
Definition: IRCore.cpp:2341
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:2273
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:2211
bool operator==(const PyTypeID &other) const
Definition: IRCore.cpp:2217
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirTypeID.
Definition: IRCore.cpp:2207
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:2177
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:2181
nanobind::object maybeDownCast()
Definition: IRCore.cpp:2189
bool operator==(const PyType &other) const
Definition: IRCore.cpp:2173
Wrapper around the generic MlirValue.
Definition: IRModule.h:1167
PyValue(PyOperationRef parentOperation, MlirValue value)
Definition: IRModule.h:1173
static PyValue createFromCapsule(nanobind::object capsule)
Creates a PyValue from the MlirValue wrapped by a capsule.
Definition: IRCore.cpp:2244
nanobind::object maybeDownCast()
Definition: IRCore.cpp:2229
nanobind::object getCapsule()
Gets a capsule wrapping the void* within the MlirValue.
Definition: IRCore.cpp:2225
virtual ~PyValue()=default
PyOperationRef & getParentOperation()
Definition: IRModule.h:1178
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:844
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:1274
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:1255
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:1293
MlirWalkResult
Operation walk result.
Definition: IR.h:837
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:933
MLIR_CAPI_EXPORTED void mlirSymbolTableDestroy(MlirSymbolTable symbolTable)
Destroys the symbol table created with mlirSymbolTableCreate.
Definition: IR.cpp:1344
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:872
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:511
void populateIRAffine(nanobind::module_ &m)
void populateIRTypes(nanobind::module_ &m)
void populateIRCore(nanobind::module_ &m)
PyObjectRef< PyOperation > PyOperationRef
Definition: IRModule.h:604
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:1318
MLIRError(llvm::Twine message, std::vector< PyDiagnostic::DiagnosticInfo > &&errorDiagnostics={})
Definition: IRModule.h:1319
std::vector< PyDiagnostic::DiagnosticInfo > errorDiagnostics
Definition: IRModule.h:1323
Materialized diagnostic information.
Definition: IRModule.h:342
std::vector< DiagnosticInfo > notes
Definition: IRModule.h:346
RAII object that captures any error diagnostics emitted to the provided context.
Definition: IRModule.h:408
std::vector< PyDiagnostic::DiagnosticInfo > take()
Definition: IRModule.h:418
ErrorCapture(PyMlirContextRef ctx)
Definition: IRModule.h:409