1319072f4SAart Bik //===- SparseTensorDialect.cpp - Sparse tensor dialect implementation -----===//
2319072f4SAart Bik //
3319072f4SAart Bik // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4319072f4SAart Bik // See https://llvm.org/LICENSE.txt for license information.
5319072f4SAart Bik // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6319072f4SAart Bik //
7319072f4SAart Bik //===----------------------------------------------------------------------===//
8319072f4SAart Bik 
9319072f4SAart Bik #include "mlir/Dialect/SparseTensor/IR/SparseTensor.h"
105517208dSAart Bik 
11319072f4SAart Bik #include "mlir/IR/Builders.h"
120a292199SAart Bik #include "mlir/IR/DialectImplementation.h"
1365e7cd13SRiver Riddle #include "mlir/IR/Matchers.h"
14319072f4SAart Bik #include "mlir/IR/OpImplementation.h"
150a292199SAart Bik #include "llvm/ADT/TypeSwitch.h"
16319072f4SAart Bik 
17319072f4SAart Bik using namespace mlir;
18319072f4SAart Bik using namespace mlir::sparse_tensor;
19319072f4SAart Bik 
200a292199SAart Bik //===----------------------------------------------------------------------===//
2196a23911SAart Bik // TensorDialect Attribute Methods.
220a292199SAart Bik //===----------------------------------------------------------------------===//
230a292199SAart Bik 
240a292199SAart Bik #define GET_ATTRDEF_CLASSES
250a292199SAart Bik #include "mlir/Dialect/SparseTensor/IR/SparseTensorAttrDefs.cpp.inc"
260a292199SAart Bik 
270a292199SAart Bik static bool acceptBitWidth(unsigned bitWidth) {
280a292199SAart Bik   switch (bitWidth) {
290a292199SAart Bik   case 0:
300a292199SAart Bik   case 8:
310a292199SAart Bik   case 16:
320a292199SAart Bik   case 32:
330a292199SAart Bik   case 64:
340a292199SAart Bik     return true;
350a292199SAart Bik   default:
360a292199SAart Bik     return false;
370a292199SAart Bik   }
380a292199SAart Bik }
390a292199SAart Bik 
40f97e72aaSMehdi Amini Attribute SparseTensorEncodingAttr::parse(AsmParser &parser, Type type) {
410a292199SAart Bik   if (failed(parser.parseLess()))
420a292199SAart Bik     return {};
430a292199SAart Bik   // Parse the data as a dictionary.
440a292199SAart Bik   DictionaryAttr dict;
450a292199SAart Bik   if (failed(parser.parseAttribute(dict)))
460a292199SAart Bik     return {};
470a292199SAart Bik   if (failed(parser.parseGreater()))
480a292199SAart Bik     return {};
490a292199SAart Bik   // Process the data from the parsed dictionary value into struct-like data.
500a292199SAart Bik   SmallVector<SparseTensorEncodingAttr::DimLevelType, 4> dlt;
510a292199SAart Bik   AffineMap map = {};
520a292199SAart Bik   unsigned ptr = 0;
530a292199SAart Bik   unsigned ind = 0;
540a292199SAart Bik   for (const NamedAttribute &attr : dict) {
550c7890c8SRiver Riddle     if (attr.getName() == "dimLevelType") {
560c7890c8SRiver Riddle       auto arrayAttr = attr.getValue().dyn_cast<ArrayAttr>();
570a292199SAart Bik       if (!arrayAttr) {
580a292199SAart Bik         parser.emitError(parser.getNameLoc(),
590a292199SAart Bik                          "expected an array for dimension level types");
600a292199SAart Bik         return {};
610a292199SAart Bik       }
62e5639b3fSMehdi Amini       for (auto i : arrayAttr) {
63e5639b3fSMehdi Amini         auto strAttr = i.dyn_cast<StringAttr>();
640a292199SAart Bik         if (!strAttr) {
650a292199SAart Bik           parser.emitError(parser.getNameLoc(),
660a292199SAart Bik                            "expected a string value in dimension level types");
670a292199SAart Bik           return {};
680a292199SAart Bik         }
690a292199SAart Bik         auto strVal = strAttr.getValue();
700a292199SAart Bik         if (strVal == "dense") {
710a292199SAart Bik           dlt.push_back(SparseTensorEncodingAttr::DimLevelType::Dense);
720a292199SAart Bik         } else if (strVal == "compressed") {
730a292199SAart Bik           dlt.push_back(SparseTensorEncodingAttr::DimLevelType::Compressed);
740a292199SAart Bik         } else if (strVal == "singleton") {
750a292199SAart Bik           dlt.push_back(SparseTensorEncodingAttr::DimLevelType::Singleton);
760a292199SAart Bik         } else {
770a292199SAart Bik           parser.emitError(parser.getNameLoc(),
780a292199SAart Bik                            "unexpected dimension level type: ")
790a292199SAart Bik               << strVal;
800a292199SAart Bik           return {};
810a292199SAart Bik         }
820a292199SAart Bik       }
830c7890c8SRiver Riddle     } else if (attr.getName() == "dimOrdering") {
840c7890c8SRiver Riddle       auto affineAttr = attr.getValue().dyn_cast<AffineMapAttr>();
850a292199SAart Bik       if (!affineAttr) {
860a292199SAart Bik         parser.emitError(parser.getNameLoc(),
870a292199SAart Bik                          "expected an affine map for dimension ordering");
880a292199SAart Bik         return {};
890a292199SAart Bik       }
900a292199SAart Bik       map = affineAttr.getValue();
910c7890c8SRiver Riddle     } else if (attr.getName() == "pointerBitWidth") {
920c7890c8SRiver Riddle       auto intAttr = attr.getValue().dyn_cast<IntegerAttr>();
930a292199SAart Bik       if (!intAttr) {
940a292199SAart Bik         parser.emitError(parser.getNameLoc(),
950a292199SAart Bik                          "expected an integral pointer bitwidth");
960a292199SAart Bik         return {};
970a292199SAart Bik       }
980a292199SAart Bik       ptr = intAttr.getInt();
990c7890c8SRiver Riddle     } else if (attr.getName() == "indexBitWidth") {
1000c7890c8SRiver Riddle       auto intAttr = attr.getValue().dyn_cast<IntegerAttr>();
1010a292199SAart Bik       if (!intAttr) {
1020a292199SAart Bik         parser.emitError(parser.getNameLoc(),
1030a292199SAart Bik                          "expected an integral index bitwidth");
1040a292199SAart Bik         return {};
1050a292199SAart Bik       }
1060a292199SAart Bik       ind = intAttr.getInt();
1070a292199SAart Bik     } else {
1080a292199SAart Bik       parser.emitError(parser.getNameLoc(), "unexpected key: ")
1090c7890c8SRiver Riddle           << attr.getName().strref();
1100a292199SAart Bik       return {};
1110a292199SAart Bik     }
1120a292199SAart Bik   }
1130a292199SAart Bik   // Construct struct-like storage for attribute.
114fb093c83SChris Lattner   return parser.getChecked<SparseTensorEncodingAttr>(parser.getContext(), dlt,
115fb093c83SChris Lattner                                                      map, ptr, ind);
1160a292199SAart Bik }
1170a292199SAart Bik 
118f97e72aaSMehdi Amini void SparseTensorEncodingAttr::print(AsmPrinter &printer) const {
1190a292199SAart Bik   // Print the struct-like storage in dictionary fashion.
120f30a8a6fSMehdi Amini   printer << "<{ dimLevelType = [ ";
1210a292199SAart Bik   for (unsigned i = 0, e = getDimLevelType().size(); i < e; i++) {
1220a292199SAart Bik     switch (getDimLevelType()[i]) {
1230a292199SAart Bik     case DimLevelType::Dense:
1240a292199SAart Bik       printer << "\"dense\"";
1250a292199SAart Bik       break;
1260a292199SAart Bik     case DimLevelType::Compressed:
1270a292199SAart Bik       printer << "\"compressed\"";
1280a292199SAart Bik       break;
1290a292199SAart Bik     case DimLevelType::Singleton:
1300a292199SAart Bik       printer << "\"singleton\"";
1310a292199SAart Bik       break;
1320a292199SAart Bik     }
1330a292199SAart Bik     if (i != e - 1)
1340a292199SAart Bik       printer << ", ";
1350a292199SAart Bik   }
1360a292199SAart Bik   printer << " ]";
1370a292199SAart Bik   if (getDimOrdering())
1380a292199SAart Bik     printer << ", dimOrdering = affine_map<" << getDimOrdering() << ">";
1390a292199SAart Bik   printer << ", pointerBitWidth = " << getPointerBitWidth()
1400a292199SAart Bik           << ", indexBitWidth = " << getIndexBitWidth() << " }>";
1410a292199SAart Bik }
1420a292199SAart Bik 
1430a292199SAart Bik LogicalResult SparseTensorEncodingAttr::verify(
1440a292199SAart Bik     function_ref<InFlightDiagnostic()> emitError,
1450a292199SAart Bik     ArrayRef<DimLevelType> dimLevelType, AffineMap dimOrdering,
1460a292199SAart Bik     unsigned pointerBitWidth, unsigned indexBitWidth) {
1470a292199SAart Bik   if (!acceptBitWidth(pointerBitWidth))
1480a292199SAart Bik     return emitError() << "unexpected pointer bitwidth: " << pointerBitWidth;
1490a292199SAart Bik   if (!acceptBitWidth(indexBitWidth))
1500a292199SAart Bik     return emitError() << "unexpected index bitwidth: " << indexBitWidth;
1510a292199SAart Bik   if (dimOrdering) {
1520a292199SAart Bik     if (!dimOrdering.isPermutation())
1530a292199SAart Bik       return emitError()
1540a292199SAart Bik              << "expected a permutation affine map for dimension ordering";
1550a292199SAart Bik     if (dimOrdering.getNumResults() != dimLevelType.size())
1560a292199SAart Bik       return emitError() << "unexpected mismatch in ordering and dimension "
1570a292199SAart Bik                             "level types size";
1580a292199SAart Bik   }
1590a292199SAart Bik   return success();
1600a292199SAart Bik }
1610a292199SAart Bik 
1620a292199SAart Bik LogicalResult SparseTensorEncodingAttr::verifyEncoding(
1630a292199SAart Bik     ArrayRef<int64_t> shape, Type elementType,
1640a292199SAart Bik     function_ref<InFlightDiagnostic()> emitError) const {
1650a292199SAart Bik   // Check structural integrity.
1660a292199SAart Bik   if (failed(verify(emitError, getDimLevelType(), getDimOrdering(),
1670a292199SAart Bik                     getPointerBitWidth(), getIndexBitWidth())))
1680a292199SAart Bik     return failure();
1690a292199SAart Bik   // Check integrity with tensor type specifics. Dimension ordering is optional,
1700a292199SAart Bik   // but we always should have dimension level types for the full rank.
1710a292199SAart Bik   unsigned size = shape.size();
1724aa9b398SAart Bik   if (size == 0)
1734aa9b398SAart Bik     return emitError() << "expected non-scalar sparse tensor";
1740a292199SAart Bik   if (getDimOrdering() && getDimOrdering().getNumResults() != size)
1750a292199SAart Bik     return emitError() << "expected an affine map of size " << size
1760a292199SAart Bik                        << " for dimension ordering";
1770a292199SAart Bik   if (getDimLevelType().size() != size)
1780a292199SAart Bik     return emitError() << "expected an array of size " << size
1790a292199SAart Bik                        << " for dimension level types";
1800a292199SAart Bik   return success();
1810a292199SAart Bik }
1820a292199SAart Bik 
18396a23911SAart Bik SparseTensorEncodingAttr
18496a23911SAart Bik mlir::sparse_tensor::getSparseTensorEncoding(Type type) {
18596a23911SAart Bik   if (auto ttp = type.dyn_cast<RankedTensorType>())
18696a23911SAart Bik     return ttp.getEncoding().dyn_cast_or_null<SparseTensorEncodingAttr>();
18796a23911SAart Bik   return nullptr;
18896a23911SAart Bik }
18996a23911SAart Bik 
1900a292199SAart Bik //===----------------------------------------------------------------------===//
19196a23911SAart Bik // TensorDialect Operations.
19296a23911SAart Bik //===----------------------------------------------------------------------===//
19396a23911SAart Bik 
19496a23911SAart Bik static LogicalResult isInBounds(Value dim, Value tensor) {
19565e7cd13SRiver Riddle   IntegerAttr constantAttr;
19665e7cd13SRiver Riddle   if (matchPattern(dim, m_Constant(&constantAttr))) {
19765e7cd13SRiver Riddle     unsigned d = constantAttr.getInt();
19896a23911SAart Bik     if (d >= tensor.getType().cast<RankedTensorType>().getRank())
19996a23911SAart Bik       return failure();
20096a23911SAart Bik   }
20196a23911SAart Bik   return success(); // in bounds, or symbolic
20296a23911SAart Bik }
20396a23911SAart Bik 
20496a23911SAart Bik static LogicalResult isMatchingWidth(Value result, unsigned width) {
20596a23911SAart Bik   Type etp = result.getType().cast<MemRefType>().getElementType();
20696a23911SAart Bik   if ((width == 0 && etp.isIndex()) || (width > 0 && etp.isInteger(width)))
20796a23911SAart Bik     return success();
20896a23911SAart Bik   return failure();
20996a23911SAart Bik }
21096a23911SAart Bik 
211b98dc035SRiver Riddle LogicalResult NewOp::verify() {
212b98dc035SRiver Riddle   if (!getSparseTensorEncoding(result().getType()))
213b98dc035SRiver Riddle     return emitError("expected a sparse tensor result");
21496a23911SAart Bik   return success();
21596a23911SAart Bik }
21696a23911SAart Bik 
217b98dc035SRiver Riddle LogicalResult InitOp::verify() {
218b98dc035SRiver Riddle   if (!getSparseTensorEncoding(result().getType()))
219b98dc035SRiver Riddle     return emitError("expected a sparse tensor result");
220b98dc035SRiver Riddle   RankedTensorType ttp = getType().cast<RankedTensorType>();
22135517a25SAart Bik   unsigned rank = ttp.getRank();
222b98dc035SRiver Riddle   if (rank != sizes().size())
223b98dc035SRiver Riddle     return emitError("unexpected mismatch between tensor rank and sizes: ")
224b98dc035SRiver Riddle            << rank << " vs. " << sizes().size();
22535517a25SAart Bik   auto shape = ttp.getShape();
22635517a25SAart Bik   for (unsigned i = 0; i < rank; i++) {
22735517a25SAart Bik     if (shape[i] == ShapedType::kDynamicSize)
22835517a25SAart Bik       continue;
22965e7cd13SRiver Riddle     IntegerAttr constantAttr;
230b98dc035SRiver Riddle     if (!matchPattern(sizes()[i], m_Constant(&constantAttr)) ||
23165e7cd13SRiver Riddle         constantAttr.getInt() != shape[i]) {
232b98dc035SRiver Riddle       return emitError("unexpected mismatch with static dimension size ")
23335517a25SAart Bik              << shape[i];
23435517a25SAart Bik     }
23565e7cd13SRiver Riddle   }
23635517a25SAart Bik   return success();
23735517a25SAart Bik }
23835517a25SAart Bik 
239b98dc035SRiver Riddle LogicalResult ConvertOp::verify() {
240b98dc035SRiver Riddle   if (auto tp1 = source().getType().dyn_cast<RankedTensorType>()) {
241b98dc035SRiver Riddle     if (auto tp2 = dest().getType().dyn_cast<RankedTensorType>()) {
2421e6ef0cfSAart Bik       if (tp1.getRank() != tp2.getRank())
243b98dc035SRiver Riddle         return emitError("unexpected conversion mismatch in rank");
244697ea09dSAart Bik       auto shape1 = tp1.getShape();
245697ea09dSAart Bik       auto shape2 = tp2.getShape();
2469d1db3d4SAart Bik       // Accept size matches between the source and the destination type
2479d1db3d4SAart Bik       // (e.g. 10 vs. 10, 10 vs. ?, or ? vs. ?), but reject direct mismatches or
2489d1db3d4SAart Bik       // matches that would need a runtime assert (e.g. 10 vs. 20 or ? vs. 10).
249b98dc035SRiver Riddle       for (unsigned d = 0, rank = tp1.getRank(); d < rank; d++)
2509d1db3d4SAart Bik         if (shape1[d] != shape2[d] && shape2[d] != ShapedType::kDynamicSize)
251b98dc035SRiver Riddle           return emitError("unexpected conversion mismatch in dimension ") << d;
252697ea09dSAart Bik       return success();
253697ea09dSAart Bik     }
254697ea09dSAart Bik   }
255b98dc035SRiver Riddle   return emitError("unexpected type in convert");
256697ea09dSAart Bik }
257697ea09dSAart Bik 
258066d786cSAart Bik OpFoldResult ConvertOp::fold(ArrayRef<Attribute> operands) {
259066d786cSAart Bik   if (getType() == source().getType())
260066d786cSAart Bik     return source();
261066d786cSAart Bik   return {};
262066d786cSAart Bik }
263066d786cSAart Bik 
264b98dc035SRiver Riddle LogicalResult ToPointersOp::verify() {
265b98dc035SRiver Riddle   if (auto e = getSparseTensorEncoding(tensor().getType())) {
266b98dc035SRiver Riddle     if (failed(isInBounds(dim(), tensor())))
267b98dc035SRiver Riddle       return emitError("requested pointers dimension out of bounds");
268b98dc035SRiver Riddle     if (failed(isMatchingWidth(result(), e.getPointerBitWidth())))
269b98dc035SRiver Riddle       return emitError("unexpected type for pointers");
27096a23911SAart Bik     return success();
27196a23911SAart Bik   }
272b98dc035SRiver Riddle   return emitError("expected a sparse tensor to get pointers");
27396a23911SAart Bik }
27496a23911SAart Bik 
275b98dc035SRiver Riddle LogicalResult ToIndicesOp::verify() {
276b98dc035SRiver Riddle   if (auto e = getSparseTensorEncoding(tensor().getType())) {
277b98dc035SRiver Riddle     if (failed(isInBounds(dim(), tensor())))
278b98dc035SRiver Riddle       return emitError("requested indices dimension out of bounds");
279b98dc035SRiver Riddle     if (failed(isMatchingWidth(result(), e.getIndexBitWidth())))
280b98dc035SRiver Riddle       return emitError("unexpected type for indices");
28196a23911SAart Bik     return success();
28296a23911SAart Bik   }
283b98dc035SRiver Riddle   return emitError("expected a sparse tensor to get indices");
28496a23911SAart Bik }
28596a23911SAart Bik 
286b98dc035SRiver Riddle LogicalResult ToValuesOp::verify() {
287b98dc035SRiver Riddle   if (!getSparseTensorEncoding(tensor().getType()))
288b98dc035SRiver Riddle     return emitError("expected a sparse tensor to get values");
289b98dc035SRiver Riddle   RankedTensorType ttp = tensor().getType().cast<RankedTensorType>();
290b98dc035SRiver Riddle   MemRefType mtp = result().getType().cast<MemRefType>();
29196a23911SAart Bik   if (ttp.getElementType() != mtp.getElementType())
292b98dc035SRiver Riddle     return emitError("unexpected mismatch in element types");
29396a23911SAart Bik   return success();
29496a23911SAart Bik }
29596a23911SAart Bik 
296f66e5769SAart Bik //===----------------------------------------------------------------------===//
297f66e5769SAart Bik // TensorDialect Management Operations.
298f66e5769SAart Bik //===----------------------------------------------------------------------===//
299f66e5769SAart Bik 
300b98dc035SRiver Riddle LogicalResult LexInsertOp::verify() {
301b98dc035SRiver Riddle   if (!getSparseTensorEncoding(tensor().getType()))
302b98dc035SRiver Riddle     return emitError("expected a sparse tensor for insertion");
303f66e5769SAart Bik   return success();
304f66e5769SAart Bik }
305f66e5769SAart Bik 
306b98dc035SRiver Riddle LogicalResult ExpandOp::verify() {
307b98dc035SRiver Riddle   if (!getSparseTensorEncoding(tensor().getType()))
308b98dc035SRiver Riddle     return emitError("expected a sparse tensor for expansion");
3094f2ec7f9SAart Bik   return success();
3104f2ec7f9SAart Bik }
3114f2ec7f9SAart Bik 
312b98dc035SRiver Riddle LogicalResult CompressOp::verify() {
313b98dc035SRiver Riddle   if (!getSparseTensorEncoding(tensor().getType()))
314b98dc035SRiver Riddle     return emitError("expected a sparse tensor for compression");
3154f2ec7f9SAart Bik   return success();
3164f2ec7f9SAart Bik }
3174f2ec7f9SAart Bik 
318b98dc035SRiver Riddle LogicalResult LoadOp::verify() {
319b98dc035SRiver Riddle   if (!getSparseTensorEncoding(tensor().getType()))
320b98dc035SRiver Riddle     return emitError("expected a sparse tensor to materialize");
321f66e5769SAart Bik   return success();
322f66e5769SAart Bik }
323f66e5769SAart Bik 
324b98dc035SRiver Riddle LogicalResult ReleaseOp::verify() {
325b98dc035SRiver Riddle   if (!getSparseTensorEncoding(tensor().getType()))
326b98dc035SRiver Riddle     return emitError("expected a sparse tensor to release");
32736b66ab9SAart Bik   return success();
328727a63e0SAart Bik }
329727a63e0SAart Bik 
330b98dc035SRiver Riddle LogicalResult OutOp::verify() {
331b98dc035SRiver Riddle   if (!getSparseTensorEncoding(tensor().getType()))
332b98dc035SRiver Riddle     return emitError("expected a sparse tensor for output");
333efa15f41SAart Bik   return success();
334efa15f41SAart Bik }
335efa15f41SAart Bik 
33696a23911SAart Bik //===----------------------------------------------------------------------===//
337*414ed019SJim Kitchen // TensorDialect Linalg.Generic Operations.
338*414ed019SJim Kitchen //===----------------------------------------------------------------------===//
339*414ed019SJim Kitchen 
340*414ed019SJim Kitchen template <class T>
341*414ed019SJim Kitchen static LogicalResult verifyNumBlockArgs(T *op, Region &region,
342*414ed019SJim Kitchen                                         const char *regionName,
343*414ed019SJim Kitchen                                         TypeRange inputTypes, Type outputType) {
344*414ed019SJim Kitchen   unsigned numArgs = region.getNumArguments();
345*414ed019SJim Kitchen   unsigned expectedNum = inputTypes.size();
346*414ed019SJim Kitchen   if (numArgs != expectedNum)
347*414ed019SJim Kitchen     return op->emitError() << regionName << " region must have exactly "
348*414ed019SJim Kitchen                            << expectedNum << " arguments";
349*414ed019SJim Kitchen 
350*414ed019SJim Kitchen   for (unsigned i = 0; i < numArgs; i++) {
351*414ed019SJim Kitchen     Type typ = region.getArgument(i).getType();
352*414ed019SJim Kitchen     if (typ != inputTypes[i])
353*414ed019SJim Kitchen       return op->emitError() << regionName << " region argument " << (i + 1)
354*414ed019SJim Kitchen                              << " type mismatch";
355*414ed019SJim Kitchen   }
356*414ed019SJim Kitchen   Operation *term = region.front().getTerminator();
357*414ed019SJim Kitchen   YieldOp yield = dyn_cast<YieldOp>(term);
358*414ed019SJim Kitchen   if (!yield)
359*414ed019SJim Kitchen     return op->emitError() << regionName
360*414ed019SJim Kitchen                            << " region must end with sparse_tensor.yield";
361*414ed019SJim Kitchen   if (yield.getOperand().getType() != outputType)
362*414ed019SJim Kitchen     return op->emitError() << regionName << " region yield type mismatch";
363*414ed019SJim Kitchen 
364*414ed019SJim Kitchen   return success();
365*414ed019SJim Kitchen }
366*414ed019SJim Kitchen 
367*414ed019SJim Kitchen LogicalResult BinaryOp::verify() {
368*414ed019SJim Kitchen   NamedAttrList attrs = (*this)->getAttrs();
369*414ed019SJim Kitchen   Type leftType = x().getType();
370*414ed019SJim Kitchen   Type rightType = y().getType();
371*414ed019SJim Kitchen   Type outputType = output().getType();
372*414ed019SJim Kitchen   Region &overlap = overlapRegion();
373*414ed019SJim Kitchen   Region &left = leftRegion();
374*414ed019SJim Kitchen   Region &right = rightRegion();
375*414ed019SJim Kitchen 
376*414ed019SJim Kitchen   // Check correct number of block arguments and return type for each
377*414ed019SJim Kitchen   // non-empty region.
378*414ed019SJim Kitchen   LogicalResult regionResult = success();
379*414ed019SJim Kitchen   if (!overlap.empty()) {
380*414ed019SJim Kitchen     regionResult = verifyNumBlockArgs(
381*414ed019SJim Kitchen         this, overlap, "overlap", TypeRange{leftType, rightType}, outputType);
382*414ed019SJim Kitchen     if (failed(regionResult))
383*414ed019SJim Kitchen       return regionResult;
384*414ed019SJim Kitchen   }
385*414ed019SJim Kitchen   if (!left.empty()) {
386*414ed019SJim Kitchen     regionResult =
387*414ed019SJim Kitchen         verifyNumBlockArgs(this, left, "left", TypeRange{leftType}, outputType);
388*414ed019SJim Kitchen     if (failed(regionResult))
389*414ed019SJim Kitchen       return regionResult;
390*414ed019SJim Kitchen   } else if (left_identity()) {
391*414ed019SJim Kitchen     if (leftType != outputType)
392*414ed019SJim Kitchen       return emitError("left=identity requires first argument to have the same "
393*414ed019SJim Kitchen                        "type as the output");
394*414ed019SJim Kitchen   }
395*414ed019SJim Kitchen   if (!right.empty()) {
396*414ed019SJim Kitchen     regionResult = verifyNumBlockArgs(this, right, "right",
397*414ed019SJim Kitchen                                       TypeRange{rightType}, outputType);
398*414ed019SJim Kitchen     if (failed(regionResult))
399*414ed019SJim Kitchen       return regionResult;
400*414ed019SJim Kitchen   } else if (right_identity()) {
401*414ed019SJim Kitchen     if (rightType != outputType)
402*414ed019SJim Kitchen       return emitError("right=identity requires second argument to have the "
403*414ed019SJim Kitchen                        "same type as the output");
404*414ed019SJim Kitchen   }
405*414ed019SJim Kitchen 
406*414ed019SJim Kitchen   return success();
407*414ed019SJim Kitchen }
408*414ed019SJim Kitchen 
409*414ed019SJim Kitchen LogicalResult UnaryOp::verify() {
410*414ed019SJim Kitchen   Type inputType = x().getType();
411*414ed019SJim Kitchen   Type outputType = output().getType();
412*414ed019SJim Kitchen   LogicalResult regionResult = success();
413*414ed019SJim Kitchen 
414*414ed019SJim Kitchen   // Check correct number of block arguments and return type for each
415*414ed019SJim Kitchen   // non-empty region.
416*414ed019SJim Kitchen   Region &present = presentRegion();
417*414ed019SJim Kitchen   if (!present.empty()) {
418*414ed019SJim Kitchen     regionResult = verifyNumBlockArgs(this, present, "present",
419*414ed019SJim Kitchen                                       TypeRange{inputType}, outputType);
420*414ed019SJim Kitchen     if (failed(regionResult))
421*414ed019SJim Kitchen       return regionResult;
422*414ed019SJim Kitchen   }
423*414ed019SJim Kitchen   Region &absent = absentRegion();
424*414ed019SJim Kitchen   if (!absent.empty()) {
425*414ed019SJim Kitchen     regionResult =
426*414ed019SJim Kitchen         verifyNumBlockArgs(this, absent, "absent", TypeRange{}, outputType);
427*414ed019SJim Kitchen     if (failed(regionResult))
428*414ed019SJim Kitchen       return regionResult;
429*414ed019SJim Kitchen   }
430*414ed019SJim Kitchen 
431*414ed019SJim Kitchen   return success();
432*414ed019SJim Kitchen }
433*414ed019SJim Kitchen 
434*414ed019SJim Kitchen LogicalResult YieldOp::verify() {
435*414ed019SJim Kitchen   // Check for compatible parent.
436*414ed019SJim Kitchen   auto *parentOp = (*this)->getParentOp();
437*414ed019SJim Kitchen   if (auto binaryOp = dyn_cast<BinaryOp>(parentOp))
438*414ed019SJim Kitchen     return success();
439*414ed019SJim Kitchen   if (auto unaryOp = dyn_cast<UnaryOp>(parentOp))
440*414ed019SJim Kitchen     return success();
441*414ed019SJim Kitchen 
442*414ed019SJim Kitchen   return emitOpError("expected parent op to be sparse_tensor binary or unary");
443*414ed019SJim Kitchen }
444*414ed019SJim Kitchen 
445*414ed019SJim Kitchen //===----------------------------------------------------------------------===//
44696a23911SAart Bik // TensorDialect Methods.
4470a292199SAart Bik //===----------------------------------------------------------------------===//
4480a292199SAart Bik 
449319072f4SAart Bik void SparseTensorDialect::initialize() {
4500a292199SAart Bik   addAttributes<
4510a292199SAart Bik #define GET_ATTRDEF_LIST
4520a292199SAart Bik #include "mlir/Dialect/SparseTensor/IR/SparseTensorAttrDefs.cpp.inc"
4530a292199SAart Bik       >();
454319072f4SAart Bik   addOperations<
455319072f4SAart Bik #define GET_OP_LIST
456319072f4SAart Bik #include "mlir/Dialect/SparseTensor/IR/SparseTensorOps.cpp.inc"
457319072f4SAart Bik       >();
458319072f4SAart Bik }
459319072f4SAart Bik 
460319072f4SAart Bik #define GET_OP_CLASSES
461319072f4SAart Bik #include "mlir/Dialect/SparseTensor/IR/SparseTensorOps.cpp.inc"
4625517208dSAart Bik 
4635517208dSAart Bik #include "mlir/Dialect/SparseTensor/IR/SparseTensorOpsDialect.cpp.inc"
464