//===- 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 #include #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 { 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 lvlTypes, std::optional dimToLvl, std::optional lvlToDim, int posWidth, int crdWidth, std::optional explicitVal, std::optional 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 &properties, unsigned n, unsigned m) { std::vector props; props.reserve(properties.size()); for (auto prop : properties) { props.push_back( static_cast(prop)); } return mlirSparseTensorEncodingAttrBuildLvlType( static_cast(lvlFmt), props.data(), props.size(), n, m); }, nb::arg("lvl_fmt"), nb::arg("properties") = std::vector(), 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 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 { MlirAffineMap ret = mlirSparseTensorEncodingAttrGetDimToLvl(self); if (mlirAffineMapIsNull(ret)) return {}; return PyAffineMap(self.getContext(), ret); }); c.def_prop_ro( "lvl_to_dim", [](EncodingAttr &self) -> std::optional { 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> { MlirAttribute ret = mlirSparseTensorEncodingAttrGetExplicitVal(self); if (mlirAttributeIsNull(ret)) return {}; return PyAttribute(self.getContext(), ret).maybeDownCast(); }); c.def_prop_ro("implicit_val", [](EncodingAttr &self) -> std::optional> { 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 ret; ret.reserve(lvlRank); for (int l = 0; l < lvlRank; l++) ret.push_back(static_cast( mlirSparseTensorEncodingAttrGetLvlFmt(self, l))); return ret; }); } }; static void populateDialectSparseTensorSubmodule(nb::module_ &m) { nb::enum_(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_(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); }