//===- DialectLLVM.cpp - Pybind module for LLVM dialect API support -------===// // // 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 #include "mlir-c/Dialect/LLVM.h" #include "mlir-c/IR.h" #include "mlir-c/Support.h" #include "mlir-c/Target/LLVMIR.h" #include "mlir/Bindings/Python/Diagnostics.h" #include "mlir/Bindings/Python/IRCore.h" #include "mlir/Bindings/Python/Nanobind.h" #include "mlir/Bindings/Python/NanobindAdaptors.h" namespace nb = nanobind; using namespace nanobind::literals; using namespace mlir; using namespace mlir::python::nanobind_adaptors; namespace mlir { namespace python { namespace MLIR_BINDINGS_PYTHON_DOMAIN { namespace llvm { //===--------------------------------------------------------------------===// // StructType //===--------------------------------------------------------------------===// struct StructType : PyConcreteType { static constexpr IsAFunctionTy isaFunction = mlirTypeIsALLVMStructType; static constexpr GetTypeIDFunctionTy getTypeIdFunction = mlirLLVMStructTypeGetTypeID; static constexpr const char *pyClassName = "StructType"; static inline const MlirStringRef name = mlirLLVMStructTypeGetName(); using Base::Base; static void bindDerived(ClassTy &c) { c.def_static( "get_literal", [](const std::vector &elements, bool packed, DefaultingPyLocation loc, DefaultingPyMlirContext context) { python::CollectDiagnosticsToStringScope scope( mlirLocationGetContext(loc)); std::vector elements_(elements.size()); std::copy(elements.begin(), elements.end(), elements_.begin()); MlirType type = mlirLLVMStructTypeLiteralGetChecked( loc, elements.size(), elements_.data(), packed); if (mlirTypeIsNull(type)) { throw nb::value_error(scope.takeMessage().c_str()); } return StructType(context->getRef(), type); }, "elements"_a, nb::kw_only(), "packed"_a = false, "loc"_a = nb::none(), "context"_a = nb::none()); c.def_static( "get_literal_unchecked", [](const std::vector &elements, bool packed, DefaultingPyMlirContext context) { python::CollectDiagnosticsToStringScope scope(context.get()->get()); std::vector elements_(elements.size()); std::copy(elements.begin(), elements.end(), elements_.begin()); MlirType type = mlirLLVMStructTypeLiteralGet( context.get()->get(), elements.size(), elements_.data(), packed); if (mlirTypeIsNull(type)) { throw nb::value_error(scope.takeMessage().c_str()); } return StructType(context->getRef(), type); }, "elements"_a, nb::kw_only(), "packed"_a = false, "context"_a = nb::none()); c.def_static( "get_identified", [](const std::string &name, DefaultingPyMlirContext context) { return StructType(context->getRef(), mlirLLVMStructTypeIdentifiedGet( context.get()->get(), mlirStringRefCreate(name.data(), name.size()))); }, "name"_a, nb::kw_only(), "context"_a = nb::none()); c.def_static( "get_opaque", [](const std::string &name, DefaultingPyMlirContext context) { return StructType(context->getRef(), mlirLLVMStructTypeOpaqueGet( context.get()->get(), mlirStringRefCreate(name.data(), name.size()))); }, "name"_a, "context"_a = nb::none()); c.def( "set_body", [](const StructType &self, const std::vector &elements, bool packed) { std::vector elements_(elements.size()); std::copy(elements.begin(), elements.end(), elements_.begin()); MlirLogicalResult result = mlirLLVMStructTypeSetBody( self, elements.size(), elements_.data(), packed); if (!mlirLogicalResultIsSuccess(result)) { throw nb::value_error( "Struct body already set to different content."); } }, "elements"_a, nb::kw_only(), "packed"_a = false); c.def_static( "new_identified", [](const std::string &name, const std::vector &elements, bool packed, DefaultingPyMlirContext context) { std::vector elements_(elements.size()); std::copy(elements.begin(), elements.end(), elements_.begin()); return StructType(context->getRef(), mlirLLVMStructTypeIdentifiedNewGet( context.get()->get(), mlirStringRefCreate(name.data(), name.length()), elements.size(), elements_.data(), packed)); }, "name"_a, "elements"_a, nb::kw_only(), "packed"_a = false, "context"_a = nb::none()); c.def_prop_ro( "name", [](const StructType &type) -> std::optional { if (mlirLLVMStructTypeIsLiteral(type)) return std::nullopt; MlirStringRef stringRef = mlirLLVMStructTypeGetIdentifier(type); return std::string(stringRef.data, stringRef.length); }); c.def_prop_ro("body", [](const StructType &type) -> nb::object { // Don't crash in absence of a body. if (mlirLLVMStructTypeIsOpaque(type)) return nb::none(); nb::list body; for (intptr_t i = 0, e = mlirLLVMStructTypeGetNumElementTypes(type); i < e; ++i) { body.append(mlirLLVMStructTypeGetElementType(type, i)); } return body; }); c.def_prop_ro("packed", [](const StructType &type) { return mlirLLVMStructTypeIsPacked(type); }); c.def_prop_ro("opaque", [](const StructType &type) { return mlirLLVMStructTypeIsOpaque(type); }); } }; //===--------------------------------------------------------------------===// // PointerType //===--------------------------------------------------------------------===// struct PointerType : PyConcreteType { static constexpr IsAFunctionTy isaFunction = mlirTypeIsALLVMPointerType; static constexpr GetTypeIDFunctionTy getTypeIdFunction = mlirLLVMPointerTypeGetTypeID; static constexpr const char *pyClassName = "PointerType"; static inline const MlirStringRef name = mlirLLVMPointerTypeGetName(); using Base::Base; static void bindDerived(ClassTy &c) { c.def_static( "get", [](std::optional addressSpace, DefaultingPyMlirContext context) { python::CollectDiagnosticsToStringScope scope(context.get()->get()); MlirType type = mlirLLVMPointerTypeGet( context.get()->get(), addressSpace.has_value() ? *addressSpace : 0); if (mlirTypeIsNull(type)) { throw nb::value_error(scope.takeMessage().c_str()); } return PointerType(context->getRef(), type); }, "address_space"_a = nb::none(), nb::kw_only(), "context"_a = nb::none()); c.def_prop_ro("address_space", [](const PointerType &type) { return mlirLLVMPointerTypeGetAddressSpace(type); }); } }; static void populateDialectLLVMSubmodule(nanobind::module_ &m) { StructType::bind(m); PointerType::bind(m); m.def( "translate_module_to_llvmir", [](const PyOperation &module) { return mlirTranslateModuleToLLVMIRToString(module); }, "module"_a, nb::rv_policy::take_ownership); } } // namespace llvm } // namespace MLIR_BINDINGS_PYTHON_DOMAIN } // namespace python } // namespace mlir NB_MODULE(_mlirDialectsLLVM, m) { m.doc() = "MLIR LLVM Dialect"; mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::llvm::populateDialectLLVMSubmodule( m); }