//===- Enums.h - Enums for the SparseTensor dialect -------------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// // // Typedefs and enums shared between MLIR code for manipulating the // IR, and the lightweight runtime support library for sparse tensor // manipulations. That is, all the enums are used to define the API // of the runtime library and hence are also needed when generating // calls into the runtime library. Moveover, the `LevelType` enum // is also used as the internal IR encoding of dimension level types, // to avoid code duplication (e.g., for the predicates). // // This file also defines x-macros <https://en.wikipedia.org/wiki/X_Macro> // so that we can generate variations of the public functions for each // supported primary- and/or overhead-type. // // Because this file defines a library which is a dependency of the // runtime library itself, this file must not depend on any MLIR internals // (e.g., operators, attributes, ArrayRefs, etc) lest the runtime library // inherit those dependencies. // //===----------------------------------------------------------------------===// #ifndef MLIR_DIALECT_SPARSETENSOR_IR_ENUMS_H #define MLIR_DIALECT_SPARSETENSOR_IR_ENUMS_H // NOTE: Client code will need to include "mlir/ExecutionEngine/Float16bits.h" // if they want to use the `MLIR_SPARSETENSOR_FOREVERY_V` macro. #include <cassert> #include <cinttypes> #include <complex> #include <optional> #include <vector> namespace mlir { namespace sparse_tensor { /// This type is used in the public API at all places where MLIR expects /// values with the built-in type "index". For now, we simply assume that /// type is 64-bit, but targets with different "index" bitwidths should /// link with an alternatively built runtime support library. index_type; /// Encoding of overhead types (both position overhead and coordinate /// overhead), for "overloading" @newSparseTensor. enum class OverheadType : uint32_t { … }; // This x-macro calls its argument on every overhead type which has // fixed-width. It excludes `index_type` because that type is often // handled specially (e.g., by translating it into the architecture-dependent // equivalent fixed-width overhead type). #define MLIR_SPARSETENSOR_FOREVERY_FIXED_O(DO) … // This x-macro calls its argument on every overhead type, including // `index_type`. #define MLIR_SPARSETENSOR_FOREVERY_O(DO) … // These are not just shorthands but indicate the particular // implementation used (e.g., as opposed to C99's `complex double`, // or MLIR's `ComplexType`). complex64; complex32; /// Encoding of the elemental type, for "overloading" @newSparseTensor. enum class PrimaryType : uint32_t { … }; // This x-macro includes all `V` types. #define MLIR_SPARSETENSOR_FOREVERY_V(DO) … // This x-macro includes all `V` types and supports variadic arguments. #define MLIR_SPARSETENSOR_FOREVERY_V_VAR(DO, ...) … // This x-macro calls its argument on every pair of overhead and `V` types. #define MLIR_SPARSETENSOR_FOREVERY_V_O(DO) … constexpr bool isFloatingPrimaryType(PrimaryType valTy) { … } constexpr bool isIntegralPrimaryType(PrimaryType valTy) { … } constexpr bool isRealPrimaryType(PrimaryType valTy) { … } constexpr bool isComplexPrimaryType(PrimaryType valTy) { … } /// The actions performed by @newSparseTensor. enum class Action : uint32_t { … }; /// This enum defines all supported storage format without the level properties. enum class LevelFormat : uint64_t { … }; constexpr bool encPowOfTwo(LevelFormat fmt) { … } // All LevelFormats must have only one bit set (power of two). static_assert …; template <LevelFormat... targets> constexpr bool isAnyOfFmt(LevelFormat fmt) { … } /// Returns string representation of the given level format. constexpr const char *toFormatString(LevelFormat lvlFmt) { … } /// This enum defines all the nondefault properties for storage formats. enum class LevelPropNonDefault : uint64_t { … }; /// Returns string representation of the given level properties. constexpr const char *toPropString(LevelPropNonDefault lvlProp) { … } /// This enum defines all the sparse representations supportable by /// the SparseTensor dialect. We use a lightweight encoding to encode /// the "format" per se (dense, compressed, singleton, loose_compressed, /// n-out-of-m), the "properties" (ordered, unique) as well as n and m when /// the format is NOutOfM. /// The encoding is chosen for performance of the runtime library, and thus may /// change in future versions; consequently, client code should use the /// predicate functions defined below, rather than relying on knowledge /// about the particular binary encoding. /// /// The `Undef` "format" is a special value used internally for cases /// where we need to store an undefined or indeterminate `LevelType`. /// It should not be used externally, since it does not indicate an /// actual/representable format. struct LevelType { … }; // For backward-compatibility. TODO: remove below after fully migration. constexpr uint64_t nToBits(uint64_t n) { … } constexpr uint64_t mToBits(uint64_t m) { … } inline std::optional<LevelType> buildLevelType(LevelFormat lf, const std::vector<LevelPropNonDefault> &properties, uint64_t n = 0, uint64_t m = 0) { … } inline std::optional<LevelType> buildLevelType(LevelFormat lf, bool ordered, bool unique, uint64_t n = 0, uint64_t m = 0) { … } inline bool isUndefLT(LevelType lt) { … } inline bool isDenseLT(LevelType lt) { … } inline bool isBatchLT(LevelType lt) { … } inline bool isCompressedLT(LevelType lt) { … } inline bool isLooseCompressedLT(LevelType lt) { … } inline bool isSingletonLT(LevelType lt) { … } inline bool isNOutOfMLT(LevelType lt) { … } inline bool isOrderedLT(LevelType lt) { … } inline bool isUniqueLT(LevelType lt) { … } inline bool isWithCrdLT(LevelType lt) { … } inline bool isWithPosLT(LevelType lt) { … } inline bool isValidLT(LevelType lt) { … } inline std::optional<LevelFormat> getLevelFormat(LevelType lt) { … } inline uint64_t getN(LevelType lt) { … } inline uint64_t getM(LevelType lt) { … } inline bool isValidNOutOfMLT(LevelType lt, uint64_t n, uint64_t m) { … } inline std::string toMLIRString(LevelType lt) { … } /// Bit manipulations for affine encoding. /// /// Note that because the indices in the mappings refer to dimensions /// and levels (and *not* the sizes of these dimensions and levels), the /// 64-bit encoding gives ample room for a compact encoding of affine /// operations in the higher bits. Pure permutations still allow for /// 60-bit indices. But non-permutations reserve 20-bits for the /// potential three components (index i, constant, index ii). /// /// The compact encoding is as follows: /// /// 0xffffffffffffffff /// |0000 | 60-bit idx| e.g. i /// |0001 floor| 20-bit const|20-bit idx| e.g. i floor c /// |0010 mod | 20-bit const|20-bit idx| e.g. i mod c /// |0011 mul |20-bit idx|20-bit const|20-bit idx| e.g. i + c * ii /// /// This encoding provides sufficient generality for currently supported /// sparse tensor types. To generalize this more, we will need to provide /// a broader encoding scheme for affine functions. Also, the library /// encoding may be replaced with pure "direct-IR" code in the future. /// constexpr uint64_t encodeDim(uint64_t i, uint64_t cf, uint64_t cm) { … } constexpr uint64_t encodeLvl(uint64_t i, uint64_t c, uint64_t ii) { … } constexpr bool isEncodedFloor(uint64_t v) { … } constexpr bool isEncodedMod(uint64_t v) { … } constexpr bool isEncodedMul(uint64_t v) { … } constexpr uint64_t decodeIndex(uint64_t v) { … } constexpr uint64_t decodeConst(uint64_t v) { … } constexpr uint64_t decodeMulc(uint64_t v) { … } constexpr uint64_t decodeMuli(uint64_t v) { … } } // namespace sparse_tensor } // namespace mlir #endif // MLIR_DIALECT_SPARSETENSOR_IR_ENUMS_H