@@ -14,22 +14,15 @@ include "mlir/IR/EnumAttr.td"
14
14
include "mlir/Dialect/SparseTensor/IR/SparseTensorBase.td"
15
15
include "mlir/IR/TensorEncoding.td"
16
16
17
- // All of the Tensor attributes will extend this class.
17
+ // All of the sparse tensor attributes will extend this class.
18
18
class SparseTensor_Attr<string name,
19
19
list<Trait> traits = []>
20
20
: AttrDef<SparseTensor_Dialect, name, traits>;
21
21
22
22
//===----------------------------------------------------------------------===//
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).
33
26
//===----------------------------------------------------------------------===//
34
27
35
28
def DimensionAttr :
@@ -107,79 +100,71 @@ def SparseTensorEncodingAttr : SparseTensor_Attr<"SparseTensorEncoding",
107
100
let mnemonic = "encoding";
108
101
109
102
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
176
161
into the sparse storage scheme). A narrow width reduces the memory
177
162
footprint of overhead storage, as long as the width suffices to
178
163
define the total required range (viz. the maximum number of stored
179
164
entries over all indirection levels). The choices are `8`, `16`,
180
165
`32`, `64`, or, the default, `0` to indicate the native bitwidth.
181
166
182
- - The required bitwidth for " coordinate" storage (the coordinates
167
+ - The required bitwidth for ` coordinate` storage (the coordinates
183
168
of stored entries). A narrow width reduces the memory footprint
184
169
of overhead storage, as long as the width suffices to define
185
170
the total required range (viz. the maximum value of each tensor
@@ -194,41 +179,46 @@ def SparseTensorEncodingAttr : SparseTensor_Attr<"SparseTensorEncoding",
194
179
```mlir
195
180
// Sparse vector.
196
181
#SparseVector = #sparse_tensor.encoding<{
197
- map = (d0 ) -> (d0 : compressed)
182
+ map = (i ) -> (i : compressed)
198
183
}>
199
184
... tensor<?xf32, #SparseVector> ...
200
185
201
- // Sorted Coordinate Scheme .
186
+ // Sorted coordinate scheme .
202
187
#SortedCOO = #sparse_tensor.encoding<{
203
- map = (d0, d1 ) -> (d0 : compressed(nonunique), d1 : singleton)
188
+ map = (i, j ) -> (i : compressed(nonunique), j : singleton)
204
189
}>
205
190
... tensor<?x?xf64, #SortedCOO> ...
206
191
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
+
207
204
// Doubly compressed sparse column storage with specific bitwidths.
208
205
#DCSC = #sparse_tensor.encoding<{
209
- map = (d0, d1 ) -> (d1 : compressed, d0 : compressed),
206
+ map = (i, j ) -> (j : compressed, i : compressed),
210
207
posWidth = 32,
211
208
crdWidth = 8
212
209
}>
213
210
... tensor<8x8xf64, #DCSC> ...
214
211
215
212
// Block sparse row storage (2x3 blocks).
216
- #BCSR = #sparse_tensor.encoding<{
213
+ #BSR = #sparse_tensor.encoding<{
217
214
map = ( i, j ) ->
218
215
( i floordiv 2 : compressed,
219
216
j floordiv 3 : compressed,
220
217
i mod 2 : dense,
221
218
j mod 3 : dense
222
219
)
223
220
}>
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> ...
232
222
233
223
// CSR slice (offset = 0, size = 4, stride = 1 on the first dimension;
234
224
// offset = 0, size = 8, and a dynamic stride on the second dimension).
@@ -444,7 +434,6 @@ def AnyRankedSparseTensor : RankedSparseTensorOf<[AnyType]>;
444
434
class ScalarLikeOf<list<Type> allowedTypes>
445
435
: AnyTypeOf<[0DTensorOf<allowedTypes>, AnyTypeOf<allowedTypes>]>;
446
436
447
-
448
437
//===----------------------------------------------------------------------===//
449
438
// Sparse Tensor Sorting Algorithm Attribute.
450
439
//===----------------------------------------------------------------------===//
0 commit comments