Skip to content

Commit edefc18

Browse files
authored
[mlir][sparse] update doc for new surface syntax encoding (#67072)
1 parent de4850c commit edefc18

File tree

1 file changed

+81
-92
lines changed

1 file changed

+81
-92
lines changed

mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorAttrDefs.td

Lines changed: 81 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,15 @@ include "mlir/IR/EnumAttr.td"
1414
include "mlir/Dialect/SparseTensor/IR/SparseTensorBase.td"
1515
include "mlir/IR/TensorEncoding.td"
1616

17-
// All of the Tensor attributes will extend this class.
17+
// All of the sparse tensor attributes will extend this class.
1818
class SparseTensor_Attr<string name,
1919
list<Trait> traits = []>
2020
: AttrDef<SparseTensor_Dialect, name, traits>;
2121

2222
//===----------------------------------------------------------------------===//
23-
// Type aliases.
24-
//
25-
// These attributes are just like `IndexAttr` (include/mlir/IR/OpBase.td),
26-
// except that:
27-
// (1) the `summary` is more specific (i.e., the fourth parameter to
28-
// `TypedAttrBase`), which helps tablegen provide better error messages.
29-
// (2) tablegen-generated getters will have the given `returnType`, in
30-
// lieu of the `APInt` that `IndexAttr` uses. This avoids the boilerplate
31-
// of needing to say `get{FOO}().getZExtValue()`, as well as using
32-
// C++ types which better document intent.
23+
// These attributes are just like `IndexAttr` except that they clarify whether
24+
// the index refers to a dimension (an axis of the semantic tensor) or a level
25+
// (an axis of the actual storage format).
3326
//===----------------------------------------------------------------------===//
3427

3528
def DimensionAttr :
@@ -107,79 +100,71 @@ def SparseTensorEncodingAttr : SparseTensor_Attr<"SparseTensorEncoding",
107100
let mnemonic = "encoding";
108101

109102
let description = [{
110-
An attribute to encode TACO-style information on sparsity properties
111-
of tensors. The encoding is eventually used by a **sparse compiler**
112-
pass to generate sparse code fully automatically for all tensor
113-
expressions that involve tensors with a sparse encoding. Compiler
114-
passes that run before this sparse compiler pass need to be
115-
aware of the semantics of tensor types with such an encoding.
116-
117-
Each sparse tensor comes equipped with two different sets of axes for
118-
describing the tensor's multi-dimensional structure. We use the term
119-
"dimension" to refer to the axes of the semantic tensor itself; whereas,
120-
we use the term "level" to refer to the axes of the storage scheme,
121-
which is the operational representation of that tensor. Therefore,
122-
the fields of the encoding attribute (further explained below) satisfy
123-
the following correspondences:
124-
125-
- Dimensions:
126-
- the shape of the tensor type
127-
- the `dimSlices` field
128-
- the arguments of the `dimToLvl` field
129-
- Levels:
130-
- the results of the `dimToLvl` field
131-
- the `lvlTypes` field
132-
133-
The attribute consists of the following fields.
134-
135-
- Level-type for each level of a tensor type:
136-
- **dense** : all entries along this level are stored.
137-
- **compressed** : only nonzeros along this level are stored.
138-
- **singleton** : a variant of the compressed level-format,
139-
for when coordinates are guaranteed to have no siblings at this level.
140-
By default, each level-type has the property of being unique (no
141-
duplicates at that level) and ordered (coordinates appear sorted
142-
at that level). The following two suffixes can be used to specify
143-
that the level should instead be non-unique (duplicates may appear)
144-
and/or non-ordered (coordinates may appear unsorted).
145-
- **-nu** : not unique
146-
- **-no** : not ordered
147-
Currently, these suffixes (if present) must appear in this order.
148-
In the future, we may introduce additional level-types and
149-
properties, and split up how the level-format and properties are
150-
specified rather than using this suffix mechanism.
151-
152-
- An optional affine map from dimension-coordinates to level-coordinates;
153-
defaulting to the identity map. For example, given a 2-d tensor:
154-
`(i, j) -> (i, j)` specifies row-wise storage, `(i, j) -> (j, i)`
155-
specifies column-wise storage, and
156-
`(i, j) -> (i floordiv 2, j floordiv 3, i mod 2, j mod 3)`
157-
specifies 2x3 block-sparsity. For block-sparsity, blocks are typically
158-
stored with compression while dense storage is used within each block
159-
(although hybrid schemes are possible as well).
160-
161-
(The following will be corrected in an upcoming change that completely
162-
overhauls the syntax of this attribute.)
163-
164-
The dimToLvl mapping also provides a notion of "counting a
165-
dimension", where every stored element with the same coordinate
166-
is mapped to a new slice. For instance, ELL storage of a 2-d
167-
tensor can be defined with the mapping `(i, j) -> (#i, i, j)`
168-
using the notation of [Chou20]. Lacking the `#` symbol in MLIR's
169-
affine mapping, we use a free symbol `c` to define such counting,
170-
together with a constant that denotes the number of resulting
171-
slices. For example, the mapping `(i, j)[c] -> (c * 3 * i, i, j)`
172-
with the level-types `["dense", "dense", "compressed"]` denotes ELL
173-
storage with three jagged diagonals that count the dimension `i`.
174-
175-
- The required bitwidth for "position" storage (integral offsets
103+
An attribute to encode information on sparsity properties of tensors, inspired
104+
by the TACO formalization of sparse tensors. This encoding is eventually used
105+
by a **sparsifier** pass to generate sparse code fully automatically from a
106+
sparsity-agnostic representation of the computation, i.e., an implicit sparse
107+
representation is converted to an explicit sparse representation where co-iterating
108+
loops operate on sparse storage formats rather than tensors with a sparsity
109+
encoding. Compiler passes that run before this sparse compiler pass need to
110+
be aware of the semantics of tensor types with such a sparsity encoding.
111+
112+
In this encoding, we use `dimension` to refer to the axes of the semantic tensor,
113+
and `level` to refer to the axes of the actual storage format, i.e., the
114+
operational representation of the sparse tensor in memory. The number of
115+
dimensions is usually the same as the number of levels (such as CSR storage format).
116+
However, the encoding can also map dimensions to higher-order levels (for example,
117+
to encode a block-sparse BSR storage format) or to lower-order levels
118+
(for example, to linearize dimensions as a single level in the storage).
119+
120+
The encoding contains a `map` that provides the following:
121+
122+
- An ordered sequence of dimension specifications, each of which defines:
123+
- the dimension-size (implicit from the tensor’s dimension-shape)
124+
- a **dimension-expression**
125+
- An ordered sequence of level specifications, each of which includes a required
126+
**level-type**, which defines how the level should be stored. Each level-type
127+
consists of:
128+
- a **level-format**
129+
- a collection of **level-properties** that apply to the level-format
130+
- a **level-expression**, which defines what is stored
131+
132+
Each level-expression is an affine expression over dimension-variables. Thus, the
133+
level-expressions collectively define an affine map from dimension-coordinates to
134+
level-coordinates. The dimension-expressions collectively define the inverse map,
135+
which only needs to be provided for elaborate cases where it cannot be inferred
136+
automatically. Within the sparse storage format, we refer to indices that are
137+
stored explicitly as `coordinates` and indices into the storage format as `positions`.
138+
139+
The supported level-formats are the following:
140+
141+
- **dense** : all entries along this level are stored
142+
- **compressed** : only nonzeros along this level are stored
143+
- **singleton** : a variant of the compressed format, where coordinates have no siblings
144+
145+
Different level-formats may have different collections of level-properties.
146+
By default, each level-type has the property of being unique (no duplicate
147+
coordinates at that level), ordered (coordinates appear sorted at that
148+
level), and, for compression, storing the positions in a compact way where
149+
an interval is defined by a lower bound "pos(i)" and an upper bound "pos(i+1)-1".
150+
The following properties can be added to a level-format to change this
151+
default behavior:
152+
153+
- **nonunique** : duplicate coordinates may appear at the level
154+
- **nonordered** : coordinates may appear in arbribratry order
155+
- **high** : the upper bound is stored explicitly in a separate array
156+
- **block2_4** : the compression uses a 2:4 encoding per 1x4 block
157+
158+
In addition to the `map`, the following two fields are optional:
159+
160+
- The required bitwidth for `position` storage (integral offsets
176161
into the sparse storage scheme). A narrow width reduces the memory
177162
footprint of overhead storage, as long as the width suffices to
178163
define the total required range (viz. the maximum number of stored
179164
entries over all indirection levels). The choices are `8`, `16`,
180165
`32`, `64`, or, the default, `0` to indicate the native bitwidth.
181166

182-
- The required bitwidth for "coordinate" storage (the coordinates
167+
- The required bitwidth for `coordinate` storage (the coordinates
183168
of stored entries). A narrow width reduces the memory footprint
184169
of overhead storage, as long as the width suffices to define
185170
the total required range (viz. the maximum value of each tensor
@@ -194,41 +179,46 @@ def SparseTensorEncodingAttr : SparseTensor_Attr<"SparseTensorEncoding",
194179
```mlir
195180
// Sparse vector.
196181
#SparseVector = #sparse_tensor.encoding<{
197-
map = (d0) -> (d0 : compressed)
182+
map = (i) -> (i : compressed)
198183
}>
199184
... tensor<?xf32, #SparseVector> ...
200185

201-
// Sorted Coordinate Scheme.
186+
// Sorted coordinate scheme.
202187
#SortedCOO = #sparse_tensor.encoding<{
203-
map = (d0, d1) -> (d0 : compressed(nonunique), d1 : singleton)
188+
map = (i, j) -> (i : compressed(nonunique), j : singleton)
204189
}>
205190
... tensor<?x?xf64, #SortedCOO> ...
206191

192+
// Batched sorted coordinate scheme, with high encoding.
193+
#BCOO = #sparse_tensor.encoding<{
194+
map = (i, j, k) -> (i : dense, j : compressed(nonunique, high), k : singleton)
195+
}>
196+
... tensor<10x10xf32, #BCOO> ...
197+
198+
// Compressed sparse row.
199+
#CSR = #sparse_tensor.encoding<{
200+
map = (i, j) -> (i : dense, j : compressed)
201+
}>
202+
... tensor<100x100xbf16, #CSR> ...
203+
207204
// Doubly compressed sparse column storage with specific bitwidths.
208205
#DCSC = #sparse_tensor.encoding<{
209-
map = (d0, d1) -> (d1 : compressed, d0 : compressed),
206+
map = (i, j) -> (j : compressed, i : compressed),
210207
posWidth = 32,
211208
crdWidth = 8
212209
}>
213210
... tensor<8x8xf64, #DCSC> ...
214211

215212
// Block sparse row storage (2x3 blocks).
216-
#BCSR = #sparse_tensor.encoding<{
213+
#BSR = #sparse_tensor.encoding<{
217214
map = ( i, j ) ->
218215
( i floordiv 2 : compressed,
219216
j floordiv 3 : compressed,
220217
i mod 2 : dense,
221218
j mod 3 : dense
222219
)
223220
}>
224-
... tensor<20x30xf32, #BCSR> ...
225-
226-
// ELL storage (4 jagged diagonals, i.e., at most 4 nonzeros per row).
227-
#ELL = #sparse_tensor.encoding<{
228-
lvlTypes = [ "dense", "dense", "compressed" ],
229-
dimToLvl = affine_map<(i, j)[c] -> (c * 4 * i, i, j)>
230-
}>
231-
... tensor<?x?xf64, #ELL> ...
221+
... tensor<20x30xf32, #BSR> ...
232222

233223
// CSR slice (offset = 0, size = 4, stride = 1 on the first dimension;
234224
// offset = 0, size = 8, and a dynamic stride on the second dimension).
@@ -444,7 +434,6 @@ def AnyRankedSparseTensor : RankedSparseTensorOf<[AnyType]>;
444434
class ScalarLikeOf<list<Type> allowedTypes>
445435
: AnyTypeOf<[0DTensorOf<allowedTypes>, AnyTypeOf<allowedTypes>]>;
446436

447-
448437
//===----------------------------------------------------------------------===//
449438
// Sparse Tensor Sorting Algorithm Attribute.
450439
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)