@@ -1598,9 +1598,14 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
15981598 (inputWidth == ShapedType::kDynamic ))
15991599 return failure ();
16001600
1601- llvm::ArrayRef<int64_t > scaleInt = adaptor.getScale ();
1602- llvm::ArrayRef<int64_t > offsetInt = adaptor.getOffset ();
1603- llvm::ArrayRef<int64_t > borderInt = adaptor.getBorder ();
1601+ SmallVector<int64_t > scaleInt, offsetInt, borderInt;
1602+ if (!tosa::getConstShapeValue (adaptor.getScale ().getDefiningOp (), scaleInt) ||
1603+ !tosa::getConstShapeValue (adaptor.getOffset ().getDefiningOp (),
1604+ offsetInt) ||
1605+ !tosa::getConstShapeValue (adaptor.getBorder ().getDefiningOp (),
1606+ borderInt)) {
1607+ return failure ();
1608+ }
16041609
16051610 // Compute the output shape based on attributes: scale, offset, and border.
16061611 outputShape[1 ] =
@@ -1617,6 +1622,98 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
16171622 return success ();
16181623}
16191624
1625+ LogicalResult tosa::ResizeOp::verify () {
1626+ const Value input = getInput ();
1627+ const Value output = getOutput ();
1628+ const RankedTensorType inputType =
1629+ llvm::dyn_cast<RankedTensorType>(input.getType ());
1630+ const RankedTensorType outputType =
1631+ llvm::dyn_cast<RankedTensorType>(output.getType ());
1632+
1633+ if (!inputType)
1634+ return emitOpError (" expect a ranked input tensor" );
1635+ if (!outputType)
1636+ return emitOpError (" expect a ranked output tensor" );
1637+
1638+ const int64_t oh = outputType.getDimSize (1 );
1639+ const int64_t ow = outputType.getDimSize (2 );
1640+ const int64_t ih = inputType.getDimSize (1 );
1641+ const int64_t iw = inputType.getDimSize (2 );
1642+
1643+ SmallVector<int64_t > scaleValues;
1644+ SmallVector<int64_t > offsetValues;
1645+ SmallVector<int64_t > borderValues;
1646+ if (!tosa::getConstShapeValue (getScale ().getDefiningOp (), scaleValues) ||
1647+ !tosa::getConstShapeValue (getOffset ().getDefiningOp (), offsetValues) ||
1648+ !tosa::getConstShapeValue (getBorder ().getDefiningOp (), borderValues)) {
1649+ // Skip following checks if shape is not constant
1650+ return success ();
1651+ }
1652+
1653+ if (llvm::any_of (scaleValues, [](int64_t s) { return s <= 0 ; }))
1654+ return emitOpError (" expect all scale values to be > 0, got " )
1655+ << scaleValues;
1656+
1657+ const int64_t scaleYN = scaleValues[0 ];
1658+ const int64_t scaleYD = scaleValues[1 ];
1659+ const int64_t scaleXN = scaleValues[2 ];
1660+ const int64_t scaleXD = scaleValues[3 ];
1661+
1662+ const int64_t offsetY = offsetValues[0 ];
1663+ const int64_t offsetX = offsetValues[1 ];
1664+
1665+ const int64_t borderY = borderValues[0 ];
1666+ const int64_t borderX = borderValues[1 ];
1667+
1668+ auto idivCheck = [](const int64_t lhs,
1669+ const int64_t rhs) -> std::optional<int64_t > {
1670+ if (lhs % rhs != 0 )
1671+ return std::nullopt ;
1672+ return lhs / rhs;
1673+ };
1674+
1675+ // Don't check with input height that could be broadcast (ih != 1)
1676+ // since Linalg, a consumer of TOSA, expects broadcasting support
1677+ // in resize to be available. Taking the cautious approach for now,
1678+ // we can consider removing support for broadcasting later.
1679+ if (ih != ShapedType::kDynamic && ih != 1 ) {
1680+ const std::optional<int64_t > calculatedOutHeightMinusOne =
1681+ idivCheck ((ih - 1 ) * scaleYN - offsetY + borderY, scaleYD);
1682+ if (!calculatedOutHeightMinusOne.has_value ())
1683+ return emitOpError (" expected (input_height - 1) * scale_y_n - offset_y + "
1684+ " border_y " )
1685+ << " to be wholly divisible by scale_y_d, got ((" << ih
1686+ << " - 1) * " << scaleYN << " - " << offsetY << " + " << borderY
1687+ << " ) / " << scaleYD;
1688+ const int64_t calculatedOutHeight = calculatedOutHeightMinusOne.value () + 1 ;
1689+ if (oh != ShapedType::kDynamic && calculatedOutHeight != oh)
1690+ return emitOpError (" calculated output height did not match expected: " )
1691+ << " calculated=" << calculatedOutHeight << " , expected=" << oh;
1692+ }
1693+
1694+ // Don't check with input width that could be broadcast (iw != 1)
1695+ // since Linalg, a consumer of TOSA, expects broadcasting support
1696+ // in resize to be available. Taking the cautious approach for now,
1697+ // we can consider removing support for broadcasting later.
1698+ if (iw != ShapedType::kDynamic && iw != 1 ) {
1699+ const int64_t scaledInWidth = (iw - 1 ) * scaleXN - offsetX + borderX;
1700+ const std::optional<int64_t > calculatedOutWidthMinusOne =
1701+ idivCheck (scaledInWidth, scaleXD);
1702+ if (!calculatedOutWidthMinusOne.has_value ())
1703+ return emitOpError (" expected (input_width - 1) * scale_x_n - offset_x + "
1704+ " border_x " )
1705+ << " to be wholly divisible by scale_x_d, got ((" << iw
1706+ << " - 1) * " << scaleXN << " - " << offsetX << " + " << borderX
1707+ << " ) / " << scaleXD;
1708+ const int64_t calculatedOutWidth = calculatedOutWidthMinusOne.value () + 1 ;
1709+ if (ow != ShapedType::kDynamic && calculatedOutWidth != ow)
1710+ return emitOpError (" calculated output width did not match expected: " )
1711+ << " calculated=" << calculatedOutWidth << " , expected=" << ow;
1712+ }
1713+
1714+ return success ();
1715+ }
1716+
16201717LogicalResult tosa::ScatterOp::inferReturnTypeComponents (
16211718 MLIRContext *context, ::std::optional<Location> location,
16221719 ScatterOp::Adaptor adaptor,
0 commit comments