@@ -1254,6 +1254,67 @@ LogicalResult mlir::linalg::detail::verifyStructuredOpInterface(Operation *op) {
12541254 if (!linalgOp.getShapesToLoopsMap ())
12551255 return op->emitOpError (" expected the shape-to-loops map to be non-null" );
12561256
1257+ // Check if given shapes match to inferred shapes.
1258+ SmallVector<int64_t , 4 > endLoopRangeValues = linalgOp.getStaticLoopRanges ();
1259+ SmallVector<int64_t , 4 > startLoopRangeValues (endLoopRangeValues.size (), 0 );
1260+ // Verify only static cases since we can't get exact dimension sizes and
1261+ // loop ranges for dynamic cases in this stage.
1262+ if (llvm::none_of (endLoopRangeValues, ShapedType::isDynamic)) {
1263+ for (int64_t &range : endLoopRangeValues)
1264+ range -= 1 ;
1265+ for (OpOperand &opOperand : linalgOp->getOpOperands ()) {
1266+ AffineMap indexingMap = linalgOp.getMatchingIndexingMap (&opOperand);
1267+ SmallVector<int64_t , 4 > startIndices =
1268+ indexingMap.compose (startLoopRangeValues);
1269+ SmallVector<int64_t , 4 > endIndices =
1270+ indexingMap.compose (endLoopRangeValues);
1271+ ArrayRef<int64_t > shape = linalgOp.getShape (&opOperand);
1272+ for (auto dim : llvm::seq<int64_t >(0 , shape.size ())) {
1273+ // Ignore dynamic dimension or the case that the dimension size is 0
1274+ if (ShapedType::isDynamic (shape[dim]) || shape[dim] == 0 )
1275+ continue ;
1276+
1277+ // The first index or last index should be the maximum or the minimum in
1278+ // the inferred index ranges since the range is increasing or
1279+ // decreasing. The size of dimensions of input/output operands and the
1280+ // maximum value + 1 in the inferred range should be the same. But, for
1281+ // now we check if the inferred ranges are in boundary of input/output
1282+ // operands' size or not in case that Affine Expressions are complicated
1283+ // such as d0 * 3
1284+ // + d1 since it is not easy to handle the issues.
1285+ // Found the case that this solution can't check, for example, (d0, d1)
1286+ // -> (d1 - d0)
1287+ int64_t inferredDimSize =
1288+ std::max (startIndices[dim], endIndices[dim]) + 1 ;
1289+ if (std::min (startIndices[dim], endIndices[dim]) < 0 ) {
1290+ std::string mapStr;
1291+ {
1292+ llvm::raw_string_ostream os (mapStr);
1293+ os << indexingMap;
1294+ }
1295+ return op->emitOpError (
1296+ " unexpected result less than 0 at expression #" )
1297+ << dim << " in " << mapStr;
1298+ }
1299+ if (isa<AffineDimExpr>(indexingMap.getResult (dim))) {
1300+ if (inferredDimSize != shape[dim]) {
1301+ return op->emitOpError (" inferred input/output operand #" )
1302+ << opOperand.getOperandNumber () << " has shape's dimension #"
1303+ << dim << " to be " << inferredDimSize << " , but found "
1304+ << shape[dim];
1305+ }
1306+ } else {
1307+ if (inferredDimSize > shape[dim]) {
1308+ return op->emitOpError (" inferred input/output operand #" )
1309+ << opOperand.getOperandNumber () << " has shape's dimension #"
1310+ << dim << " to be greater than or equal to "
1311+ << inferredDimSize << " , but found " << shape[dim];
1312+ }
1313+ }
1314+ }
1315+ }
1316+ }
1317+
12571318 // Check the region has exactly one block.
12581319 if (linalgOp->getNumRegions () != 1 ||
12591320 !llvm::hasSingleElement (linalgOp->getRegion (0 )))
0 commit comments