Skip to content

Commit 088c7ce

Browse files
authored
[mlir][sparse] introduce SoA level property on singleton level. (#81942)
1 parent feee627 commit 088c7ce

File tree

6 files changed

+74
-7
lines changed

6 files changed

+74
-7
lines changed

mlir/include/mlir/Dialect/SparseTensor/IR/Enums.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,9 @@ constexpr const char *toFormatString(LevelFormat lvlFmt) {
189189

190190
/// This enum defines all the nondefault properties for storage formats.
191191
enum class LevelPropNonDefault : uint64_t {
192-
Nonunique = 0x0001,
193-
Nonordered = 0x0002,
192+
Nonunique = 0x0001, // 0b001
193+
Nonordered = 0x0002, // 0b010
194+
SoA = 0x0004, // 0b100
194195
};
195196

196197
/// Returns string representation of the given level properties.
@@ -200,6 +201,8 @@ constexpr const char *toPropString(LevelPropNonDefault lvlProp) {
200201
return "nonunique";
201202
case LevelPropNonDefault::Nonordered:
202203
return "nonordered";
204+
case LevelPropNonDefault::SoA:
205+
return "soa";
203206
}
204207
return "";
205208
}
@@ -334,6 +337,11 @@ struct LevelType {
334337
propStr += ", ";
335338
propStr += toPropString(LevelPropNonDefault::Nonordered);
336339
}
340+
if (isa<LevelPropNonDefault::SoA>()) {
341+
if (!propStr.empty())
342+
propStr += ", ";
343+
propStr += toPropString(LevelPropNonDefault::SoA);
344+
}
337345
if (!propStr.empty())
338346
lvlStr += ("(" + propStr + ")");
339347
return lvlStr;

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,14 @@ def SparseTensorEncodingAttr : SparseTensor_Attr<"SparseTensorEncoding",
157157

158158
By default, each level-type has the property of being unique (no duplicate
159159
coordinates at that level) and ordered (coordinates appear sorted at that
160-
level). The following properties can be added to a level-format to change
161-
this default behavior:
160+
level). For singleton levels, the coordinates are fused with its parents in AoS
161+
(array of structures) scheme. The following properties can be added to a level-format
162+
to change this default behavior:
162163

163164
- **nonunique** : duplicate coordinates may appear at the level
164165
- **nonordered** : coordinates may appear in arbribratry order
166+
- **soa** : only applicable to singleton levels, fuses the singleton
167+
level in SoA (structure of arrays) scheme.
165168

166169
In addition to the map, the following two fields are optional:
167170

@@ -188,10 +191,18 @@ def SparseTensorEncodingAttr : SparseTensor_Attr<"SparseTensorEncoding",
188191
}>
189192
... tensor<?xf32, #SparseVector> ...
190193

191-
// Sorted coordinate scheme.
194+
// Sorted coordinate scheme (arranged in AoS format by default).
192195
#SortedCOO = #sparse_tensor.encoding<{
193196
map = (i, j) -> (i : compressed(nonunique), j : singleton)
194197
}>
198+
// coordinates = {x_crd, y_crd}[nnz]
199+
... tensor<?x?xf64, #SortedCOO> ...
200+
201+
// Sorted coordinate scheme (arranged in SoA format).
202+
#SortedCOO = #sparse_tensor.encoding<{
203+
map = (i, j) -> (i : compressed(nonunique), j : singleton(soa))
204+
}>
205+
// coordinates = {x_crd[nnz], y_crd[nnz]}
195206
... tensor<?x?xf64, #SortedCOO> ...
196207

197208
// Batched sorted coordinate scheme, with high encoding.

mlir/lib/Dialect/SparseTensor/IR/Detail/LvlTypeParser.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,12 @@ ParseResult LvlTypeParser::parseProperty(AsmParser &parser,
8787
auto loc = parser.getCurrentLocation();
8888
ERROR_IF(failed(parser.parseOptionalKeyword(&strVal)),
8989
"expected valid level property (e.g. nonordered, nonunique or high)")
90-
if (strVal.compare("nonunique") == 0) {
90+
if (strVal.equals(toPropString(LevelPropNonDefault::Nonunique))) {
9191
*properties |= static_cast<uint64_t>(LevelPropNonDefault::Nonunique);
92-
} else if (strVal.compare("nonordered") == 0) {
92+
} else if (strVal.equals(toPropString(LevelPropNonDefault::Nonordered))) {
9393
*properties |= static_cast<uint64_t>(LevelPropNonDefault::Nonordered);
94+
} else if (strVal.equals(toPropString(LevelPropNonDefault::SoA))) {
95+
*properties |= static_cast<uint64_t>(LevelPropNonDefault::SoA);
9496
} else {
9597
parser.emitError(loc, "unknown level property: ") << strVal;
9698
return failure();

mlir/lib/Dialect/SparseTensor/IR/SparseTensorDialect.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,26 @@ LogicalResult SparseTensorEncodingAttr::verify(
664664
[](LevelType i) { return isSingletonLT(i); }))
665665
return emitError() << "expected all singleton lvlTypes "
666666
"following a singleton level";
667+
// We can potentially support mixed SoA/AoS singleton levels.
668+
if (!std::all_of(it, lvlTypes.end(), [it](LevelType i) {
669+
return it->isa<LevelPropNonDefault::SoA>() ==
670+
i.isa<LevelPropNonDefault::SoA>();
671+
})) {
672+
return emitError() << "expected all singleton lvlTypes stored in the "
673+
"same memory layout (SoA vs AoS).";
674+
}
667675
}
676+
677+
// SoA property can only be applied on singleton level.
678+
auto soaLvls = llvm::make_filter_range(lvlTypes, [](LevelType lt) {
679+
return lt.isa<LevelPropNonDefault::SoA>();
680+
});
681+
if (llvm::any_of(soaLvls, [](LevelType lt) {
682+
return !lt.isa<LevelFormat::Singleton>();
683+
})) {
684+
return emitError() << "SoA is only applicable to singleton lvlTypes.";
685+
}
686+
668687
// TODO: audit formats that actually are supported by backend.
669688
if (auto it = std::find_if(lvlTypes.begin(), lvlTypes.end(), isNOutOfMLT);
670689
it != std::end(lvlTypes)) {

mlir/test/Dialect/SparseTensor/invalid_encoding.mlir

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,22 @@ func.func private @too_many_lvl_decl(%arg0: tensor<?x?xf64, #TooManyLvlDecl>) {
234234

235235
// -----
236236

237+
// expected-error@+1{{expected all singleton lvlTypes stored in the same memory layout (SoA vs AoS).}}
238+
#COO_SoA = #sparse_tensor.encoding<{
239+
map = (d0, d1, d2) -> (d0 : compressed(nonunique), d1 : singleton(soa, nonunique), d2 : singleton)
240+
}>
241+
func.func private @sparse_coo(tensor<?x?xf32, #COO_SoA>)
242+
243+
// -----
244+
245+
// expected-error@+1{{SoA is only applicable to singleton lvlTypes.}}
246+
#COO_SoA = #sparse_tensor.encoding<{
247+
map = (d0, d1) -> (d0 : compressed(nonunique, soa), d1 : singleton(soa))
248+
}>
249+
func.func private @sparse_coo(tensor<?x?xf32, #COO_SoA>)
250+
251+
// -----
252+
237253
// expected-error@+2 {{use of undeclared identifier 'l1'}}
238254
#TooFewLvlDecl = #sparse_tensor.encoding<{
239255
map = {l0} (d0, d1) -> (l0 = d0 : dense, l1 = d1 : compressed)

mlir/test/Dialect/SparseTensor/roundtrip_encoding.mlir

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,17 @@ func.func private @sparse_sorted_coo(tensor<10x10xf64, #SortedCOO>)
9494

9595
// -----
9696

97+
#COO_SoA = #sparse_tensor.encoding<{
98+
map = (d0, d1) -> (d0 : compressed(nonunique), d1 : singleton(soa))
99+
}>
100+
101+
// CHECK-DAG: #[[$COO_SoA:.*]] = #sparse_tensor.encoding<{ map = (d0, d1) -> (d0 : compressed(nonunique), d1 : singleton(soa)) }>
102+
// CHECK-LABEL: func private @sparse_coo(
103+
// CHECK-SAME: tensor<?x?xf32, #[[$COO_SoA]]>)
104+
func.func private @sparse_coo(tensor<?x?xf32, #COO_SoA>)
105+
106+
// -----
107+
97108
#BSR = #sparse_tensor.encoding<{
98109
map = ( i, j ) ->
99110
( i floordiv 2 : dense,

0 commit comments

Comments
 (0)