| //===- DialectSparseTensor.cpp - 'sparse_tensor' dialect submodule --------===// | |
| // | |
| // 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 <optional> | |
| #include <vector> | |
| #include "mlir-c/AffineMap.h" | |
| #include "mlir-c/Dialect/SparseTensor.h" | |
| #include "mlir-c/IR.h" | |
| #include "mlir/Bindings/Python/IRCore.h" | |
| #include "mlir/Bindings/Python/Nanobind.h" | |
| #include "mlir/Bindings/Python/NanobindAdaptors.h" | |
| namespace nb = nanobind; | |
| using namespace mlir::python::nanobind_adaptors; | |
| namespace mlir { | |
| namespace python { | |
| namespace MLIR_BINDINGS_PYTHON_DOMAIN { | |
| namespace sparse_tensor { | |
| enum class PySparseTensorLevelFormat : std::underlying_type_t< | |
| MlirSparseTensorLevelFormat> { | |
| DENSE = MLIR_SPARSE_TENSOR_LEVEL_DENSE, | |
| N_OUT_OF_M = MLIR_SPARSE_TENSOR_LEVEL_N_OUT_OF_M, | |
| COMPRESSED = MLIR_SPARSE_TENSOR_LEVEL_COMPRESSED, | |
| SINGLETON = MLIR_SPARSE_TENSOR_LEVEL_SINGLETON, | |
| LOOSE_COMPRESSED = MLIR_SPARSE_TENSOR_LEVEL_LOOSE_COMPRESSED | |
| }; | |
| enum class PySparseTensorLevelPropertyNondefault : std::underlying_type_t< | |
| MlirSparseTensorLevelPropertyNondefault> { | |
| NON_ORDERED = MLIR_SPARSE_PROPERTY_NON_ORDERED, | |
| NON_UNIQUE = MLIR_SPARSE_PROPERTY_NON_UNIQUE, | |
| SOA = MLIR_SPARSE_PROPERTY_SOA, | |
| }; | |
| struct EncodingAttr : PyConcreteAttribute<EncodingAttr> { | |
| static constexpr IsAFunctionTy isaFunction = | |
| mlirAttributeIsASparseTensorEncodingAttr; | |
| static constexpr const char *pyClassName = "EncodingAttr"; | |
| static inline const MlirStringRef name = | |
| mlirSparseTensorEncodingAttrGetName(); | |
| using Base::Base; | |
| static void bindDerived(ClassTy &c) { | |
| c.def_static( | |
| "get", | |
| [](std::vector<MlirSparseTensorLevelType> lvlTypes, | |
| std::optional<PyAffineMap> dimToLvl, | |
| std::optional<PyAffineMap> lvlToDim, int posWidth, int crdWidth, | |
| std::optional<PyAttribute> explicitVal, | |
| std::optional<PyAttribute> implicitVal, | |
| DefaultingPyMlirContext context) { | |
| return EncodingAttr( | |
| context->getRef(), | |
| mlirSparseTensorEncodingAttrGet( | |
| context.get()->get(), lvlTypes.size(), lvlTypes.data(), | |
| dimToLvl ? *dimToLvl : MlirAffineMap{nullptr}, | |
| lvlToDim ? *lvlToDim : MlirAffineMap{nullptr}, posWidth, | |
| crdWidth, explicitVal ? *explicitVal : MlirAttribute{nullptr}, | |
| implicitVal ? *implicitVal : MlirAttribute{nullptr})); | |
| }, | |
| nb::arg("lvl_types"), nb::arg("dim_to_lvl").none(), | |
| nb::arg("lvl_to_dim").none(), nb::arg("pos_width"), | |
| nb::arg("crd_width"), nb::arg("explicit_val") = nb::none(), | |
| nb::arg("implicit_val") = nb::none(), nb::arg("context") = nb::none(), | |
| "Gets a sparse_tensor.encoding from parameters."); | |
| c.def_static( | |
| "build_level_type", | |
| [](PySparseTensorLevelFormat lvlFmt, | |
| const std::vector<PySparseTensorLevelPropertyNondefault> &properties, | |
| unsigned n, unsigned m) { | |
| std::vector<MlirSparseTensorLevelPropertyNondefault> props; | |
| props.reserve(properties.size()); | |
| for (auto prop : properties) { | |
| props.push_back( | |
| static_cast<MlirSparseTensorLevelPropertyNondefault>(prop)); | |
| } | |
| return mlirSparseTensorEncodingAttrBuildLvlType( | |
| static_cast<MlirSparseTensorLevelFormat>(lvlFmt), props.data(), | |
| props.size(), n, m); | |
| }, | |
| nb::arg("lvl_fmt"), | |
| nb::arg("properties") = | |
| std::vector<PySparseTensorLevelPropertyNondefault>(), | |
| nb::arg("n") = 0, nb::arg("m") = 0, | |
| "Builds a sparse_tensor.encoding.level_type from parameters."); | |
| c.def_prop_ro("lvl_types", [](const EncodingAttr &self) { | |
| const int lvlRank = mlirSparseTensorEncodingGetLvlRank(self); | |
| std::vector<MlirSparseTensorLevelType> ret; | |
| ret.reserve(lvlRank); | |
| for (int l = 0; l < lvlRank; ++l) | |
| ret.push_back(mlirSparseTensorEncodingAttrGetLvlType(self, l)); | |
| return ret; | |
| }); | |
| c.def_prop_ro( | |
| "dim_to_lvl", [](EncodingAttr &self) -> std::optional<PyAffineMap> { | |
| MlirAffineMap ret = mlirSparseTensorEncodingAttrGetDimToLvl(self); | |
| if (mlirAffineMapIsNull(ret)) | |
| return {}; | |
| return PyAffineMap(self.getContext(), ret); | |
| }); | |
| c.def_prop_ro( | |
| "lvl_to_dim", [](EncodingAttr &self) -> std::optional<PyAffineMap> { | |
| MlirAffineMap ret = mlirSparseTensorEncodingAttrGetLvlToDim(self); | |
| if (mlirAffineMapIsNull(ret)) | |
| return {}; | |
| return PyAffineMap(self.getContext(), ret); | |
| }); | |
| c.def_prop_ro("pos_width", mlirSparseTensorEncodingAttrGetPosWidth); | |
| c.def_prop_ro("crd_width", mlirSparseTensorEncodingAttrGetCrdWidth); | |
| c.def_prop_ro("explicit_val", | |
| [](EncodingAttr &self) | |
| -> std::optional<nb::typed<nb::object, PyAttribute>> { | |
| MlirAttribute ret = | |
| mlirSparseTensorEncodingAttrGetExplicitVal(self); | |
| if (mlirAttributeIsNull(ret)) | |
| return {}; | |
| return PyAttribute(self.getContext(), ret).maybeDownCast(); | |
| }); | |
| c.def_prop_ro("implicit_val", | |
| [](EncodingAttr &self) | |
| -> std::optional<nb::typed<nb::object, PyAttribute>> { | |
| MlirAttribute ret = | |
| mlirSparseTensorEncodingAttrGetImplicitVal(self); | |
| if (mlirAttributeIsNull(ret)) | |
| return {}; | |
| return PyAttribute(self.getContext(), ret).maybeDownCast(); | |
| }); | |
| c.def_prop_ro("structured_n", [](const EncodingAttr &self) -> unsigned { | |
| const int lvlRank = mlirSparseTensorEncodingGetLvlRank(self); | |
| return mlirSparseTensorEncodingAttrGetStructuredN( | |
| mlirSparseTensorEncodingAttrGetLvlType(self, lvlRank - 1)); | |
| }); | |
| c.def_prop_ro("structured_m", [](const EncodingAttr &self) -> unsigned { | |
| const int lvlRank = mlirSparseTensorEncodingGetLvlRank(self); | |
| return mlirSparseTensorEncodingAttrGetStructuredM( | |
| mlirSparseTensorEncodingAttrGetLvlType(self, lvlRank - 1)); | |
| }); | |
| c.def_prop_ro("lvl_formats_enum", [](const EncodingAttr &self) { | |
| const int lvlRank = mlirSparseTensorEncodingGetLvlRank(self); | |
| std::vector<PySparseTensorLevelFormat> ret; | |
| ret.reserve(lvlRank); | |
| for (int l = 0; l < lvlRank; l++) | |
| ret.push_back(static_cast<PySparseTensorLevelFormat>( | |
| mlirSparseTensorEncodingAttrGetLvlFmt(self, l))); | |
| return ret; | |
| }); | |
| } | |
| }; | |
| static void populateDialectSparseTensorSubmodule(nb::module_ &m) { | |
| nb::enum_<PySparseTensorLevelFormat>(m, "LevelFormat", nb::is_arithmetic(), | |
| nb::is_flag()) | |
| .value("dense", PySparseTensorLevelFormat::DENSE) | |
| .value("n_out_of_m", PySparseTensorLevelFormat::N_OUT_OF_M) | |
| .value("compressed", PySparseTensorLevelFormat::COMPRESSED) | |
| .value("singleton", PySparseTensorLevelFormat::SINGLETON) | |
| .value("loose_compressed", PySparseTensorLevelFormat::LOOSE_COMPRESSED); | |
| nb::enum_<PySparseTensorLevelPropertyNondefault>(m, "LevelProperty") | |
| .value("non_ordered", PySparseTensorLevelPropertyNondefault::NON_ORDERED) | |
| .value("non_unique", PySparseTensorLevelPropertyNondefault::NON_UNIQUE) | |
| .value("soa", PySparseTensorLevelPropertyNondefault::SOA); | |
| EncodingAttr::bind(m); | |
| } | |
| } // namespace sparse_tensor | |
| } // namespace MLIR_BINDINGS_PYTHON_DOMAIN | |
| } // namespace python | |
| } // namespace mlir | |
| NB_MODULE(_mlirDialectsSparseTensor, m) { | |
| m.doc() = "MLIR SparseTensor dialect."; | |
| mlir::python::MLIR_BINDINGS_PYTHON_DOMAIN::sparse_tensor:: | |
| populateDialectSparseTensorSubmodule(m); | |
| } |