diff --git a/mlir/lib/Bindings/Python/BindingModules.h b/mlir/lib/Bindings/Python/BindingModules.h new file mode 100644 --- /dev/null +++ b/mlir/lib/Bindings/Python/BindingModules.h @@ -0,0 +1,18 @@ +//===- BindingModules.h - Submodules of pybind module ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_PYTHON_BINDINGS_MODULES_H +#define MLIR_PYTHON_BINDINGS_MODULES_H + +#include +namespace py = pybind11; + +void populateIRSubmodule(py::module m); +void populateRegistrationSubmodule(py::module m); + +#endif // MLIR_PYTHON_BINDINGS_MODULES_H diff --git a/mlir/lib/Bindings/Python/BindingModules.cpp b/mlir/lib/Bindings/Python/BindingModules.cpp new file mode 100644 --- /dev/null +++ b/mlir/lib/Bindings/Python/BindingModules.cpp @@ -0,0 +1,151 @@ +//===- BindingModules.cpp - Submodules of pybind module -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "BindingModules.h" +#include "mlir-c/IR.h" +#include "mlir-c/Registration.h" +#include "llvm/ADT/SmallVector.h" +#include + +using namespace pybind11::literals; + +// Implementation of IR submodule. +void populateIRSubmodule(py::module m) { + /*==========================================================================*/ + /* Context bindings. */ + /*==========================================================================*/ + py::class_(m, "MlirContext").def(py::init([]() -> MlirContext { + return mlirContextCreate(); + })); + + /*==========================================================================*/ + /* Location bindings. */ + /*==========================================================================*/ + py::class_(m, "MlirLocation") + .def(py::init([](MlirContext context, const char *filename, unsigned line, + unsigned col) -> MlirLocation { + return mlirLocationFileLineColGet(context, filename, line, col); + })) + .def(py::init([](MlirContext context) -> MlirLocation { + return mlirLocationUnknownGet(context); + })); + + /*==========================================================================*/ + /* Module bindings. */ + /*==========================================================================*/ + py::class_(m, "MlirModule") + .def(py::init([](MlirLocation location) -> MlirModule { + return mlirModuleCreateEmpty(location); + })) + .def(py::init([](MlirContext context, const char *module) -> MlirModule { + return mlirModuleCreateParse(context, module); + })) + .def_property_readonly("operation", &mlirModuleGetOperation); + + /*==========================================================================*/ + /* Operation state bindings. + /* + /* The implementation of operation state bindings is currently problematic. + /* As for MlirOperationState, the operation state struct in C API, there are + /* two binding method: + /* (1) Binding the struct as a Python class. + /* (2) Mapping the struct as a Python dict. + /* The former method will cause ownership problems. The lifetime of the raw + /* pointer should be noticed, which may lead to memory leak. Currently trying + /* the latter one, which makes the implementation more complicated but more + /* python compatible. + /*==========================================================================*/ + + /*==========================================================================*/ + /* Operation bindings. */ + /*==========================================================================*/ + py::class_(m, "MlirOperation") + .def(py::init([](const MlirOperationState *state) -> MlirOperation { + return mlirOperationCreate(state); + })) + .def_property_readonly("is_null", &mlirOperationIsNull) + .def_property_readonly("regions_num", &mlirOperationGetNumRegions) + .def("get_region", &mlirOperationGetRegion) + .def_property_readonly("next_in_block", &mlirOperationGetNextInBlock) + .def_property_readonly("operands_num", &mlirOperationGetNumOperands) + .def("get_operand", &mlirOperationGetOperand) + .def_property_readonly("results_num", &mlirOperationGetNumResults) + .def("get_result", &mlirOperationGetResult) + .def_property_readonly("successors_num", &mlirOperationGetNumSuccessors) + .def("get_successor", &mlirOperationGetSuccessor) + .def_property_readonly("attributes_num", &mlirOperationGetNumAttributes) + .def("get_attribute", &mlirOperationGetAttribute) + .def("get_attribute_by_name", &mlirOperationGetAttributeByName) + .def("dump", &mlirOperationDump); + + /*==========================================================================*/ + /* Block bindings. */ + /*==========================================================================*/ + py::class_(m, "MlirBlock") + .def(py::init([](unsigned nArgs, MlirType *args) -> MlirBlock { + return mlirBlockCreate(nArgs, args); + })) + .def_property_readonly("is_null", &mlirBlockIsNull) + .def_property_readonly("next_in_region", &mlirBlockGetNextInRegion) + .def_property_readonly("first_operation", &mlirBlockGetFirstOperation) + .def("append_owned_operation", &mlirBlockAppendOwnedOperation) + .def("insert_owned_operation", &mlirBlockInsertOwnedOperation) + .def_property_readonly("arguments_num", &mlirBlockGetNumArguments) + .def("get_argument", &mlirBlockGetArgument); + + /*==========================================================================*/ + /* Region bindings. */ + /*==========================================================================*/ + py::class_(m, "MlirRegion") + .def(py::init([]() -> MlirRegion { return mlirRegionCreate(); })) + .def_property_readonly("is_null", &mlirRegionIsNull) + .def_property_readonly("first_block", &mlirRegionGetFirstBlock) + .def("append_owned_block", &mlirRegionAppendOwnedBlock) + .def("insert_owned_block", &mlirRegionInsertOwnedBlock); + + /*==========================================================================*/ + /* Value bindings. */ + /*==========================================================================*/ + py::class_(m, "MlirValue") + .def_property_readonly("type", &mlirValueGetType); + + /*==========================================================================*/ + /* Type bindings. */ + /*==========================================================================*/ + py::class_(m, "MlirType") + .def(py::init([](MlirContext context, const char *type) -> MlirType { + return mlirTypeParseGet(context, type); + })) + .def("dump", &mlirTypeDump); + + /*==========================================================================*/ + /* Attribute bindings. */ + /*==========================================================================*/ + py::class_(m, "MlirAttribute") + .def(py::init([](MlirContext context, const char *attr) -> MlirAttribute { + return mlirAttributeParseGet(context, attr); + })) + .def("dump", &mlirAttributeDump); + + /*==========================================================================*/ + /* Named Attribute bindings. + /* + /* Mapping the MlirNamedAttribute struct to the Python tuple. + /* When the attribute is added to operation state, the tuple should be + /* unpacked and the element should be cast to specific type. + /*==========================================================================*/ + m.def("named_attribute_tuple", + [](const char *name, MlirAttribute attr) -> py::tuple { + return py::make_tuple(name, attr); + }); +} + +// Implementation of registration submodule. +void populateRegistrationSubmodule(py::module m) { + m.def("register_all_dialects", &mlirRegisterAllDialects); +} diff --git a/mlir/lib/Bindings/Python/CMakeLists.txt b/mlir/lib/Bindings/Python/CMakeLists.txt --- a/mlir/lib/Bindings/Python/CMakeLists.txt +++ b/mlir/lib/Bindings/Python/CMakeLists.txt @@ -19,6 +19,7 @@ # exceptions). add_library(MLIRBindingsPythonExtension ${PYEXT_LINK_MODE} MainModule.cpp + BindingModules.cpp ) target_include_directories(MLIRBindingsPythonExtension PRIVATE @@ -66,5 +67,7 @@ target_link_libraries(MLIRBindingsPythonExtension PRIVATE MLIRIR + MLIRCAPIIR + MLIRCAPIRegistration ${PYEXT_LIBADD} ) diff --git a/mlir/lib/Bindings/Python/MainModule.cpp b/mlir/lib/Bindings/Python/MainModule.cpp --- a/mlir/lib/Bindings/Python/MainModule.cpp +++ b/mlir/lib/Bindings/Python/MainModule.cpp @@ -10,6 +10,7 @@ #include +#include "BindingModules.h" #include "mlir/IR/MLIRContext.h" using namespace mlir; @@ -24,4 +25,13 @@ return std::make_tuple(std::string("From the native module"), context.isMultithreadingEnabled()); }); + + // Define and populate IR submodule. + auto irModule = m.def_submodule("ir", "MLIR IR Bindings"); + populateIRSubmodule(irModule); + + // Define and populate registration submodule. + auto registrationModule = + m.def_submodule("registration", "MLIR Registration Bindings"); + populateRegistrationSubmodule(registrationModule); } diff --git a/mlir/test/Bindings/Python/ir_test.py b/mlir/test/Bindings/Python/ir_test.py new file mode 100644 --- /dev/null +++ b/mlir/test/Bindings/Python/ir_test.py @@ -0,0 +1,11 @@ +# RUN: %PYTHON %s | FileCheck %s + +import mlir + +mlir.registration.register_all_dialects() +ctx = mlir.ir.MlirContext() +location = mlir.ir.MlirLocation(ctx) +moduleOp = mlir.ir.MlirModule(location) +module = moduleOp.operation +print(module.is_null) +# CHECK: 0