#ifndef MLIR_BINDINGS_PYTHON_IRMODULES_H
#define MLIR_BINDINGS_PYTHON_IRMODULES_H
#include <optional>
#include <sstream>
#include <utility>
#include <vector>
#include "Globals.h"
#include "NanobindUtils.h"
#include "mlir-c/AffineExpr.h"
#include "mlir-c/AffineMap.h"
#include "mlir-c/BuiltinAttributes.h"
#include "mlir-c/Diagnostics.h"
#include "mlir-c/IR.h"
#include "mlir-c/IntegerSet.h"
#include "mlir-c/Transforms.h"
#include "mlir/Bindings/Python/Nanobind.h"
#include "mlir/Bindings/Python/NanobindAdaptors.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/ThreadPool.h"
namespace mlir {
namespace python {
class PyBlock;
class PyDiagnostic;
class PyDiagnosticHandler;
class PyInsertionPoint;
class PyLocation;
class DefaultingPyLocation;
class PyMlirContext;
class DefaultingPyMlirContext;
class PyModule;
class PyOperation;
class PyOperationBase;
class PyType;
class PySymbolTable;
class PyValue;
template <typename T>
class PyObjectRef {
public:
PyObjectRef(T *referrent, nanobind::object object)
: referrent(referrent), object(std::move(object)) {
assert(this->referrent &&
"cannot construct PyObjectRef with null referrent");
assert(this->object && "cannot construct PyObjectRef with null object");
}
PyObjectRef(PyObjectRef &&other) noexcept
: referrent(other.referrent), object(std::move(other.object)) {
other.referrent = nullptr;
assert(!other.object);
}
PyObjectRef(const PyObjectRef &other)
: referrent(other.referrent), object(other.object ) {}
~PyObjectRef() = default;
int getRefCount() {
if (!object)
return 0;
return Py_REFCNT(object.ptr());
}
nanobind::object releaseObject() {
assert(referrent && object);
referrent = nullptr;
auto stolen = std::move(object);
return stolen;
}
T *get() { return referrent; }
T *operator->() {
assert(referrent && object);
return referrent;
}
nanobind::object getObject() {
assert(referrent && object);
return object;
}
operator bool() const { return referrent && object; }
using NBTypedT = nanobind::typed<nanobind::object, T>;
private:
T *referrent;
nanobind::object object;
};
class PyThreadContextEntry {
public:
enum class FrameKind {
Context,
InsertionPoint,
Location,
};
PyThreadContextEntry(FrameKind frameKind, nanobind::object context,
nanobind::object insertionPoint,
nanobind::object location)
: context(std::move(context)), insertionPoint(std::move(insertionPoint)),
location(std::move(location)), frameKind(frameKind) {}
static PyMlirContext *getDefaultContext();
static PyInsertionPoint *getDefaultInsertionPoint();
static PyLocation *getDefaultLocation();
PyMlirContext *getContext();
PyInsertionPoint *getInsertionPoint();
PyLocation *getLocation();
FrameKind getFrameKind() { return frameKind; }
static PyThreadContextEntry *getTopOfStack();
static nanobind::object pushContext(nanobind::object context);
static void popContext(PyMlirContext &context);
static nanobind::object pushInsertionPoint(nanobind::object insertionPoint);
static void popInsertionPoint(PyInsertionPoint &insertionPoint);
static nanobind::object pushLocation(nanobind::object location);
static void popLocation(PyLocation &location);
static std::vector<PyThreadContextEntry> &getStack();
private:
static void push(FrameKind frameKind, nanobind::object context,
nanobind::object insertionPoint, nanobind::object location);
nanobind::object context;
nanobind::object insertionPoint;
nanobind::object location;
FrameKind frameKind;
};
class PyThreadPool {
public:
PyThreadPool() {
ownedThreadPool = std::make_unique<llvm::DefaultThreadPool>();
}
PyThreadPool(const PyThreadPool &) = delete;
PyThreadPool(PyThreadPool &&) = delete;
int getMaxConcurrency() const { return ownedThreadPool->getMaxConcurrency(); }
MlirLlvmThreadPool get() { return wrap(ownedThreadPool.get()); }
std::string _mlir_thread_pool_ptr() const {
std::stringstream ss;
ss << ownedThreadPool.get();
return ss.str();
}
private:
std::unique_ptr<llvm::ThreadPoolInterface> ownedThreadPool;
};
using PyMlirContextRef = PyObjectRef<PyMlirContext>;
class PyMlirContext {
public:
PyMlirContext() = delete;
PyMlirContext(MlirContext context);
PyMlirContext(const PyMlirContext &) = delete;
PyMlirContext(PyMlirContext &&) = delete;
static PyMlirContextRef forContext(MlirContext context);
~PyMlirContext();
MlirContext get() { return context; }
PyMlirContextRef getRef() {
return PyMlirContextRef(this, nanobind::cast(this));
}
nanobind::object getCapsule();
static nanobind::object createFromCapsule(nanobind::object capsule);
static size_t getLiveCount();
size_t getLiveModuleCount();
static nanobind::object contextEnter(nanobind::object context);
void contextExit(const nanobind::object &excType,
const nanobind::object &excVal,
const nanobind::object &excTb);
nanobind::object attachDiagnosticHandler(nanobind::object callback);
void setEmitErrorDiagnostics(bool value) { emitErrorDiagnostics = value; }
bool getEmitErrorDiagnostics() { return emitErrorDiagnostics; }
struct ErrorCapture;
private:
using LiveContextMap = llvm::DenseMap<void *, PyMlirContext *>;
static nanobind::ft_mutex live_contexts_mutex;
static LiveContextMap &getLiveContexts();
using LiveModuleMap =
llvm::DenseMap<const void *, std::pair<nanobind::handle, PyModule *>>;
LiveModuleMap liveModules;
bool emitErrorDiagnostics = false;
MlirContext context;
friend class PyModule;
friend class PyOperation;
};
class DefaultingPyMlirContext
: public Defaulting<DefaultingPyMlirContext, PyMlirContext> {
public:
using Defaulting::Defaulting;
static constexpr const char kTypeDescription[] = "Context";
static PyMlirContext &resolve();
};
class BaseContextObject {
public:
BaseContextObject(PyMlirContextRef ref) : contextRef(std::move(ref)) {
assert(this->contextRef &&
"context object constructed with null context ref");
}
PyMlirContextRef &getContext() { return contextRef; }
private:
PyMlirContextRef contextRef;
};
class PyLocation : public BaseContextObject {
public:
PyLocation(PyMlirContextRef contextRef, MlirLocation loc)
: BaseContextObject(std::move(contextRef)), loc(loc) {}
operator MlirLocation() const { return loc; }
MlirLocation get() const { return loc; }
static nanobind::object contextEnter(nanobind::object location);
void contextExit(const nanobind::object &excType,
const nanobind::object &excVal,
const nanobind::object &excTb);
nanobind::object getCapsule();
static PyLocation createFromCapsule(nanobind::object capsule);
private:
MlirLocation loc;
};
class PyDiagnostic {
public:
PyDiagnostic(MlirDiagnostic diagnostic) : diagnostic(diagnostic) {}
void invalidate();
bool isValid() { return valid; }
MlirDiagnosticSeverity getSeverity();
PyLocation getLocation();
nanobind::str getMessage();
nanobind::tuple getNotes();
struct DiagnosticInfo {
MlirDiagnosticSeverity severity;
PyLocation location;
std::string message;
std::vector<DiagnosticInfo> notes;
};
DiagnosticInfo getInfo();
private:
MlirDiagnostic diagnostic;
void checkValid();
std::optional<nanobind::tuple> materializedNotes;
bool valid = true;
};
class PyDiagnosticHandler {
public:
PyDiagnosticHandler(MlirContext context, nanobind::object callback);
~PyDiagnosticHandler();
bool isAttached() { return registeredID.has_value(); }
bool getHadError() { return hadError; }
void detach();
nanobind::object contextEnter() { return nanobind::cast(this); }
void contextExit(const nanobind::object &excType,
const nanobind::object &excVal,
const nanobind::object &excTb) {
detach();
}
private:
MlirContext context;
nanobind::object callback;
std::optional<MlirDiagnosticHandlerID> registeredID;
bool hadError = false;
friend class PyMlirContext;
};
struct PyMlirContext::ErrorCapture {
ErrorCapture(PyMlirContextRef ctx)
: ctx(ctx), handlerID(mlirContextAttachDiagnosticHandler(
ctx->get(), handler, this,
nullptr)) {}
~ErrorCapture() {
mlirContextDetachDiagnosticHandler(ctx->get(), handlerID);
assert(errors.empty() && "unhandled captured errors");
}
std::vector<PyDiagnostic::DiagnosticInfo> take() {
return std::move(errors);
};
private:
PyMlirContextRef ctx;
MlirDiagnosticHandlerID handlerID;
std::vector<PyDiagnostic::DiagnosticInfo> errors;
static MlirLogicalResult handler(MlirDiagnostic diag, void *userData);
};
class PyDialectDescriptor : public BaseContextObject {
public:
PyDialectDescriptor(PyMlirContextRef contextRef, MlirDialect dialect)
: BaseContextObject(std::move(contextRef)), dialect(dialect) {}
MlirDialect get() { return dialect; }
private:
MlirDialect dialect;
};
class PyDialects : public BaseContextObject {
public:
PyDialects(PyMlirContextRef contextRef)
: BaseContextObject(std::move(contextRef)) {}
MlirDialect getDialectForKey(const std::string &key, bool attrError);
};
class PyDialect {
public:
PyDialect(nanobind::object descriptor) : descriptor(std::move(descriptor)) {}
nanobind::object getDescriptor() { return descriptor; }
private:
nanobind::object descriptor;
};
class PyDialectRegistry {
public:
PyDialectRegistry() : registry(mlirDialectRegistryCreate()) {}
PyDialectRegistry(MlirDialectRegistry registry) : registry(registry) {}
~PyDialectRegistry() {
if (!mlirDialectRegistryIsNull(registry))
mlirDialectRegistryDestroy(registry);
}
PyDialectRegistry(PyDialectRegistry &) = delete;
PyDialectRegistry(PyDialectRegistry &&other) noexcept
: registry(other.registry) {
other.registry = {nullptr};
}
operator MlirDialectRegistry() const { return registry; }
MlirDialectRegistry get() const { return registry; }
nanobind::object getCapsule();
static PyDialectRegistry createFromCapsule(nanobind::object capsule);
private:
MlirDialectRegistry registry;
};
class DefaultingPyLocation
: public Defaulting<DefaultingPyLocation, PyLocation> {
public:
using Defaulting::Defaulting;
static constexpr const char kTypeDescription[] = "Location";
static PyLocation &resolve();
operator MlirLocation() const { return *get(); }
};
class PyModule;
using PyModuleRef = PyObjectRef<PyModule>;
class PyModule : public BaseContextObject {
public:
static PyModuleRef forModule(MlirModule module);
PyModule(PyModule &) = delete;
PyModule(PyMlirContext &&) = delete;
~PyModule();
MlirModule get() { return module; }
PyModuleRef getRef() {
return PyModuleRef(this, nanobind::borrow<nanobind::object>(handle));
}
nanobind::object getCapsule();
static nanobind::object createFromCapsule(nanobind::object capsule);
void clearMlirModule() { module = {nullptr}; }
private:
PyModule(PyMlirContextRef contextRef, MlirModule module);
MlirModule module;
nanobind::handle handle;
};
class PyAsmState;
class PyOperationBase {
public:
virtual ~PyOperationBase() = default;
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);
void print(PyAsmState &state, nanobind::object fileObject, bool binary);
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);
void writeBytecode(const nanobind::object &fileObject,
std::optional<int64_t> bytecodeVersion);
void walk(std::function<MlirWalkResult(MlirOperation)> callback,
MlirWalkOrder walkOrder);
void moveAfter(PyOperationBase &other);
void moveBefore(PyOperationBase &other);
bool isBeforeInBlock(PyOperationBase &other);
bool verify();
virtual PyOperation &getOperation() = 0;
};
class PyOperation;
class PyOpView;
using PyOperationRef = PyObjectRef<PyOperation>;
class PyOperation : public PyOperationBase, public BaseContextObject {
public:
~PyOperation() override;
PyOperation &getOperation() override { return *this; }
static PyOperationRef
forOperation(PyMlirContextRef contextRef, MlirOperation operation,
nanobind::object parentKeepAlive = nanobind::object());
static PyOperationRef
createDetached(PyMlirContextRef contextRef, MlirOperation operation,
nanobind::object parentKeepAlive = nanobind::object());
static PyOperationRef parse(PyMlirContextRef contextRef,
const std::string &sourceStr,
const std::string &sourceName);
void detachFromParent() {
mlirOperationRemoveFromParent(getOperation());
setDetached();
parentKeepAlive = nanobind::object();
}
operator MlirOperation() const { return get(); }
MlirOperation get() const {
checkValid();
return operation;
}
PyOperationRef getRef() {
return PyOperationRef(this, nanobind::borrow<nanobind::object>(handle));
}
bool isAttached() { return attached; }
void setAttached(const nanobind::object &parent = nanobind::object()) {
assert(!attached && "operation already attached");
attached = true;
}
void setDetached() {
assert(attached && "operation already detached");
attached = false;
}
void checkValid() const;
PyBlock getBlock();
std::optional<PyOperationRef> getParentOperation();
nanobind::object getCapsule();
static nanobind::object createFromCapsule(const nanobind::object &capsule);
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);
nanobind::object createOpView();
void erase();
void setInvalid() { valid = false; }
nanobind::object clone(const nanobind::object &ip);
PyOperation(PyMlirContextRef contextRef, MlirOperation operation);
private:
static PyOperationRef createInstance(PyMlirContextRef contextRef,
MlirOperation operation,
nanobind::object parentKeepAlive);
MlirOperation operation;
nanobind::handle handle;
nanobind::object parentKeepAlive;
bool attached = true;
bool valid = true;
friend class PyOperationBase;
friend class PySymbolTable;
};
class PyOpView : public PyOperationBase {
public:
PyOpView(const nanobind::object &operationObject);
PyOperation &getOperation() override { return operation; }
nanobind::object getOperationObject() { return operationObject; }
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);
static nanobind::object constructDerived(const nanobind::object &cls,
const nanobind::object &operation);
private:
PyOperation &operation;
nanobind::object operationObject;
};
class PyRegion {
public:
PyRegion(PyOperationRef parentOperation, MlirRegion region)
: parentOperation(std::move(parentOperation)), region(region) {
assert(!mlirRegionIsNull(region) && "python region cannot be null");
}
operator MlirRegion() const { return region; }
MlirRegion get() { return region; }
PyOperationRef &getParentOperation() { return parentOperation; }
void checkValid() { return parentOperation->checkValid(); }
private:
PyOperationRef parentOperation;
MlirRegion region;
};
class PyAsmState {
public:
PyAsmState(MlirValue value, bool useLocalScope) {
flags = mlirOpPrintingFlagsCreate();
if (useLocalScope)
mlirOpPrintingFlagsUseLocalScope(flags);
state = mlirAsmStateCreateForValue(value, flags);
}
PyAsmState(PyOperationBase &operation, bool useLocalScope) {
flags = mlirOpPrintingFlagsCreate();
if (useLocalScope)
mlirOpPrintingFlagsUseLocalScope(flags);
state =
mlirAsmStateCreateForOperation(operation.getOperation().get(), flags);
}
~PyAsmState() { mlirOpPrintingFlagsDestroy(flags); }
PyAsmState(PyAsmState &other) = delete;
PyAsmState(const PyAsmState &other) = delete;
MlirAsmState get() { return state; }
private:
MlirAsmState state;
MlirOpPrintingFlags flags;
};
class PyBlock {
public:
PyBlock(PyOperationRef parentOperation, MlirBlock block)
: parentOperation(std::move(parentOperation)), block(block) {
assert(!mlirBlockIsNull(block) && "python block cannot be null");
}
MlirBlock get() { return block; }
PyOperationRef &getParentOperation() { return parentOperation; }
void checkValid() { return parentOperation->checkValid(); }
nanobind::object getCapsule();
private:
PyOperationRef parentOperation;
MlirBlock block;
};
class PyInsertionPoint {
public:
PyInsertionPoint(const PyBlock &block);
PyInsertionPoint(PyOperationBase &beforeOperationBase);
PyInsertionPoint(PyOperationRef beforeOperationRef);
static PyInsertionPoint atBlockBegin(PyBlock &block);
static PyInsertionPoint atBlockTerminator(PyBlock &block);
static PyInsertionPoint after(PyOperationBase &op);
void insert(PyOperationBase &operationBase);
static nanobind::object contextEnter(nanobind::object insertionPoint);
void contextExit(const nanobind::object &excType,
const nanobind::object &excVal,
const nanobind::object &excTb);
PyBlock &getBlock() { return block; }
std::optional<PyOperationRef> &getRefOperation() { return refOperation; }
private:
PyInsertionPoint(PyBlock block, std::optional<PyOperationRef> refOperation)
: refOperation(std::move(refOperation)), block(std::move(block)) {}
std::optional<PyOperationRef> refOperation;
PyBlock block;
};
class PyType : public BaseContextObject {
public:
PyType(PyMlirContextRef contextRef, MlirType type)
: BaseContextObject(std::move(contextRef)), type(type) {}
bool operator==(const PyType &other) const;
operator MlirType() const { return type; }
MlirType get() const { return type; }
nanobind::object getCapsule();
static PyType createFromCapsule(nanobind::object capsule);
nanobind::object maybeDownCast();
private:
MlirType type;
};
class PyTypeID {
public:
PyTypeID(MlirTypeID typeID) : typeID(typeID) {}
bool operator==(const PyTypeID &other) const;
operator MlirTypeID() const { return typeID; }
MlirTypeID get() { return typeID; }
nanobind::object getCapsule();
static PyTypeID createFromCapsule(nanobind::object capsule);
private:
MlirTypeID typeID;
};
template <typename DerivedTy, typename BaseTy = PyType>
class PyConcreteType : public BaseTy {
public:
using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
using IsAFunctionTy = bool (*)(MlirType);
using GetTypeIDFunctionTy = MlirTypeID (*)();
static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
PyConcreteType() = default;
PyConcreteType(PyMlirContextRef contextRef, MlirType t)
: BaseTy(std::move(contextRef), t) {}
PyConcreteType(PyType &orig)
: PyConcreteType(orig.getContext(), castFrom(orig)) {}
static MlirType castFrom(PyType &orig) {
if (!DerivedTy::isaFunction(orig)) {
auto origRepr =
nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
throw nanobind::value_error((llvm::Twine("Cannot cast type to ") +
DerivedTy::pyClassName + " (from " +
origRepr + ")")
.str()
.c_str());
}
return orig;
}
static void bind(nanobind::module_ &m) {
auto cls = ClassTy(m, DerivedTy::pyClassName);
cls.def(nanobind::init<PyType &>(), nanobind::keep_alive<0, 1>(),
nanobind::arg("cast_from_type"));
cls.def_static(
"isinstance",
[](PyType &otherType) -> bool {
return DerivedTy::isaFunction(otherType);
},
nanobind::arg("other"));
cls.def_prop_ro_static(
"static_typeid",
[](nanobind::object & ) {
if (DerivedTy::getTypeIdFunction)
return PyTypeID(DerivedTy::getTypeIdFunction());
throw nanobind::attribute_error(
(DerivedTy::pyClassName + llvm::Twine(" has no typeid."))
.str()
.c_str());
},
nanobind::sig("def static_typeid(/) -> TypeID"));
cls.def_prop_ro("typeid", [](PyType &self) {
return nanobind::cast<PyTypeID>(nanobind::cast(self).attr("typeid"));
});
cls.def("__repr__", [](DerivedTy &self) {
PyPrintAccumulator printAccum;
printAccum.parts.append(DerivedTy::pyClassName);
printAccum.parts.append("(");
mlirTypePrint(self, printAccum.getCallback(), printAccum.getUserData());
printAccum.parts.append(")");
return printAccum.join();
});
if (DerivedTy::getTypeIdFunction) {
PyGlobals::get().registerTypeCaster(
DerivedTy::getTypeIdFunction(),
nanobind::cast<nanobind::callable>(nanobind::cpp_function(
[](PyType pyType) -> DerivedTy { return pyType; })));
}
DerivedTy::bindDerived(cls);
}
static void bindDerived(ClassTy &m) {}
};
class PyAttribute : public BaseContextObject {
public:
PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
: BaseContextObject(std::move(contextRef)), attr(attr) {}
bool operator==(const PyAttribute &other) const;
operator MlirAttribute() const { return attr; }
MlirAttribute get() const { return attr; }
nanobind::object getCapsule();
static PyAttribute createFromCapsule(const nanobind::object &capsule);
nanobind::object maybeDownCast();
private:
MlirAttribute attr;
};
class PyNamedAttribute {
public:
PyNamedAttribute(MlirAttribute attr, std::string ownedName);
MlirNamedAttribute namedAttr;
private:
std::unique_ptr<std::string> ownedName;
};
template <typename DerivedTy, typename BaseTy = PyAttribute>
class PyConcreteAttribute : public BaseTy {
public:
using ClassTy = nanobind::class_<DerivedTy, BaseTy>;
using IsAFunctionTy = bool (*)(MlirAttribute);
using GetTypeIDFunctionTy = MlirTypeID (*)();
static constexpr GetTypeIDFunctionTy getTypeIdFunction = nullptr;
PyConcreteAttribute() = default;
PyConcreteAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
: BaseTy(std::move(contextRef), attr) {}
PyConcreteAttribute(PyAttribute &orig)
: PyConcreteAttribute(orig.getContext(), castFrom(orig)) {}
static MlirAttribute castFrom(PyAttribute &orig) {
if (!DerivedTy::isaFunction(orig)) {
auto origRepr =
nanobind::cast<std::string>(nanobind::repr(nanobind::cast(orig)));
throw nanobind::value_error((llvm::Twine("Cannot cast attribute to ") +
DerivedTy::pyClassName + " (from " +
origRepr + ")")
.str()
.c_str());
}
return orig;
}
static void bind(nanobind::module_ &m, PyType_Slot *slots = nullptr) {
ClassTy cls;
if (slots) {
cls = ClassTy(m, DerivedTy::pyClassName, nanobind::type_slots(slots));
} else {
cls = ClassTy(m, DerivedTy::pyClassName);
}
cls.def(nanobind::init<PyAttribute &>(), nanobind::keep_alive<0, 1>(),
nanobind::arg("cast_from_attr"));
cls.def_static(
"isinstance",
[](PyAttribute &otherAttr) -> bool {
return DerivedTy::isaFunction(otherAttr);
},
nanobind::arg("other"));
cls.def_prop_ro(
"type",
[](PyAttribute &attr) -> nanobind::typed<nanobind::object, PyType> {
return PyType(attr.getContext(), mlirAttributeGetType(attr))
.maybeDownCast();
});
cls.def_prop_ro_static(
"static_typeid",
[](nanobind::object & ) -> PyTypeID {
if (DerivedTy::getTypeIdFunction)
return PyTypeID(DerivedTy::getTypeIdFunction());
throw nanobind::attribute_error(
(DerivedTy::pyClassName + llvm::Twine(" has no typeid."))
.str()
.c_str());
},
nanobind::sig("def static_typeid(/) -> TypeID"));
cls.def_prop_ro("typeid", [](PyAttribute &self) {
return nanobind::cast<PyTypeID>(nanobind::cast(self).attr("typeid"));
});
cls.def("__repr__", [](DerivedTy &self) {
PyPrintAccumulator printAccum;
printAccum.parts.append(DerivedTy::pyClassName);
printAccum.parts.append("(");
mlirAttributePrint(self, printAccum.getCallback(),
printAccum.getUserData());
printAccum.parts.append(")");
return printAccum.join();
});
if (DerivedTy::getTypeIdFunction) {
PyGlobals::get().registerTypeCaster(
DerivedTy::getTypeIdFunction(),
nanobind::cast<nanobind::callable>(
nanobind::cpp_function([](PyAttribute pyAttribute) -> DerivedTy {
return pyAttribute;
})));
}
DerivedTy::bindDerived(cls);
}
static void bindDerived(ClassTy &m) {}
};
class PyStringAttribute : public PyConcreteAttribute<PyStringAttribute> {
public:
static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAString;
static constexpr const char *pyClassName = "StringAttr";
using PyConcreteAttribute::PyConcreteAttribute;
static constexpr GetTypeIDFunctionTy getTypeIdFunction =
mlirStringAttrGetTypeID;
static void bindDerived(ClassTy &c);
};
class PyValue {
public:
virtual ~PyValue() = default;
PyValue(PyOperationRef parentOperation, MlirValue value)
: parentOperation(std::move(parentOperation)), value(value) {}
operator MlirValue() const { return value; }
MlirValue get() { return value; }
PyOperationRef &getParentOperation() { return parentOperation; }
void checkValid() { return parentOperation->checkValid(); }
nanobind::object getCapsule();
nanobind::object maybeDownCast();
static PyValue createFromCapsule(nanobind::object capsule);
private:
PyOperationRef parentOperation;
MlirValue value;
};
class PyAffineExpr : public BaseContextObject {
public:
PyAffineExpr(PyMlirContextRef contextRef, MlirAffineExpr affineExpr)
: BaseContextObject(std::move(contextRef)), affineExpr(affineExpr) {}
bool operator==(const PyAffineExpr &other) const;
operator MlirAffineExpr() const { return affineExpr; }
MlirAffineExpr get() const { return affineExpr; }
nanobind::object getCapsule();
static PyAffineExpr createFromCapsule(const nanobind::object &capsule);
PyAffineExpr add(const PyAffineExpr &other) const;
PyAffineExpr mul(const PyAffineExpr &other) const;
PyAffineExpr floorDiv(const PyAffineExpr &other) const;
PyAffineExpr ceilDiv(const PyAffineExpr &other) const;
PyAffineExpr mod(const PyAffineExpr &other) const;
private:
MlirAffineExpr affineExpr;
};
class PyAffineMap : public BaseContextObject {
public:
PyAffineMap(PyMlirContextRef contextRef, MlirAffineMap affineMap)
: BaseContextObject(std::move(contextRef)), affineMap(affineMap) {}
bool operator==(const PyAffineMap &other) const;
operator MlirAffineMap() const { return affineMap; }
MlirAffineMap get() const { return affineMap; }
nanobind::object getCapsule();
static PyAffineMap createFromCapsule(const nanobind::object &capsule);
private:
MlirAffineMap affineMap;
};
class PyIntegerSet : public BaseContextObject {
public:
PyIntegerSet(PyMlirContextRef contextRef, MlirIntegerSet integerSet)
: BaseContextObject(std::move(contextRef)), integerSet(integerSet) {}
bool operator==(const PyIntegerSet &other) const;
operator MlirIntegerSet() const { return integerSet; }
MlirIntegerSet get() const { return integerSet; }
nanobind::object getCapsule();
static PyIntegerSet createFromCapsule(const nanobind::object &capsule);
private:
MlirIntegerSet integerSet;
};
class PySymbolTable {
public:
explicit PySymbolTable(PyOperationBase &operation);
~PySymbolTable() { mlirSymbolTableDestroy(symbolTable); }
nanobind::object dunderGetItem(const std::string &name);
void erase(PyOperationBase &symbol);
void dunderDel(const std::string &name);
PyStringAttribute insert(PyOperationBase &symbol);
static PyStringAttribute getSymbolName(PyOperationBase &symbol);
static void setSymbolName(PyOperationBase &symbol, const std::string &name);
static PyStringAttribute getVisibility(PyOperationBase &symbol);
static void setVisibility(PyOperationBase &symbol,
const std::string &visibility);
static void replaceAllSymbolUses(const std::string &oldSymbol,
const std::string &newSymbol,
PyOperationBase &from);
static void walkSymbolTables(PyOperationBase &from, bool allSymUsesVisible,
nanobind::object callback);
operator MlirSymbolTable() { return symbolTable; }
private:
PyOperationRef operation;
MlirSymbolTable symbolTable;
};
struct MLIRError {
MLIRError(llvm::Twine message,
std::vector<PyDiagnostic::DiagnosticInfo> &&errorDiagnostics = {})
: message(message.str()), errorDiagnostics(std::move(errorDiagnostics)) {}
std::string message;
std::vector<PyDiagnostic::DiagnosticInfo> errorDiagnostics;
};
void populateIRAffine(nanobind::module_ &m);
void populateIRAttributes(nanobind::module_ &m);
void populateIRCore(nanobind::module_ &m);
void populateIRInterfaces(nanobind::module_ &m);
void populateIRTypes(nanobind::module_ &m);
}
}
namespace nanobind {
namespace detail {
template <>
struct type_caster<mlir::python::DefaultingPyMlirContext>
: MlirDefaultingCaster<mlir::python::DefaultingPyMlirContext> {};
template <>
struct type_caster<mlir::python::DefaultingPyLocation>
: MlirDefaultingCaster<mlir::python::DefaultingPyLocation> {};
}
}
#endif