25#include "llvm/Support/FormatVariadic.h"
27#define GET_ATTRDEF_CLASSES
28#include "mlir/Dialect/SparseTensor/IR/SparseTensorAttrDefs.cpp.inc"
29#include "mlir/Dialect/SparseTensor/IR/SparseTensorAttrEnums.cpp.inc"
39#define GET_TYPEDEF_CLASSES
40#include "mlir/Dialect/SparseTensor/IR/SparseTensorTypes.cpp.inc"
49 return llvm::hash_value(
static_cast<uint64_t
>(lt));
77 if (dimShape.has_value()) {
81 enc.translateShape(*dimShape, CrdTransDirectionKind::dim2lvl);
82 memrefShape.assign(lvlShape.begin(),
83 lvlShape.begin() + enc.getBatchLvlRank());
86 memrefShape.push_back(ShapedType::kDynamic);
102 const auto lvlTypes = enc.getLvlTypes();
103 const Level lvlRank = enc.getLvlRank();
109 for (
Level l = 0; l < lvlRank; ) {
110 const auto lt = lvlTypes[l];
119 if (!cooSegsRef.empty() && cooSegsRef.front().isSegmentStart(l)) {
120 if (!cooSegsRef.front().isSoA) {
123 l = cooSegsRef.front().lvlRange.second;
129 cooSegsRef = cooSegsRef.drop_front();
157 const Type posMemType = MemRefType::get(memrefShape, stt.
getPosType());
159 const Type crdMemType = MemRefType::get(memrefShape, stt.
getCrdType());
169 return callback(specType, fieldIdx, fieldKind, lvl, lt);
171 return callback(posMemType, fieldIdx, fieldKind, lvl, lt);
173 return callback(crdMemType, fieldIdx, fieldKind, lvl, lt);
175 return callback(valMemType, fieldIdx, fieldKind, lvl, lt);
177 llvm_unreachable(
"unrecognized field kind");
182 unsigned numFields = 0;
192 unsigned numFields = 0;
204std::pair<FieldIndex, unsigned>
206 std::optional<Level> lvl)
const {
210 assert(lvl.has_value());
211 const Level cooStart = enc.getAoSCOOStart();
212 const Level lvlRank = enc.getLvlRank();
213 if (lvl.value() >= cooStart && lvl.value() < lvlRank) {
215 stride = lvlRank - cooStart;
221 if ((lvl && fLvl == lvl.value() && kind == fKind) ||
230 return std::pair<FieldIndex, unsigned>(fieldIdx, stride);
237std::optional<uint64_t> SparseTensorDimSliceAttr::getStatic(
int64_t v) {
238 return isDynamic(v) ? std::nullopt
239 : std::make_optional(
static_cast<uint64_t
>(v));
242std::optional<uint64_t> SparseTensorDimSliceAttr::getStaticOffset()
const {
243 return getStatic(getOffset());
246std::optional<uint64_t> SparseTensorDimSliceAttr::getStaticStride()
const {
247 return getStatic(getStride());
250std::optional<uint64_t> SparseTensorDimSliceAttr::getStaticSize()
const {
251 return getStatic(getSize());
254bool SparseTensorDimSliceAttr::isCompletelyDynamic()
const {
255 return isDynamic(getOffset()) && isDynamic(getStride()) &&
256 isDynamic(getSize());
259std::string SparseTensorDimSliceAttr::getStaticString(int64_t v) {
260 return isDynamic(v) ?
"?" : std::to_string(v);
263void SparseTensorDimSliceAttr::print(llvm::raw_ostream &os)
const {
264 assert(getImpl() &&
"Uninitialized SparseTensorDimSliceAttr");
266 os << getStaticString(getOffset());
268 os << getStaticString(getSize());
270 os << getStaticString(getStride());
274void SparseTensorDimSliceAttr::print(AsmPrinter &printer)
const {
281 if (parseResult.has_value()) {
282 if (parseResult.value().succeeded() &&
result < 0) {
285 "expect positive value or ? for slice offset/size/stride");
288 return parseResult.value();
292 result = SparseTensorDimSliceAttr::kDynamic;
296Attribute SparseTensorDimSliceAttr::parse(AsmParser &parser, Type type) {
297 int64_t offset = kDynamic, size = kDynamic, stride = kDynamic;
309 offset, size, stride);
314 int64_t offset, int64_t size, int64_t stride) {
315 if (!isDynamic(offset) && offset < 0)
316 return emitError() <<
"expect non-negative value or ? for slice offset";
317 if (!isDynamic(size) && size <= 0)
318 return emitError() <<
"expect positive value or ? for slice size";
319 if (!isDynamic(stride) && stride <= 0)
320 return emitError() <<
"expect positive value or ? for slice stride";
324SparseTensorEncodingAttr
325SparseTensorEncodingAttr::withDimToLvl(AffineMap dimToLvl)
const {
326 assert(getImpl() &&
"Uninitialized SparseTensorEncodingAttr");
327 return SparseTensorEncodingAttr::get(
328 getContext(), getLvlTypes(), dimToLvl, AffineMap(), getPosWidth(),
329 getCrdWidth(), getExplicitVal(), getImplicitVal());
332SparseTensorEncodingAttr
333SparseTensorEncodingAttr::withDimToLvl(SparseTensorEncodingAttr enc)
const {
334 return withDimToLvl(enc ? enc.getDimToLvl() : AffineMap());
337SparseTensorEncodingAttr SparseTensorEncodingAttr::withoutDimToLvl()
const {
338 return withDimToLvl(AffineMap());
341SparseTensorEncodingAttr
342SparseTensorEncodingAttr::withBitWidths(
unsigned posWidth,
343 unsigned crdWidth)
const {
344 assert(getImpl() &&
"Uninitialized SparseTensorEncodingAttr");
345 return SparseTensorEncodingAttr::get(
346 getContext(), getLvlTypes(), getDimToLvl(), getLvlToDim(), posWidth,
347 crdWidth, getExplicitVal(), getImplicitVal());
350SparseTensorEncodingAttr SparseTensorEncodingAttr::withoutBitWidths()
const {
351 return withBitWidths(0, 0);
354SparseTensorEncodingAttr
355SparseTensorEncodingAttr::withExplicitVal(Attribute explicitVal)
const {
356 assert(getImpl() &&
"Uninitialized SparseTensorEncodingAttr");
357 return SparseTensorEncodingAttr::get(
358 getContext(), getLvlTypes(), getDimToLvl(), getLvlToDim(), getPosWidth(),
359 getCrdWidth(), explicitVal, getImplicitVal());
362SparseTensorEncodingAttr SparseTensorEncodingAttr::withoutExplicitVal()
const {
363 return withExplicitVal(Attribute());
366SparseTensorEncodingAttr
367SparseTensorEncodingAttr::withImplicitVal(Attribute implicitVal)
const {
368 assert(getImpl() &&
"Uninitialized SparseTensorEncodingAttr");
369 return SparseTensorEncodingAttr::get(
370 getContext(), getLvlTypes(), getDimToLvl(), getLvlToDim(), getPosWidth(),
371 getCrdWidth(), getExplicitVal(), implicitVal);
374SparseTensorEncodingAttr SparseTensorEncodingAttr::withoutImplicitVal()
const {
375 return withImplicitVal(Attribute());
378SparseTensorEncodingAttr SparseTensorEncodingAttr::withDimSlices(
379 ArrayRef<SparseTensorDimSliceAttr> dimSlices)
const {
380 return SparseTensorEncodingAttr::get(
381 getContext(), getLvlTypes(), getDimToLvl(), getLvlToDim(), getPosWidth(),
382 getCrdWidth(), getExplicitVal(), getImplicitVal(), dimSlices);
385SparseTensorEncodingAttr SparseTensorEncodingAttr::withoutDimSlices()
const {
386 return withDimSlices(ArrayRef<SparseTensorDimSliceAttr>{});
389uint64_t SparseTensorEncodingAttr::getBatchLvlRank()
const {
390 ArrayRef<LevelType> lvlTypes = getLvlTypes();
391 auto lastBatch = std::find_if(lvlTypes.rbegin(), lvlTypes.rend(),
isBatchLT);
392 return std::distance(lastBatch, lvlTypes.rend());
395bool SparseTensorEncodingAttr::isAllDense()
const {
396 return !getImpl() || llvm::all_of(getLvlTypes(),
isDenseLT);
399bool SparseTensorEncodingAttr::isAllOrdered()
const {
400 return !getImpl() || llvm::all_of(getLvlTypes(),
isOrderedLT);
403Type SparseTensorEncodingAttr::getCrdElemType()
const {
407 return IntegerType::get(
getContext(), getCrdWidth());
411Type SparseTensorEncodingAttr::getPosElemType()
const {
415 return IntegerType::get(
getContext(), getPosWidth());
419MemRefType SparseTensorEncodingAttr::getCrdMemRefType(
420 std::optional<ArrayRef<int64_t>> dimShape)
const {
422 return MemRefType::get(shape, getCrdElemType());
425MemRefType SparseTensorEncodingAttr::getPosMemRefType(
426 std::optional<ArrayRef<int64_t>> dimShape)
const {
428 return MemRefType::get(shape, getPosElemType());
431bool SparseTensorEncodingAttr::isIdentity()
const {
432 return !getImpl() || !getDimToLvl() || getDimToLvl().isIdentity();
435bool SparseTensorEncodingAttr::isPermutation()
const {
436 return !getImpl() || !getDimToLvl() || getDimToLvl().isPermutation();
439Dimension SparseTensorEncodingAttr::getDimRank()
const {
440 assert(getImpl() &&
"Uninitialized SparseTensorEncodingAttr");
441 const auto dimToLvl = getDimToLvl();
442 return dimToLvl ? dimToLvl.
getNumDims() : getLvlRank();
445Level SparseTensorEncodingAttr::getLvlRank()
const {
446 assert(getImpl() &&
"Uninitialized SparseTensorEncodingAttr");
447 return getLvlTypes().size();
453 assert(l < getLvlRank() &&
"Level is out of bounds");
454 return getLvlTypes()[l];
457bool SparseTensorEncodingAttr::isSlice()
const {
458 assert(getImpl() &&
"Uninitialized SparseTensorEncodingAttr");
459 return !getDimSlices().empty();
462SparseTensorDimSliceAttr
463SparseTensorEncodingAttr::getDimSlice(
Dimension dim)
const {
464 assert(isSlice() &&
"Is not a slice");
465 const auto dimSlices = getDimSlices();
466 assert(dim < dimSlices.size() &&
"Dimension is out of bounds");
467 return dimSlices[dim];
470std::optional<uint64_t>
471SparseTensorEncodingAttr::getStaticDimSliceOffset(
Dimension dim)
const {
472 return getDimSlice(dim).getStaticOffset();
475std::optional<uint64_t>
476SparseTensorEncodingAttr::getStaticDimSliceStride(
Dimension dim)
const {
477 return getDimSlice(dim).getStaticStride();
480std::optional<uint64_t>
481SparseTensorEncodingAttr::getStaticLvlSliceOffset(
Level lvl)
const {
482 return getStaticDimSliceOffset(
toDim(*
this, lvl));
485std::optional<uint64_t>
486SparseTensorEncodingAttr::getStaticLvlSliceStride(
Level lvl)
const {
487 return getStaticDimSliceStride(
toDim(*
this, lvl));
491SparseTensorEncodingAttr::translateShape(ArrayRef<int64_t> srcShape,
492 CrdTransDirectionKind dir)
const {
494 return SmallVector<int64_t>(srcShape);
496 SmallVector<int64_t> ret;
498 dir == CrdTransDirectionKind::dim2lvl ? getLvlRank() : getDimRank();
502 for (
unsigned r = 0; r < rank; r++) {
503 unsigned trans = dir == CrdTransDirectionKind::dim2lvl ?
toDim(*
this, r)
505 ret.push_back(srcShape[trans]);
512 dir == CrdTransDirectionKind::dim2lvl ? getDimToLvl() : getLvlToDim();
519 ret.resize(rank, ShapedType::kDynamic);
523 SmallVector<AffineExpr> dimRep;
524 dimRep.reserve(srcShape.size());
525 for (int64_t sz : srcShape) {
526 if (ShapedType::isStatic(sz)) {
538 unsigned numSymbols = getDimToLvl().getNumSymbols();
540 for (AffineExpr exp : transMap.
getResults()) {
543 srcShape.size(), numSymbols);
545 if (
auto c = llvm::dyn_cast<AffineConstantExpr>(evalExp)) {
546 ret.push_back(c.getValue() + 1);
548 if (
auto mod = llvm::dyn_cast<AffineBinaryOpExpr>(evalExp);
552 if (
auto bound = llvm::dyn_cast<AffineConstantExpr>(mod.getRHS())) {
553 ret.push_back(bound.getValue());
557 ret.push_back(ShapedType::kDynamic);
560 assert(ret.size() == rank);
565SparseTensorEncodingAttr::translateCrds(OpBuilder &builder, Location loc,
567 CrdTransDirectionKind dir)
const {
571 SmallVector<Type> retType(
572 dir == CrdTransDirectionKind::lvl2dim ? getDimRank() : getLvlRank(),
575 CrdTranslateOp::create(builder, loc, retType, crds, dir, *
this);
576 return transOp.getOutCrds();
579Attribute SparseTensorEncodingAttr::parse(AsmParser &parser, Type type) {
587 SmallVector<LevelType> lvlTypes;
588 SmallVector<SparseTensorDimSliceAttr> dimSlices;
589 AffineMap dimToLvl = {};
590 AffineMap lvlToDim = {};
591 unsigned posWidth = 0;
592 unsigned crdWidth = 0;
593 Attribute explicitVal;
594 Attribute implicitVal;
596 SmallVector<StringRef, 5> keys = {
"map",
"posWidth",
"crdWidth",
597 "explicitVal",
"implicitVal"};
600 auto *it = find(keys, attrName);
601 if (it == keys.end()) {
605 unsigned keyWordIndex = it - keys.begin();
610 switch (keyWordIndex) {
613 auto res = cParser.parseDimLvlMap();
616 const auto &dlm = *res;
618 const Level lvlRank = dlm.getLvlRank();
619 for (
Level lvl = 0; lvl < lvlRank; lvl++)
620 lvlTypes.push_back(dlm.getLvlType(lvl));
622 const Dimension dimRank = dlm.getDimRank();
623 for (
Dimension dim = 0; dim < dimRank; dim++)
624 dimSlices.push_back(dlm.getDimSlice(dim));
628 const auto isDefined = [](SparseTensorDimSliceAttr
slice) {
629 return static_cast<bool>(
slice.getImpl());
631 if (llvm::any_of(dimSlices, isDefined)) {
632 const auto defaultSlice =
633 SparseTensorDimSliceAttr::get(parser.
getContext());
634 for (
Dimension dim = 0; dim < dimRank; dim++)
635 if (!isDefined(dimSlices[dim]))
636 dimSlices[dim] = defaultSlice;
641 dimToLvl = dlm.getDimToLvlMap(parser.
getContext());
642 lvlToDim = dlm.getLvlToDimMap(parser.
getContext());
649 auto intAttr = llvm::dyn_cast<IntegerAttr>(attr);
652 "expected an integral position bitwidth");
655 posWidth = intAttr.getInt();
662 auto intAttr = llvm::dyn_cast<IntegerAttr>(attr);
665 "expected an integral index bitwidth");
668 crdWidth = intAttr.getInt();
675 if (
auto result = llvm::dyn_cast<FloatAttr>(attr)) {
677 }
else if (
auto result = llvm::dyn_cast<IntegerAttr>(attr)) {
679 }
else if (
auto result = llvm::dyn_cast<complex::NumberAttr>(attr)) {
683 "expected a numeric value for explicitVal");
692 if (
auto result = llvm::dyn_cast<FloatAttr>(attr)) {
694 }
else if (
auto result = llvm::dyn_cast<IntegerAttr>(attr)) {
696 }
else if (
auto result = llvm::dyn_cast<complex::NumberAttr>(attr)) {
700 "expected a numeric value for implicitVal");
718 if (!lvlToDim || lvlToDim.
isEmpty()) {
721 return parser.
getChecked<SparseTensorEncodingAttr>(
722 parser.
getContext(), lvlTypes, dimToLvl, lvlToDim, posWidth, crdWidth,
723 explicitVal, implicitVal, dimSlices);
726void SparseTensorEncodingAttr::print(AsmPrinter &printer)
const {
727 auto map =
static_cast<AffineMap
>(getDimToLvl());
731 printer <<
"<{ map = ";
732 printSymbols(map, printer);
734 printDimensions(map, printer, getDimSlices());
736 printLevels(map, printer, getLvlTypes());
740 printer <<
", posWidth = " << getPosWidth();
742 printer <<
", crdWidth = " << getCrdWidth();
743 if (getExplicitVal()) {
744 printer <<
", explicitVal = " << getExplicitVal();
746 if (getImplicitVal())
747 printer <<
", implicitVal = " << getImplicitVal();
751void SparseTensorEncodingAttr::printSymbols(AffineMap &map,
752 AsmPrinter &printer)
const {
756 for (
unsigned i = 0, n = map.
getNumSymbols() - 1; i < n; i++)
757 printer <<
's' << i <<
", ";
763void SparseTensorEncodingAttr::printDimensions(
764 AffineMap &map, AsmPrinter &printer,
765 ArrayRef<SparseTensorDimSliceAttr> dimSlices)
const {
766 if (!dimSlices.empty()) {
767 for (
unsigned i = 0, n = map.
getNumDims() - 1; i < n; i++)
768 printer <<
'd' << i <<
" : " << dimSlices[i] <<
", ";
770 printer <<
'd' << map.
getNumDims() - 1 <<
" : "
774 for (
unsigned i = 0, n = map.
getNumDims() - 1; i < n; i++)
775 printer <<
'd' << i <<
", ";
781void SparseTensorEncodingAttr::printLevels(AffineMap &map, AsmPrinter &printer,
782 ArrayRef<LevelType> lvlTypes)
const {
783 for (
unsigned i = 0, n = map.
getNumResults() - 1; i < n; i++) {
794LogicalResult SparseTensorEncodingAttr::verify(
796 AffineMap dimToLvl, AffineMap lvlToDim,
unsigned posWidth,
797 unsigned crdWidth, Attribute explicitVal, Attribute implicitVal,
798 ArrayRef<SparseTensorDimSliceAttr> dimSlices) {
800 return emitError() <<
"unexpected position bitwidth: " << posWidth;
802 return emitError() <<
"unexpected coordinate bitwidth: " << crdWidth;
806 while (it != lvlTypes.end()) {
807 if (it == lvlTypes.begin() ||
809 return emitError() <<
"expected compressed or loose_compressed level "
810 "before singleton level";
812 auto *curCOOEnd = std::find_if_not(it, lvlTypes.end(),
isSingletonLT);
814 return emitError() <<
"expected all singleton lvlTypes "
815 "following a singleton level";
817 if (!std::all_of(it, curCOOEnd, [it](
LevelType i) {
821 return emitError() <<
"expected all singleton lvlTypes stored in the "
822 "same memory layout (SoA vs AoS).";
827 auto lastBatch = std::find_if(lvlTypes.rbegin(), lvlTypes.rend(),
isBatchLT);
828 if (!std::all_of(lastBatch, lvlTypes.rend(),
isBatchLT))
829 return emitError() <<
"Batch lvlType can only be leading levels.";
832 auto soaLvls = llvm::make_filter_range(lvlTypes, [](
LevelType lt) {
835 if (llvm::any_of(soaLvls, [](
LevelType lt) {
838 return emitError() <<
"SoA is only applicable to singleton lvlTypes.";
845 for (
auto [i, lt] : llvm::drop_begin(llvm::enumerate(lvlTypes))) {
847 return emitError() <<
"dense level cannot follow a non-unique level";
851 if (
auto it = llvm::find_if(lvlTypes,
isNOutOfMLT);
852 it != std::end(lvlTypes)) {
853 if (it != lvlTypes.end() - 1)
854 return emitError() <<
"expected n_out_of_m to be the last level type";
855 if (!std::all_of(lvlTypes.begin(), it,
isDenseLT))
856 return emitError() <<
"expected all dense lvlTypes "
857 "before a n_out_of_m level";
861 <<
"expected 1xm block structure for n_out_of_m level";
864 unsigned coefficient = 0;
865 for (
const auto &elem : sizes) {
867 if (elem != coefficient && coefficient != 0) {
868 return emitError() <<
"expected only one blocked level "
869 "with the same coefficients";
874 if (coefficient !=
getM(*it)) {
875 return emitError() <<
"expected coeffiencts of Affine expressions "
876 "to be equal to m of n_out_of_m level";
885 const Level lvlRank = lvlTypes.size();
887 return emitError() <<
"expected a non-empty array for lvlTypes";
893 <<
"level-rank mismatch between dimToLvl and lvlTypes: "
898 return emitError() <<
"failed to infer lvlToDim from dimToLvl";
899 if (lvlToDim && (inferRes != lvlToDim))
900 return emitError() <<
"expected lvlToDim to be an inverse of dimToLvl";
901 if (dimRank > lvlRank)
902 return emitError() <<
"unexpected dimToLvl mapping from " << dimRank
903 <<
" to " << lvlRank;
905 if (!dimSlices.empty()) {
906 if (dimSlices.size() != dimRank)
908 <<
"dimension-rank mismatch between dimSlices and dimToLvl: "
909 << dimSlices.size() <<
" != " << dimRank;
912 if (dimRank != lvlRank)
914 <<
"dimSlices expected dimension-rank to match level-rank: "
915 << dimRank <<
" != " << lvlRank;
925 if (
auto complexTp = dyn_cast<ComplexType>(elemTp)) {
926 Type elt = complexTp.getElementType();
932LogicalResult SparseTensorEncodingAttr::verifyEncoding(
933 ArrayRef<Size> dimShape, Type elementType,
938 getPosWidth(), getCrdWidth(), getExplicitVal(),
939 getImplicitVal(), getDimSlices())))
944 const Dimension dimRank = dimShape.size();
946 return emitError() <<
"expected non-scalar sparse tensor";
947 if (getDimRank() != dimRank)
949 <<
"dimension-rank mismatch between encoding and tensor shape: "
950 << getDimRank() <<
" != " << dimRank;
951 if (
auto expVal = getExplicitVal()) {
952 Type attrType = llvm::dyn_cast<TypedAttr>(expVal).getType();
953 if (attrType != elementType) {
954 return emitError() <<
"explicit value type mismatch between encoding and "
955 <<
"tensor element type: " << attrType
956 <<
" != " << elementType;
959 if (
auto impVal = getImplicitVal()) {
960 Type attrType = llvm::dyn_cast<TypedAttr>(impVal).getType();
961 if (attrType != elementType) {
962 return emitError() <<
"implicit value type mismatch between encoding and "
963 <<
"tensor element type: " << attrType
964 <<
" != " << elementType;
967 auto impFVal = llvm::dyn_cast<FloatAttr>(impVal);
968 auto impIntVal = llvm::dyn_cast<IntegerAttr>(impVal);
969 auto impComplexVal = llvm::dyn_cast<complex::NumberAttr>(impVal);
970 if ((impFVal && impFVal.getValue().isNonZero()) ||
971 (impIntVal && !impIntVal.getValue().isZero()) ||
972 (impComplexVal && (impComplexVal.getImag().isNonZero() ||
973 impComplexVal.getReal().isNonZero()))) {
974 return emitError() <<
"implicit value must be zero";
978 return emitError() <<
"invalid primary type";
982Level mlir::sparse_tensor::SparseTensorEncodingAttr::getAoSCOOStart()
const {
983 SmallVector<COOSegment> coo = getCOOSegments();
984 assert(coo.size() == 1 || coo.empty());
985 if (!coo.empty() && coo.front().isAoS()) {
986 return coo.front().lvlRange.first;
991SmallVector<COOSegment>
992mlir::sparse_tensor::SparseTensorEncodingAttr::getCOOSegments()
const {
993 SmallVector<COOSegment> ret;
994 if (getLvlRank() <= 1)
997 ArrayRef<LevelType> lts = getLvlTypes();
999 while (l < getLvlRank()) {
1002 auto cur = lts.begin() + l;
1003 auto end = std::find_if(cur + 1, lts.end(), [](
LevelType lt) {
1004 return !lt.isa<LevelFormat::Singleton>();
1006 unsigned cooLen = std::distance(cur, end);
1012 ret.push_back(
COOSegment{std::make_pair(l, l + cooLen),
1033 for (
Level l = startLvl + 1; l < lvlRank; ++l)
1045 lvlTypes.reserve(lvlRank);
1052 std::fill_n(std::back_inserter(lvlTypes), lvlRank - 2,
1057 auto enc = SparseTensorEncodingAttr::get(
1067SparseTensorEncodingAttr
1069 if (
auto ttp = llvm::dyn_cast<RankedTensorType>(type))
1070 return llvm::dyn_cast_or_null<SparseTensorEncodingAttr>(ttp.getEncoding());
1071 if (
auto mdtp = llvm::dyn_cast<StorageSpecifierType>(type))
1072 return mdtp.getEncoding();
1078 auto map =
static_cast<AffineMap>(dimToLvl);
1099 std::map<unsigned, SmallVector<AffineExpr, 3>> lvlExprComponents;
1100 for (
unsigned i = 0, n = numLvls; i < n; i++) {
1102 if (
auto binOp = dyn_cast<AffineBinaryOpExpr>(
result)) {
1105 auto pos = dyn_cast<AffineDimExpr>(binOp.getLHS()).getPosition();
1106 assert(lvlExprComponents.find(pos) == lvlExprComponents.end() &&
1107 "expected only one floordiv for each dimension");
1112 components.push_back(binOp.getRHS());
1114 lvlExprComponents[pos] = components;
1116 auto pos = dyn_cast<AffineDimExpr>(binOp.getLHS()).getPosition();
1117 assert(lvlExprComponents.find(pos) != lvlExprComponents.end() &&
1118 "expected floordiv before mod");
1123 assert(
false &&
"expected floordiv or mod");
1126 auto pos = cast<AffineDimExpr>(
result).getPosition();
1134 for (
auto &components : lvlExprComponents) {
1135 assert(components.second.size() == 3 &&
1136 "expected 3 components to build lvlExprs");
1141 lvlExprs[components.first] = addOp;
1145 llvm::erase_if(lvlExprs, [](
AffineExpr expr) {
return !expr; });
1151 "expected dimToLvl to be block sparsity for calling getBlockSize");
1154 if (
auto binOp = dyn_cast<AffineBinaryOpExpr>(
result)) {
1156 blockSize.push_back(
1157 dyn_cast<AffineConstantExpr>(binOp.getRHS()).getValue());
1160 blockSize.push_back(0);
1169 std::map<unsigned, int64_t> coeffientMap;
1170 bool hasBlock =
false;
1172 if (
auto binOp = dyn_cast<AffineBinaryOpExpr>(
result)) {
1174 auto dimOp = dyn_cast<AffineDimExpr>(binOp.getLHS());
1175 auto conOp = dyn_cast<AffineConstantExpr>(binOp.getRHS());
1176 if (!dimOp || !conOp || conOp.getValue() <= 0)
1179 auto pos = dimOp.getPosition();
1182 auto [it,
inserted] = coeffientMap.try_emplace(pos);
1186 it->second = conOp.getValue();
1189 auto it = coeffientMap.find(pos);
1190 if (it == coeffientMap.end())
1193 if (conOp.getValue() != it->second)
1199 }
else if (
auto dimOp = dyn_cast<AffineDimExpr>(
result)) {
1200 auto pos = dimOp.getPosition();
1202 if (!coeffientMap.try_emplace(pos, 0).second)
1212 auto hasNonIdentityMap = [](
Value v) {
1217 return llvm::any_of(op->
getOperands(), hasNonIdentityMap) ||
1218 llvm::any_of(op->
getResults(), hasNonIdentityMap);
1223 assert(enc.isPermutation() &&
"Non permutation map not supported");
1224 if (
const auto dimToLvl = enc.getDimToLvl())
1232 assert(enc.isPermutation() &&
"Non permutation map not supported");
1233 if (
const auto lvlToDim = enc.getLvlToDim())
1243static SparseTensorEncodingAttr
1246 for (
auto lt : enc.getLvlTypes())
1249 return SparseTensorEncodingAttr::get(
1250 enc.getContext(), lts,
1260 enc.getDimSlices());
1264StorageSpecifierType::get(MLIRContext *ctx, SparseTensorEncodingAttr encoding) {
1271 SparseTensorEncodingAttr encoding) {
1290 StorageSpecifierKind mdKind, std::optional<Level> lvl,
1292 if (mdKind == StorageSpecifierKind::ValMemSize && lvl) {
1294 "redundant level argument for querying value memory size");
1297 const auto enc = md.getType().getEncoding();
1298 const Level lvlRank = enc.getLvlRank();
1300 if (mdKind == StorageSpecifierKind::DimOffset ||
1301 mdKind == StorageSpecifierKind::DimStride)
1303 return op->
emitError(
"requested slice data on non-slice tensor");
1305 if (mdKind != StorageSpecifierKind::ValMemSize) {
1307 return op->
emitError(
"missing level argument");
1309 const Level l = lvl.value();
1311 return op->
emitError(
"requested level is out of bounds");
1313 if (mdKind == StorageSpecifierKind::PosMemSize && enc.isSingletonLvl(l))
1315 "requested position memory size on a singleton level");
1331 llvm_unreachable(
"Unrecognizable FieldKind");
1336 RankedTensorType valTp,
1339 return op->
emitError(
"the sparse-tensor must have static shape");
1341 return op->
emitError(
"the sparse-tensor must have an encoding attribute");
1347 auto cooTp = llvm::cast<ShapedType>(lvlTps.back());
1349 unsigned expCOORank = stt.
getLvlRank() - cooStartLvl;
1350 if (cooTp.getRank() != 2 || expCOORank != cooTp.getShape().back()) {
1351 return op->
emitError(
"input/output trailing COO level-ranks don't match");
1358 return op->
emitError(
"inconsistent number of fields between input/output");
1361 bool misMatch =
false;
1368 Type inputTp =
nullptr;
1372 assert(fid == idx && stt.
getLvlType(lvl) == lt);
1373 inputTp = lvlTps[idx++];
1376 Type inpElemTp = llvm::cast<TensorType>(inputTp).getElementType();
1378 if (inpElemTp != expElemTp) {
1386 return op->
emitError(
"input/output element-types don't match");
1390LogicalResult AssembleOp::verify() {
1391 RankedTensorType valuesTp = getValues().getType();
1392 const auto lvlsTp = getLevels().getTypes();
1397LogicalResult DisassembleOp::verify() {
1399 return emitError(
"output values and return value type mismatch");
1401 for (
auto [ot, rt] : llvm::zip_equal(getOutLevels(), getRetLevels()))
1402 if (ot.getType() != rt.getType())
1403 return emitError(
"output levels and return levels type mismatch");
1405 RankedTensorType valuesTp = getRetValues().getType();
1406 const auto lvlsTp = getRetLevels().getTypes();
1411LogicalResult ConvertOp::verify() {
1412 RankedTensorType tp1 = getSource().getType();
1413 RankedTensorType tp2 = getDest().getType();
1414 if (tp1.getRank() != tp2.getRank())
1415 return emitError(
"unexpected conversion mismatch in rank");
1417 llvm::dyn_cast_or_null<SparseTensorEncodingAttr>(tp2.getEncoding());
1418 if (dstEnc && dstEnc.isSlice())
1419 return emitError(
"cannot convert to a sparse tensor slice");
1421 auto shape1 = tp1.getShape();
1422 auto shape2 = tp2.getShape();
1426 for (
Dimension d = 0, dimRank = tp1.getRank(); d < dimRank; d++)
1427 if (shape1[d] != shape2[d] && shape2[d] != ShapedType::kDynamic)
1428 return emitError(
"unexpected conversion mismatch in dimension ") << d;
1432OpFoldResult ConvertOp::fold(FoldAdaptor adaptor) {
1438bool ConvertOp::needsExtraSort() {
1457 if (
auto constOp = getSource().getDefiningOp<arith::ConstantOp>())
1458 if (isa<SparseElementsAttr>(constOp.getValue()))
1464LogicalResult CrdTranslateOp::verify() {
1465 uint64_t inRank = getEncoder().getLvlRank();
1466 uint64_t outRank = getEncoder().getDimRank();
1468 if (getDirection() == CrdTransDirectionKind::dim2lvl)
1469 std::swap(inRank, outRank);
1471 if (inRank != getInCrds().size() || outRank != getOutCrds().size())
1472 return emitError(
"Coordinate rank mismatch with encoding");
1477LogicalResult CrdTranslateOp::fold(FoldAdaptor adaptor,
1478 SmallVectorImpl<OpFoldResult> &results) {
1479 if (getEncoder().isIdentity()) {
1480 results.assign(getInCrds().begin(), getInCrds().end());
1484 AffineMap perm = getDirection() == CrdTransDirectionKind::dim2lvl
1485 ? getEncoder().getDimToLvl()
1486 : getEncoder().getLvlToDim();
1488 results.push_back(getInCrds()[cast<AffineDimExpr>(exp).getPosition()]);
1493 auto def = getInCrds()[0].getDefiningOp<CrdTranslateOp>();
1494 bool sameDef = def && llvm::all_of(getInCrds(), [def](Value v) {
1500 bool oppositeDir = def.getDirection() != getDirection();
1502 def.getEncoder().getDimToLvl() == getEncoder().getDimToLvl();
1503 bool sameCount = def.getNumResults() == getInCrds().size();
1504 if (!oppositeDir || !sameOracle || !sameCount)
1509 bool sameOrder = llvm::all_of(llvm::zip_equal(def.getOutCrds(), getInCrds()),
1510 [](
auto valuePair) {
1511 auto [
lhs,
rhs] = valuePair;
1519 results.append(def.getInCrds().begin(), def.getInCrds().end());
1523void LvlOp::build(OpBuilder &builder, OperationState &state, Value source,
1526 return build(builder, state, source, val);
1529LogicalResult LvlOp::verify() {
1530 if (std::optional<uint64_t> lvl = getConstantLvlIndex()) {
1532 if (
static_cast<uint64_t
>(lvl.value()) >= stt.
getLvlRank())
1534 "Level index exceeds the rank of the input sparse tensor");
1539std::optional<uint64_t> LvlOp::getConstantLvlIndex() {
1549 cast<RankedTensorType>(getSource().
getType()).getRank());
1553OpFoldResult LvlOp::fold(FoldAdaptor adaptor) {
1554 auto lvlIndex = llvm::dyn_cast_if_present<IntegerAttr>(adaptor.getIndex());
1558 Level lvl = lvlIndex.getAPSInt().getZExtValue();
1568 auto getIndexAttr = [
this](int64_t lvlSz) {
1569 return IntegerAttr::get(IndexType::get(
getContext()), APInt(64, lvlSz));
1573 if (ShapedType::isStatic(lvlShape[lvl]))
1574 return getIndexAttr(lvlShape[lvl]);
1579void ReinterpretMapOp::build(OpBuilder &odsBuilder, OperationState &odsState,
1580 SparseTensorEncodingAttr dstEnc, Value source) {
1582 SmallVector<int64_t> srcLvlShape = srcStt.
getLvlShape();
1583 SmallVector<int64_t> dstDimShape =
1584 dstEnc.translateShape(srcLvlShape, CrdTransDirectionKind::lvl2dim);
1586 RankedTensorType::get(dstDimShape, srcStt.
getElementType(), dstEnc);
1587 return build(odsBuilder, odsState, dstTp, source);
1590LogicalResult ReinterpretMapOp::verify() {
1593 ArrayRef<LevelType> srcLvlTps = srcStt.
getLvlTypes();
1594 ArrayRef<LevelType> dstLvlTps = dstStt.
getLvlTypes();
1596 if (srcLvlTps.size() != dstLvlTps.size())
1597 return emitError(
"Level rank mismatch between source/dest tensors");
1599 for (
auto [srcLvlTp, dstLvlTp] : llvm::zip(srcLvlTps, dstLvlTps))
1600 if (srcLvlTp != dstLvlTp)
1601 return emitError(
"Level type mismatch between source/dest tensors");
1605 return emitError(
"Crd/Pos width mismatch between source/dest tensors");
1609 return emitError(
"Element type mismatch between source/dest tensors");
1611 SmallVector<Size> srcLvlShape = srcStt.
getLvlShape();
1612 SmallVector<Size> dstLvlShape = dstStt.
getLvlShape();
1613 for (
auto [srcLvlSz, dstLvlSz] : llvm::zip(srcLvlShape, dstLvlShape)) {
1614 if (srcLvlSz != dstLvlSz) {
1618 return emitError(
"Level size mismatch between source/dest tensors");
1625OpFoldResult ReinterpretMapOp::fold(FoldAdaptor adaptor) {
1629 if (
auto def = getSource().getDefiningOp<ReinterpretMapOp>()) {
1631 if (def.getSource().getType() == getDest().
getType())
1632 return def.getSource();
1637template <
typename ToBufferOp>
1641 typename ToBufferOp::Adaptor adaptor(ops, attr, prop, region);
1643 Type elemTp =
nullptr;
1644 bool withStride =
false;
1645 if constexpr (std::is_same_v<ToBufferOp, ToPositionsOp>) {
1647 }
else if constexpr (std::is_same_v<ToBufferOp, ToCoordinatesOp> ||
1648 std::is_same_v<ToBufferOp, ToCoordinatesBufferOp>) {
1650 if constexpr (std::is_same_v<ToBufferOp, ToCoordinatesOp>)
1652 }
else if constexpr (std::is_same_v<ToBufferOp, ToValuesOp>) {
1656 assert(elemTp &&
"unhandled operation.");
1658 bufShape.push_back(ShapedType::kDynamic);
1660 auto layout = withStride ? StridedLayoutAttr::StridedLayoutAttr::get(
1662 {ShapedType::kDynamic})
1663 : StridedLayoutAttr();
1664 ret.emplace_back(MemRefType::get(bufShape, elemTp, layout));
1668LogicalResult ToPositionsOp::verify() {
1671 return emitError(
"requested level is out of bounds");
1673 return emitError(
"unexpected type for positions");
1678ToPositionsOp::inferReturnTypes(MLIRContext *ctx, std::optional<Location> loc,
1680 PropertyRef prop, RegionRange region,
1681 SmallVectorImpl<mlir::Type> &ret) {
1685LogicalResult ToCoordinatesOp::verify() {
1688 return emitError(
"requested level is out of bounds");
1690 return emitError(
"unexpected type for coordinates");
1695ToCoordinatesOp::inferReturnTypes(MLIRContext *ctx, std::optional<Location> loc,
1697 PropertyRef prop, RegionRange region,
1698 SmallVectorImpl<mlir::Type> &ret) {
1702LogicalResult ToCoordinatesBufferOp::verify() {
1705 return emitError(
"expected sparse tensor with a COO region");
1709LogicalResult ToCoordinatesBufferOp::inferReturnTypes(
1710 MLIRContext *ctx, std::optional<Location> loc,
ValueRange ops,
1711 DictionaryAttr attr, PropertyRef prop, RegionRange region,
1712 SmallVectorImpl<mlir::Type> &ret) {
1717LogicalResult ToValuesOp::verify() {
1721 return emitError(
"unexpected mismatch in element types");
1725LogicalResult ToValuesOp::inferReturnTypes(MLIRContext *ctx,
1726 std::optional<Location> loc,
1728 PropertyRef prop, RegionRange region,
1729 SmallVectorImpl<mlir::Type> &ret) {
1733LogicalResult ToSliceOffsetOp::verify() {
1734 auto rank =
getSlice().getType().getRank();
1735 if (rank <= getDim().getSExtValue() || getDim().getSExtValue() < 0)
1736 return emitError(
"requested dimension out of bound");
1740LogicalResult ToSliceStrideOp::verify() {
1741 auto rank =
getSlice().getType().getRank();
1742 if (rank <= getDim().getSExtValue() || getDim().getSExtValue() < 0)
1743 return emitError(
"requested dimension out of bound");
1747LogicalResult GetStorageSpecifierOp::verify() {
1749 getSpecifier(), getOperation());
1752template <
typename SpecifierOp>
1754 return op.getSpecifier().template getDefiningOp<SetStorageSpecifierOp>();
1757OpFoldResult GetStorageSpecifierOp::fold(FoldAdaptor adaptor) {
1758 const StorageSpecifierKind kind = getSpecifierKind();
1759 const auto lvl = getLevel();
1761 if (kind == op.getSpecifierKind() && lvl == op.getLevel())
1762 return op.getValue();
1766LogicalResult SetStorageSpecifierOp::verify() {
1768 getSpecifier(), getOperation());
1773 const char *regionName,
1776 unsigned expectedNum = inputTypes.size();
1777 if (numArgs != expectedNum)
1778 return op->emitError() << regionName <<
" region must have exactly "
1779 << expectedNum <<
" arguments";
1781 for (
unsigned i = 0; i < numArgs; i++) {
1783 if (typ != inputTypes[i])
1784 return op->emitError() << regionName <<
" region argument " << (i + 1)
1785 <<
" type mismatch";
1789 return op->emitError() << regionName
1790 <<
" region must end with a terminator";
1793 YieldOp yield = dyn_cast<YieldOp>(term);
1795 return op->emitError() << regionName
1796 <<
" region must end with sparse_tensor.yield";
1797 if (!yield.hasSingleResult() ||
1798 yield.getSingleResult().getType() != outputType)
1799 return op->emitError() << regionName <<
" region yield type mismatch";
1804LogicalResult BinaryOp::verify() {
1805 NamedAttrList attrs = (*this)->getDiscardableAttrDictionary().getValue();
1806 Type leftType = getX().getType();
1807 Type rightType = getY().getType();
1808 Type outputType = getOutput().getType();
1809 Region &overlap = getOverlapRegion();
1810 Region &left = getLeftRegion();
1811 Region &right = getRightRegion();
1815 if (!overlap.
empty()) {
1817 TypeRange{leftType, rightType}, outputType)))
1820 if (!left.
empty()) {
1824 }
else if (getLeftIdentity()) {
1825 if (leftType != outputType)
1826 return emitError(
"left=identity requires first argument to have the same "
1827 "type as the output");
1829 if (!right.
empty()) {
1833 }
else if (getRightIdentity()) {
1834 if (rightType != outputType)
1835 return emitError(
"right=identity requires second argument to have the "
1836 "same type as the output");
1841LogicalResult UnaryOp::verify() {
1842 Type inputType = getX().getType();
1843 Type outputType = getOutput().getType();
1847 Region &present = getPresentRegion();
1848 if (!present.
empty()) {
1853 Region &absent = getAbsentRegion();
1854 if (!absent.
empty()) {
1860 Block *parent = getOperation()->getBlock();
1862 cast<YieldOp>(absentBlock->
getTerminator()).getSingleResult();
1863 if (
auto arg = dyn_cast<BlockArgument>(absentVal)) {
1864 if (arg.getOwner() == parent)
1865 return emitError(
"absent region cannot yield linalg argument");
1867 if (!isa<arith::ConstantOp>(def) &&
1868 (def->getBlock() == absentBlock || def->getBlock() == parent))
1869 return emitError(
"absent region cannot yield locally computed value");
1875bool ConcatenateOp::needsExtraSort() {
1880 bool allSameOrdered = llvm::all_of(getInputs(), [dstStt](Value op) {
1887 bool directLowerable =
1888 allSameOrdered && getDimension() == 0 && dstStt.
isIdentity();
1889 return !directLowerable;
1892LogicalResult ConcatenateOp::verify() {
1894 const Dimension concatDim = getDimension();
1895 const Dimension dimRank = dstTp.getDimRank();
1897 if (getInputs().size() <= 1)
1898 return emitError(
"Need at least two tensors to concatenate.");
1900 if (concatDim >= dimRank)
1902 "Concat-dimension is out of bounds for dimension-rank ({0} >= {1})",
1903 concatDim, dimRank));
1905 for (
const auto &it : llvm::enumerate(getInputs())) {
1906 const auto i = it.index();
1908 if (srcTp.hasDynamicDimShape())
1909 return emitError(llvm::formatv(
"Input tensor ${0} has dynamic shape", i));
1910 const Dimension srcDimRank = srcTp.getDimRank();
1911 if (srcDimRank != dimRank)
1913 llvm::formatv(
"Input tensor ${0} has a different rank (rank={1}) "
1914 "from the output tensor (rank={2}).",
1915 i, srcDimRank, dimRank));
1918 for (
Dimension d = 0; d < dimRank; d++) {
1919 const Size dstSh = dstTp.getDimShape()[d];
1920 if (d == concatDim) {
1921 if (ShapedType::isStatic(dstSh)) {
1926 for (
const auto src : getInputs())
1932 "The concatenation dimension of the output tensor should be the "
1933 "sum of all the concatenation dimensions of the input tensors.");
1937 for (
const auto src : getInputs()) {
1939 if (ShapedType::isStatic(prev) && sh != prev)
1940 return emitError(
"All dimensions (expect for the concatenating one) "
1941 "should be equal.");
1950void PushBackOp::build(OpBuilder &builder, OperationState &
result,
1951 Value curSize, Value inBuffer, Value value) {
1952 build(builder,
result, curSize, inBuffer, value, Value());
1955LogicalResult PushBackOp::verify() {
1956 if (Value n =
getN()) {
1958 if (nValue && nValue.value() < 1)
1959 return emitOpError(
"n must be not less than 1");
1964LogicalResult CompressOp::verify() {
1966 if (stt.
getLvlRank() != 1 +
static_cast<Level>(getLvlCoords().size()))
1967 return emitOpError(
"incorrect number of coordinates");
1971void ForeachOp::build(
1972 OpBuilder &builder, OperationState &
result, Value tensor,
1976 build(builder,
result, initArgs.
getTypes(), tensor, initArgs, order);
1984 SmallVector<Type> blockArgTypes(dimRank, builder.
getIndexType());
1988 blockArgTypes.append(initArgs.
getTypes().begin(), initArgs.
getTypes().end());
1990 SmallVector<Location> blockArgLocs(blockArgTypes.size(), tensor.
getLoc());
1992 OpBuilder::InsertionGuard guard(builder);
1993 auto ®ion = *
result.regions.front();
1995 builder.
createBlock(®ion, region.end(), blockArgTypes, blockArgLocs);
1996 bodyBuilder(builder,
result.location,
2002LogicalResult ForeachOp::verify() {
2004 const Dimension dimRank = t.getDimRank();
2005 const auto args = getBody()->getArguments();
2007 if (getOrder().has_value() && getOrder()->getNumDims() != t.getLvlRank())
2008 return emitError(
"Level traverse order does not match tensor's level rank");
2010 if (dimRank + 1 + getInitArgs().size() != args.size())
2011 return emitError(
"Unmatched number of arguments in the block");
2013 if (getNumResults() != getInitArgs().size())
2014 return emitError(
"Mismatch in number of init arguments and results");
2016 if (getResultTypes() != getInitArgs().getTypes())
2017 return emitError(
"Mismatch in types of init arguments and results");
2020 auto yield = cast<YieldOp>(getBody()->getTerminator());
2021 if (yield.getNumOperands() != getNumResults() ||
2022 yield.getOperands().getTypes() != getResultTypes())
2023 return emitError(
"Mismatch in types of yield values and results");
2025 const auto iTp = IndexType::get(
getContext());
2029 llvm::formatv(
"Expecting Index type for argument at index {0}", d));
2031 const auto elemTp = t.getElementType();
2032 const auto valueTp = args[dimRank].getType();
2033 if (elemTp != valueTp)
2035 llvm::formatv(
"Unmatched element type between input tensor and "
2036 "block argument, expected:{0}, got: {1}",
2041OpFoldResult ReorderCOOOp::fold(FoldAdaptor adaptor) {
2044 return getInputCoo();
2049LogicalResult ReorderCOOOp::verify() {
2054 return emitError(
"Expected COO sparse tensors only");
2057 return emitError(
"Unmatched dim2lvl map between input and result COO");
2062 return emitError(
"Unmatched storage format between input and result COO");
2067LogicalResult ReduceOp::verify() {
2068 Type inputType = getX().getType();
2069 Region &formula = getRegion();
2071 TypeRange{inputType, inputType}, inputType);
2074LogicalResult SelectOp::verify() {
2076 Type inputType = getX().getType();
2077 Type boolType =
b.getI1Type();
2078 Region &formula = getRegion();
2083LogicalResult SortOp::verify() {
2084 AffineMap xPerm = getPermMap();
2087 return emitError(llvm::formatv(
"Expected rank(perm_map) > 1, got {0}", nx));
2091 llvm::formatv(
"Expected a permutation map, got {0}", xPerm));
2100 const auto checkDim = [&](Value v,
Size minSize,
2101 const char *message) -> LogicalResult {
2103 if (ShapedType::isStatic(sh) && sh < minSize)
2105 llvm::formatv(
"{0} got {1} < {2}", message, sh, minSize));
2108 uint64_t n = cn.value();
2110 if (
auto nyAttr = getNyAttr())
2111 ny = nyAttr.getInt();
2112 if (
failed(checkDim(getXy(), n * (nx + ny),
2113 "Expected dimension(xy) >= n * (rank(perm_map) + ny)")))
2115 for (Value opnd : getYs())
2116 if (
failed(checkDim(opnd, n,
"Expected dimension(y) >= n")))
2126IterSpaceType IteratorType::getIterSpaceType()
const {
2127 return IterSpaceType::get(
getContext(), getEncoding(), getLoLvl(),
2131IteratorType IterSpaceType::getIteratorType()
const {
2132 return IteratorType::get(
getContext(), getEncoding(), getLoLvl(), getHiLvl());
2151 "expect larger level upper bound than lower bound");
2159 IntegerAttr &lvlHiAttr) {
2176 p << lo <<
" to " << hi;
2182 IntegerAttr lvlHi) {
2183 unsigned lo = lvlLo.getValue().getZExtValue();
2184 unsigned hi = lvlHi.getValue().getZExtValue();
2195 unsigned maxCnt = std::numeric_limits<unsigned>::max(),
2198 ParseResult crdList =
2203 definedSet.
set(cnt);
2211 "parsed more value than expected.");
2213 if (failed(crdList)) {
2216 "expecting SSA value or \"_\" for level coordinates");
2218 assert(definedArgs.size() == definedSet.
count());
2225 if (definedSet.
empty())
2228 for (
unsigned i = 0; i < size; i++) {
2229 if (definedSet[i]) {
2230 p << blocksArgs.front();
2231 blocksArgs = blocksArgs.drop_front();
2238 assert(blocksArgs.empty());
2251 for (
auto &coord : coords)
2272 if (iterators.size() != spaces.size())
2275 "mismatch in number of sparse iterators and sparse spaces");
2280 size_t numCrds = coords.size();
2288 blockArgs.append(coords);
2294 if (iterSpaceTps.size() != spaces.size())
2296 "mismatch in number of iteration space operands "
2297 "and iteration space types");
2299 for (
auto [it, tp] : llvm::zip_equal(iterators, iterSpaceTps)) {
2300 IterSpaceType spaceTp = llvm::dyn_cast<IterSpaceType>(tp);
2303 "expected sparse_tensor.iter_space type for "
2304 "iteration space operands");
2305 it.type = spaceTp.getIteratorType();
2320 if (args.size() != initArgs.size() || args.size() != state.
types.size()) {
2323 "mismatch in number of iteration arguments and return values");
2326 for (
auto [it, init, tp] : llvm::zip_equal(args, initArgs, state.
types)) {
2348 size_t numCrds = coords.size();
2356 blockArgs.append(coords);
2364 if (iterSpaceTps.size() != spaces.size())
2366 "mismatch in number of iteration space operands "
2367 "and iteration space types");
2382 if (args.size() != initArgs.size() || args.size() != state.
types.size()) {
2385 "mismatch in number of iteration arguments and return values");
2388 for (
auto [it, init, tp] : llvm::zip_equal(args, initArgs, state.
types)) {
2397LogicalResult ExtractIterSpaceOp::inferReturnTypes(
2398 MLIRContext *ctx, std::optional<Location> loc,
ValueRange ops,
2399 DictionaryAttr attr, PropertyRef prop, RegionRange region,
2400 SmallVectorImpl<mlir::Type> &ret) {
2402 ExtractIterSpaceOp::Adaptor adaptor(ops, attr, prop, region);
2404 ret.push_back(IterSpaceType::get(ctx, stt.
getEncoding(), adaptor.getLoLvl(),
2405 adaptor.getHiLvl()));
2409LogicalResult ExtractIterSpaceOp::verify() {
2410 if (getLoLvl() >= getHiLvl())
2411 return emitOpError(
"expected smaller level low than level high");
2414 if ((pIter && getLoLvl() == 0) || (!pIter && getLoLvl() != 0)) {
2416 "parent iterator should be specified iff level lower bound equals 0");
2420 IterSpaceType spaceTp = getExtractedSpace().getType();
2421 if (pIter.getType().getEncoding() != spaceTp.getEncoding())
2423 "mismatch in parent iterator encoding and iteration space encoding.");
2425 if (spaceTp.getLoLvl() != pIter.getType().getHiLvl())
2426 return emitOpError(
"parent iterator should be used to extract an "
2427 "iteration space from a consecutive level.");
2433LogicalResult ExtractValOp::verify() {
2435 auto itTp = getIterator().getType();
2438 return emitOpError(
"mismatch in tensor encoding and iterator encoding.");
2441 return emitOpError(
"must use last-level iterator to extract values. ");
2452 llvm::BitVector toRemove(iterateOp.getBody()->getNumArguments());
2453 for (
unsigned i = 0, e = iterateOp.getSpaceDim(); i < e; i++) {
2454 if (
auto crd = iterateOp.getLvlCrd(i)) {
2455 if (crd->getUsers().empty())
2456 toRemove.set(crd->getArgNumber());
2463 if (toRemove.none())
2467 iterateOp.setCrdUsedLvls(newUsedLvls);
2468 iterateOp.getBody()->eraseArguments(toRemove);
2474void IterateOp::getCanonicalizationPatterns(mlir::RewritePatternSet &results,
2475 mlir::MLIRContext *context) {
2476 results.
add<RemoveUnusedLvlCrds>(context);
2479void IterateOp::build(OpBuilder &builder, OperationState &odsState,
2481 unsigned rank = llvm::cast<IterSpaceType>(iterSpace.
getType()).getSpaceDim();
2484 return build(builder, odsState, iterSpace, initArgs, set);
2487void IterateOp::build(OpBuilder &builder, OperationState &odsState,
2490 OpBuilder::InsertionGuard guard(builder);
2496 Region *bodyRegion = odsState.
addRegion();
2501 for (Value v : initArgs)
2505 for (
unsigned i = 0, e = crdUsedLvls.
count(); i < e; i++)
2510 llvm::cast<IterSpaceType>(iterSpace.
getType()).getIteratorType(),
2514ParseResult IterateOp::parse(OpAsmParser &parser, OperationState &
result) {
2515 OpAsmParser::Argument iterator;
2516 OpAsmParser::UnresolvedOperand iterSpace;
2518 SmallVector<OpAsmParser::Argument> iters, iterArgs;
2521 if (iters.size() != 1)
2523 "expected only one iterator/iteration space");
2525 iterArgs.append(iters);
2526 Region *body =
result.addRegion();
2546 StringRef prefix =
"") {
2547 assert(blocksArgs.size() == initializers.size() &&
2548 "expected same length of arguments and initializers");
2549 if (initializers.empty())
2553 llvm::interleaveComma(llvm::zip(blocksArgs, initializers), p, [&](
auto it) {
2554 p << std::get<0>(it) <<
" = " << std::get<1>(it);
2559template <
typename SparseLoopOp>
2561 if (op.getInitArgs().size() != op.getNumResults()) {
2562 return op.emitOpError(
2563 "mismatch in number of loop-carried values and defined values");
2565 if (op.getCrdUsedLvls().max() > op.getSpaceDim())
2566 return op.emitOpError(
"required out-of-bound coordinates");
2574void IterateOp::print(OpAsmPrinter &p) {
2575 p <<
" " << getIterator() <<
" in " << getIterSpace();
2576 if (!getCrdUsedLvls().empty()) {
2583 p <<
" : " << getIterSpace().getType() <<
" ";
2584 if (!getInitArgs().empty())
2589 !getInitArgs().empty());
2592LogicalResult IterateOp::verifyRegions() {
2593 if (getIterator().
getType() != getIterSpace().
getType().getIteratorType())
2594 return emitOpError(
"mismatch in iterator and iteration space type");
2595 if (getNumRegionIterArgs() != getNumResults())
2597 "mismatch in number of basic block args and defined values");
2599 auto initArgs = getInitArgs();
2600 auto iterArgs = getRegionIterArgs();
2601 auto yieldVals = getYieldedValues();
2602 auto opResults = getResults();
2603 if (!llvm::all_equal({initArgs.size(), iterArgs.size(), yieldVals.size(),
2604 opResults.size()})) {
2605 return emitOpError() <<
"number mismatch between iter args and results.";
2608 for (
auto [i, init, iter, yield, ret] :
2609 llvm::enumerate(initArgs, iterArgs, yieldVals, opResults)) {
2610 if (init.getType() != ret.getType())
2611 return emitOpError() <<
"types mismatch between " << i
2612 <<
"th iter operand and defined value";
2613 if (iter.getType() != ret.getType())
2614 return emitOpError() <<
"types mismatch between " << i
2615 <<
"th iter region arg and defined value";
2616 if (yield.getType() != ret.getType())
2617 return emitOpError() <<
"types mismatch between " << i
2618 <<
"th yield value and defined value";
2625SmallVector<Region *> IterateOp::getLoopRegions() {
return {&getRegion()}; }
2627MutableArrayRef<OpOperand> IterateOp::getInitsMutable() {
2628 return getInitArgsMutable();
2632 return getRegion().getArguments().take_front(getNumRegionIterArgs());
2635std::optional<MutableArrayRef<OpOperand>> IterateOp::getYieldedValuesMutable() {
2636 return cast<sparse_tensor::YieldOp>(
2637 getRegion().getBlocks().front().getTerminator())
2638 .getResultsMutable();
2641std::optional<ResultRange> IterateOp::getLoopResults() {
return getResults(); }
2643OperandRange IterateOp::getEntrySuccessorOperands(RegionSuccessor successor) {
2644 return getInitArgs();
2647void IterateOp::getSuccessorRegions(RegionBranchPoint point,
2648 SmallVectorImpl<RegionSuccessor> ®ions) {
2651 regions.push_back(RegionSuccessor(&getRegion()));
2653 regions.push_back(RegionSuccessor(getOperation()));
2656ValueRange IterateOp::getSuccessorInputs(RegionSuccessor successor) {
2661void CoIterateOp::build(OpBuilder &builder, OperationState &odsState,
2663 unsigned numCases) {
2665 cast<IterSpaceType>(iterSpaces.front().
getType()).getSpaceDim();
2672 SmallVector<int64_t> caseBits(numCases, 0);
2674 return CoIterateOp::build(builder, odsState, initArgs.
getTypes(), iterSpaces,
2675 initArgs, set, cases,
2679ParseResult CoIterateOp::parse(OpAsmParser &parser, OperationState &
result) {
2681 SmallVector<Value> spaces;
2684 SmallVector<OpAsmParser::Argument> blockArgs;
2688 result.addAttribute(
"operandSegmentSizes",
2690 {static_cast<int32_t>(spaces.size()),
2691 static_cast<int32_t>(result.types.size())}));
2693 SmallVector<Attribute> cases;
2697 SmallVector<OpAsmParser::Argument> definedIts;
2704 for (
auto [i, definedIdx] : llvm::enumerate(definedItSet.
bits())) {
2706 auto spaceTp = llvm::cast<IterSpaceType>(spaces[definedIdx].
getType());
2707 definedIts[i].type = spaceTp.getIteratorType();
2709 definedIts.insert(definedIts.begin(), blockArgs.begin(), blockArgs.end());
2710 Region *body =
result.addRegion();
2714 CoIterateOp::ensureTerminator(*body, parser.
getBuilder(),
result.location);
2726void CoIterateOp::print(OpAsmPrinter &p) {
2728 llvm::interleaveComma(getIterSpaces(), p, [&](
auto s) { p << s; });
2731 if (!getCrdUsedLvls().empty()) {
2739 p <<
" : (" << getIterSpaces().getTypes() <<
")";
2740 if (!getInitArgs().empty())
2741 p.printArrowTypeList(getInitArgs().getTypes());
2743 for (
unsigned idx = 0, e = getRegions().size(); idx < e; idx++) {
2747 getRegionDefinedSpace(idx));
2749 p.printRegion(getRegion(idx),
false,
2750 !getInitArgs().empty());
2754ValueRange CoIterateOp::getYieldedValues(
unsigned regionIdx) {
2755 return cast<sparse_tensor::YieldOp>(
2756 getRegion(regionIdx).getBlocks().front().getTerminator())
2760LogicalResult CoIterateOp::verifyRegions() {
2761 for (
unsigned r = 0, e = getNumRegions(); r < e; r++) {
2762 if (getNumRegionIterArgs() != getNumResults())
2764 "mismatch in number of basic block args and defined values");
2766 auto initArgs = getInitArgs();
2767 auto iterArgs = getRegionIterArgs(r);
2768 auto yieldVals = getYieldedValues(r);
2769 auto opResults = getResults();
2770 if (!llvm::all_equal({initArgs.size(), iterArgs.size(), yieldVals.size(),
2771 opResults.size()})) {
2772 return emitOpError()
2773 <<
"number mismatch between iter args and results on " << r
2777 for (
auto [i, init, iter, yield, ret] :
2778 llvm::enumerate(initArgs, iterArgs, yieldVals, opResults)) {
2779 if (init.getType() != ret.getType())
2780 return emitOpError()
2781 <<
"types mismatch between " << i
2782 <<
"th iter operand and defined value on " << r <<
"th region";
2783 if (iter.getType() != ret.getType())
2784 return emitOpError() <<
"types mismatch between " << i
2785 <<
"th iter region arg and defined value on " << r
2787 if (yield.getType() != ret.getType())
2788 return emitOpError()
2789 <<
"types mismatch between " << i
2790 <<
"th yield value and defined value on " << r <<
"th region";
2794 auto cases = getRegionDefinedSpaces();
2795 llvm::SmallSetVector<uint64_t, 8> set(cases.begin(), cases.end());
2796 if (set.size() != getNumRegions())
2797 return emitOpError(
"contains duplicated cases.");
2802SmallVector<Region *> CoIterateOp::getSubCasesOf(
unsigned regionIdx) {
2803 SmallVector<Region *> ret;
2804 I64BitSet caseBit = getRegionDefinedSpace(regionIdx);
2805 for (Region &r : getCaseRegions())
2806 if (getRegionDefinedSpace(r.getRegionNumber()).isSubSetOf(caseBit))
2818Operation *SparseTensorDialect::materializeConstant(OpBuilder &builder,
2819 Attribute value, Type type,
2821 if (
auto op = arith::ConstantOp::materialize(builder, value, type, loc))
2826void SparseTensorDialect::initialize() {
2828#define GET_ATTRDEF_LIST
2829#include "mlir/Dialect/SparseTensor/IR/SparseTensorAttrDefs.cpp.inc"
2832#define GET_TYPEDEF_LIST
2833#include "mlir/Dialect/SparseTensor/IR/SparseTensorTypes.cpp.inc"
2837#include "mlir/Dialect/SparseTensor/IR/SparseTensorOps.cpp.inc"
2839 declarePromisedInterfaces<
2840 bufferization::BufferizableOpInterface, ConcatenateOp, ConvertOp, LoadOp,
2841 NewOp, NumberOfEntriesOp, AssembleOp, DisassembleOp,
2842 ToCoordinatesBufferOp, ToCoordinatesOp, ToPositionsOp, ToValuesOp>();
2845#define GET_OP_CLASSES
2846#include "mlir/Dialect/SparseTensor/IR/SparseTensorOps.cpp.inc"
2848#include "mlir/Dialect/SparseTensor/IR/SparseTensorOpsDialect.cpp.inc"
static void printInitializationList(OpAsmPrinter &p, Block::BlockArgListType blocksArgs, ValueRange initializers, StringRef prefix="")
Prints the initialization list in the form of <prefix>(inner = outer, inner2 = outer2,...
static bool isPermutation(const std::vector< PermutationTy > &permutation)
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
static Type getElementType(Type type, ArrayRef< int32_t > indices, function_ref< InFlightDiagnostic(StringRef)> emitErrorFn)
Walks the given type hierarchy with the given indices, potentially down to component granularity,...
static bool isUnique(It begin, It end)
static LogicalResult verifyNumBlockArgs(T *op, Region ®ion, const char *regionName, TypeRange inputTypes, Type outputType)
static ParseResult parseOptionalStaticSlice(int64_t &result, AsmParser &parser)
static SparseTensorEncodingAttr getNormalizedEncodingForSpecifier(SparseTensorEncodingAttr enc)
We normalized sparse tensor encoding attribute by always using ordered/unique LT such that "compresse...
static ParseResult parseUsedCoordList(OpAsmParser &parser, OperationState &state, SmallVectorImpl< OpAsmParser::Argument > &coords)
static LogicalResult isMatchingWidth(Value mem, unsigned width)
static constexpr bool acceptBitWidth(unsigned bitWidth)
static bool isValidPrimaryType(Type elemTp)
static mlir::ParseResult parseLevelRange(mlir::AsmParser &, mlir::sparse_tensor::Level &, mlir::sparse_tensor::Level &)
Parses a level range in the form "$lo `to` $hi" or simply "$lo" if $hi - $lo = 1.
static LogicalResult lvlIsInBounds(Level lvl, Value tensor)
static void printOptionalDefinedList(OpAsmPrinter &p, unsigned size, Block::BlockArgListType blocksArgs, I64BitSet definedSet)
static constexpr FieldIndex kDataFieldStartingIdx
static constexpr Level kInvalidLevel
static LogicalResult verifySparseLoopOp(SparseLoopOp op)
static constexpr Level kInvalidFieldIndex
static void printLevelRange(mlir::AsmPrinter &, mlir::sparse_tensor::Level, mlir::sparse_tensor::Level)
Prints a level range in the form "$lo `to` $hi" or simply "$lo" if $hi - $lo = 1.
static Type getFieldElemType(SparseTensorType stt, SparseTensorFieldKind kind)
static SetStorageSpecifierOp getSpecifierSetDef(SpecifierOp op)
static LogicalResult inferSparseBufferType(ValueRange ops, DictionaryAttr attr, PropertyRef prop, RegionRange region, SmallVectorImpl< mlir::Type > &ret)
static ParseResult parseSparseIterateLoop(OpAsmParser &parser, OperationState &state, SmallVectorImpl< OpAsmParser::Argument > &iterators, SmallVectorImpl< OpAsmParser::Argument > &blockArgs)
static SmallVector< Size > getSparseFieldShape(const SparseTensorEncodingAttr enc, std::optional< ArrayRef< int64_t > > dimShape)
static ParseResult parseOptionalDefinedList(OpAsmParser &parser, OperationState &state, I64BitSet &definedSet, SmallVectorImpl< OpAsmParser::Argument > &definedArgs, unsigned maxCnt=std::numeric_limits< unsigned >::max(), OpAsmParser::Delimiter delimiter=OpAsmParser::Delimiter::Paren)
Parses a list of optional defined list in the form of "(%val0, _, %val1, ...)", where _ is used to an...
static LogicalResult verifyPackUnPack(Operation *op, bool requiresStaticShape, SparseTensorType stt, RankedTensorType valTp, TypeRange lvlTps)
static ParseResult parseSparseCoIterateLoop(OpAsmParser &parser, OperationState &state, SmallVectorImpl< Value > &spacesVals, SmallVectorImpl< OpAsmParser::Argument > &blockArgs)
static LogicalResult verifySparsifierGetterSetter(StorageSpecifierKind mdKind, std::optional< Level > lvl, TypedValue< StorageSpecifierType > md, Operation *op)
static SmallVector< Value > slice(OpBuilder &b, Location loc, Value value, VectorType nativeType)
@ NewOp
Op vectorized into a new Op whose results will replace original Op's results.
Base type for affine expression.
void print(raw_ostream &os) const
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
MLIRContext * getContext() const
unsigned getDimPosition(unsigned idx) const
Extracts the position of the dimensional expression at the given result, when the caller knows it is ...
static AffineMap getMultiDimIdentityMap(unsigned numDims, MLIRContext *context)
Returns an AffineMap with 'numDims' identity result dim exprs.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
bool isEmpty() const
Returns true if this affine map is an empty map, i.e., () -> ().
unsigned getNumSymbols() const
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
unsigned getNumResults() const
AffineExpr getResult(unsigned idx) const
bool isPermutation() const
Returns true if the AffineMap represents a symbol-less permutation map.
This base class exposes generic asm parser hooks, usable across the various derived parsers.
virtual ParseResult parseLBrace()=0
Parse a { token.
Delimiter
These are the supported delimiters around operand lists and region argument lists,...
@ Paren
Parens surrounding zero or more operands.
@ None
Zero or more operands with no delimiters.
virtual OptionalParseResult parseOptionalInteger(APInt &result)=0
Parse an optional integer value from the stream.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseCommaSeparatedList(Delimiter delimiter, function_ref< ParseResult()> parseElementFn, StringRef contextMessage=StringRef())=0
Parse a list of comma-separated items with an optional delimiter.
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
MLIRContext * getContext() const
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
ParseResult parseInteger(IntT &result)
Parse an integer value from the stream.
virtual ParseResult parseRBrace()=0
Parse a } token.
virtual ParseResult parseLess()=0
Parse a '<' token.
virtual ParseResult parseEqual()=0
Parse a = token.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
auto getChecked(SMLoc loc, ParamsT &&...params)
Invoke the getChecked method of the given Attribute or Type class, using the provided location to emi...
virtual ParseResult parseColon()=0
Parse a : token.
virtual SMLoc getNameLoc() const =0
Return the location of the original name token.
virtual ParseResult parseQuestion()=0
Parse a '?' token.
virtual ParseResult parseGreater()=0
Parse a '>' token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseArrowTypeList(SmallVectorImpl< Type > &result)=0
Parse an arrow followed by a type list.
ParseResult parseTypeList(SmallVectorImpl< Type > &result)
Parse a type list.
ParseResult parseKeyword(StringRef keyword)
Parse a given keyword.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
This base class exposes generic asm printer hooks, usable across the various derived printers.
void printArrowTypeList(TypeRange &&types)
virtual raw_ostream & getStream() const
Return the raw output stream used by this printer.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
MutableArrayRef< BlockArgument > BlockArgListType
Operation * getTerminator()
Get the terminator operation of this block.
BlockArgument addArgument(Type type, Location loc)
Add one value to the argument list.
bool mightHaveTerminator()
Return "true" if this block might have a terminator.
BlockArgListType getArguments()
DenseI32ArrayAttr getDenseI32ArrayAttr(ArrayRef< int32_t > values)
IntegerAttr getIntegerAttr(Type type, int64_t value)
IntegerAttr getI64IntegerAttr(int64_t value)
IntegerType getIntegerType(unsigned width)
ArrayAttr getI64ArrayAttr(ArrayRef< int64_t > values)
MLIRContext is the top-level object for a collection of MLIR operations.
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult parseRegion(Region ®ion, ArrayRef< Argument > arguments={}, bool enableNameShadowing=false)=0
Parses a region.
virtual ParseResult parseArgument(Argument &result, bool allowType=false, bool allowAttrs=false)=0
Parse a single argument with the following syntax:
virtual ParseResult parseArgumentList(SmallVectorImpl< Argument > &result, Delimiter delimiter=Delimiter::None, bool allowType=false, bool allowAttrs=false)=0
Parse zero or more arguments with a specified surrounding delimiter.
ParseResult parseAssignmentList(SmallVectorImpl< Argument > &lhs, SmallVectorImpl< UnresolvedOperand > &rhs)
Parse a list of assignments of the form (x1 = y1, x2 = y2, ...)
virtual ParseResult resolveOperand(const UnresolvedOperand &operand, Type type, SmallVectorImpl< Value > &result)=0
Resolve an operand to an SSA value, emitting an error on failure.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printRegion(Region &blocks, bool printEntryBlockArgs=true, bool printBlockTerminators=true, bool printEmptyBlock=false)=0
Prints a region.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes={}, ArrayRef< Location > locs={})
Add new block with 'argTypes' arguments and set the insertion point to the end of it.
Operation is the basic unit of execution within MLIR.
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
operand_range getOperands()
Returns an iterator on the underlying Value's.
result_range getResults()
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
Type-safe wrapper around a void* for passing properties, including the properties structs of operatio...
This class provides an abstraction over the different types of ranges over Regions.
bool isOperation() const
Return true if the successor is an operation.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
unsigned getNumArguments()
BlockArgument getArgument(unsigned i)
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void finalizeOpModification(Operation *op)
This method is used to signal the end of an in-place modification of the given operation.
virtual void startOpModification(Operation *op)
This method is used to notify the rewriter that an in-place operation modification is about to happen...
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isInteger() const
Return true if this is an integer type (with the specified width).
This class provides an abstraction over the different types of ranges over Values.
type_range getType() const
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
A simple wrapper to encode a bitset of (at most 64) levels, currently used by sparse_tensor....
iterator_range< const_set_bits_iterator > bits() const
I64BitSet & set(unsigned i)
A wrapper around RankedTensorType, which has three goals:
bool isSingletonLvl(Level l) const
SmallVector< Size > getBatchLvlShape() const
Returns the batched level-shape.
MLIRContext * getContext() const
Type getElementType() const
bool isLooseCompressedLvl(Level l) const
unsigned getCrdWidth() const
Returns the coordinate-overhead bitwidth, defaulting to zero.
bool hasEncoding() const
Returns true for tensors which have an encoding, and false for those which do not.
bool isAllOrdered() const
Returns true for tensors where every level is ordered.
bool isCOOType(Level startLvl=0, bool isUnique=true) const
Returns true iff this sparse tensor type has a trailing COO region starting at the given level.
Dimension getDimRank() const
Returns the dimension-rank.
AffineMap getLvlToDim() const
Returns the lvlToDiml mapping (or the null-map for the identity).
Attribute getImplicitVal() const
Returns the implicit value, defaulting to null Attribute for 0.
bool isAllDense() const
Returns true for tensors where every level is dense.
Type getCrdType() const
Returns the coordinate-overhead MLIR type, defaulting to IndexType.
bool isIdentity() const
Returns true if the dimToLvl mapping is the identity.
bool hasSameDimToLvl(const SparseTensorType &other) const
Returns true iff the two types have the same mapping.
ArrayRef< Size > getDimShape() const
Returns the dimension-shape.
SmallVector< Size > getLvlShape() const
Returns the level-shape.
bool isCompressedLvl(Level l) const
bool hasStaticDimShape() const
Returns true if no dimension has dynamic size.
Level getLvlRank() const
Returns the level-rank.
ArrayRef< LevelType > getLvlTypes() const
unsigned getPosWidth() const
Returns the position-overhead bitwidth, defaulting to zero.
RankedTensorType getCOOType(bool ordered) const
Returns [un]ordered COO type for this sparse tensor type.
SparseTensorEncodingAttr getEncoding() const
Level getAoSCOOStart() const
Returns the starting level of this sparse tensor type for a trailing COO region that spans at least t...
LevelType getLvlType(Level l) const
AffineMap getDimToLvl() const
Returns the dimToLvl mapping (or the null-map for the identity).
Attribute getExplicitVal() const
Returns the explicit value, defaulting to null Attribute for unset.
Type getPosType() const
Returns the position-overhead MLIR type, defaulting to IndexType.
bool isUniqueLvl(Level l) const
Provides methods to access fields of a sparse tensor with the given encoding.
unsigned getNumDataFields() const
Gets the total number of data fields (coordinate arrays, position arrays, and a value array) for the ...
unsigned getNumFields() const
Gets the total number of fields for the given sparse tensor encoding.
void foreachField(llvm::function_ref< bool(FieldIndex, SparseTensorFieldKind, Level, LevelType)>) const
For each field that will be allocated for the given sparse tensor encoding, calls the callback with t...
std::pair< FieldIndex, unsigned > getFieldIndexAndStride(SparseTensorFieldKind kind, std::optional< Level > lvl) const
Parses the Sparse Tensor Encoding Attribute (STEA).
Speculatability
This enum is returned from the getSpeculatability method in the ConditionallySpeculatable op interfac...
constexpr auto Speculatable
constexpr auto NotSpeculatable
DynamicAPInt getIndex(const ConeV &cone)
Get the index of a cone, i.e., the volume of the parallelepiped spanned by its generators,...
bool isUniqueLT(LevelType lt)
Value constantIndex(OpBuilder &builder, Location loc, int64_t i)
Generates a constant of index type.
bool isWithCrdLT(LevelType lt)
std::optional< LevelType > buildLevelType(LevelFormat lf, const std::vector< LevelPropNonDefault > &properties, uint64_t n=0, uint64_t m=0)
uint64_t Dimension
The type of dimension identifiers and dimension-ranks.
bool isWithPosLT(LevelType lt)
bool isOrderedLT(LevelType lt)
std::string toMLIRString(LevelType lt)
Dimension toDim(SparseTensorEncodingAttr enc, Level l)
Convenience method to translate the given level to the corresponding dimension.
void foreachFieldAndTypeInSparseTensor(SparseTensorType, llvm::function_ref< bool(Type, FieldIndex, SparseTensorFieldKind, Level, LevelType)>)
bool isSingletonLT(LevelType lt)
static llvm::hash_code hash_value(LevelType lt)
uint64_t getN(LevelType lt)
unsigned FieldIndex
The type of field indices.
uint64_t Level
The type of level identifiers and level-ranks.
AffineMap inferLvlToDim(AffineMap dimToLvl, MLIRContext *context)
Given the dimToLvl map, infers the lvlToDim map, or returns empty Affine map when inference fails.
SparseTensorEncodingAttr getSparseTensorEncoding(Type type)
Convenience method to get a sparse encoding attribute from a type.
MemRefType getMemRefType(T &&t)
Convenience method to abbreviate casting getType().
Level toLvl(SparseTensorEncodingAttr enc, Dimension d)
Convenience method to translate the given dimension to the corresponding level.
bool isBlockSparsity(AffineMap dimToLvl)
Given the dimToLvl map, returns if it's block sparsity.
bool isDenseLT(LevelType lt)
uint64_t getM(LevelType lt)
int64_t Size
The type for individual components of a compile-time shape, including the value ShapedType::kDynamic ...
std::optional< SparseTensorType > tryGetSparseTensorType(Value val)
bool hasAnyNonIdentityOperandsOrResults(Operation *op)
Returns true iff MLIR operation has any sparse tensor with non-identity dim2lvl maps.
SparseTensorType getSparseTensorType(Value val)
Convenience methods to obtain a SparseTensorType from a Value.
SparseTensorFieldKind
===-------------------------------------------------------------------—===// The sparse tensor storag...
bool isBatchLT(LevelType lt)
SmallVector< unsigned > getBlockSize(AffineMap dimToLvl)
Given the dimToLvl map, returns the block sizes in a vector.
AffineMap inverseBlockSparsity(AffineMap dimToLvl, MLIRContext *context)
Returns the lvlToDim map for the given dimToLvl map specific to the block sparse cases.
bool isNOutOfMLT(LevelType lt)
Include the generated interface declarations.
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
AffineMap inversePermutation(AffineMap map)
Returns a map of codomain to domain dimensions such that the first codomain dimension for a particula...
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
AffineExpr getAffineBinaryOpExpr(AffineExprKind kind, AffineExpr lhs, AffineExpr rhs)
std::conditional_t< std::is_same_v< Ty, mlir::Type >, mlir::Value, detail::TypedValue< Ty > > TypedValue
If Ty is mlir::Type this will select Value instead of having a wrapper around it.
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols)
Simplify an affine expression by flattening and some amount of simple analysis.
SetVector< Operation * > getSlice(Operation *op, const BackwardSliceOptions &backwardSliceOptions={}, const ForwardSliceOptions &forwardSliceOptions={})
Iteratively computes backward slices and forward slices until a fixed point is reached.
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
LogicalResult verify(Operation *op, bool verifyRecursively=true)
Perform (potentially expensive) checks of invariants, used to detect compiler bugs,...
llvm::function_ref< Fn > function_ref
LogicalResult matchAndRewrite(IterateOp iterateOp, PatternRewriter &rewriter) const override
OpRewritePattern Base
Type alias to allow derived classes to inherit constructors with using Base::Base;.
OpRewritePattern(MLIRContext *context, PatternBenefit benefit=1, ArrayRef< StringRef > generatedNames={})
This represents an operation in an abstracted form, suitable for use with the builder APIs.
T & getOrAddProperties()
Get (or create) the properties of the provided type to be set on the operation on creation.
SmallVector< Value, 4 > operands
void addOperands(ValueRange newOperands)
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
void addTypes(ArrayRef< Type > newTypes)
SmallVector< Type, 4 > types
Types of the results of this operation.
Region * addRegion()
Create a region that should be attached to the operation.
A simple structure that encodes a range of levels in the sparse tensors that forms a COO segment.
This enum defines all the sparse representations supportable by the SparseTensor dialect.
constexpr bool isa() const
Check if the LevelType is in the LevelFormat.
LevelType stripStorageIrrelevantProperties() const