@@ -1689,9 +1689,14 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
16891689 (inputWidth == ShapedType::kDynamic ))
16901690 return failure ();
16911691
1692- llvm::ArrayRef<int64_t > scaleInt = adaptor.getScale ();
1693- llvm::ArrayRef<int64_t > offsetInt = adaptor.getOffset ();
1694- llvm::ArrayRef<int64_t > borderInt = adaptor.getBorder ();
1692+ SmallVector<int64_t > scaleInt, offsetInt, borderInt;
1693+ if (!tosa::getConstShapeValue (adaptor.getScale ().getDefiningOp (), scaleInt) ||
1694+ !tosa::getConstShapeValue (adaptor.getOffset ().getDefiningOp (),
1695+ offsetInt) ||
1696+ !tosa::getConstShapeValue (adaptor.getBorder ().getDefiningOp (),
1697+ borderInt)) {
1698+ return failure ();
1699+ }
16951700
16961701 // Compute the output shape based on attributes: scale, offset, and border.
16971702 outputShape[1 ] =
@@ -1708,6 +1713,98 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
17081713 return success ();
17091714}
17101715
1716+ LogicalResult tosa::ResizeOp::verify () {
1717+ const Value input = getInput ();
1718+ const Value output = getOutput ();
1719+ const RankedTensorType inputType =
1720+ llvm::dyn_cast<RankedTensorType>(input.getType ());
1721+ const RankedTensorType outputType =
1722+ llvm::dyn_cast<RankedTensorType>(output.getType ());
1723+
1724+ if (!inputType)
1725+ return emitOpError (" expect a ranked input tensor" );
1726+ if (!outputType)
1727+ return emitOpError (" expect a ranked output tensor" );
1728+
1729+ const int64_t oh = outputType.getDimSize (1 );
1730+ const int64_t ow = outputType.getDimSize (2 );
1731+ const int64_t ih = inputType.getDimSize (1 );
1732+ const int64_t iw = inputType.getDimSize (2 );
1733+
1734+ SmallVector<int64_t > scaleValues;
1735+ SmallVector<int64_t > offsetValues;
1736+ SmallVector<int64_t > borderValues;
1737+ if (!tosa::getConstShapeValue (getScale ().getDefiningOp (), scaleValues) ||
1738+ !tosa::getConstShapeValue (getOffset ().getDefiningOp (), offsetValues) ||
1739+ !tosa::getConstShapeValue (getBorder ().getDefiningOp (), borderValues)) {
1740+ // Skip following checks if shape is not constant
1741+ return success ();
1742+ }
1743+
1744+ if (llvm::any_of (scaleValues, [](int64_t s) { return s <= 0 ; }))
1745+ return emitOpError (" expect all scale values to be > 0, got " )
1746+ << scaleValues;
1747+
1748+ const int64_t scaleYN = scaleValues[0 ];
1749+ const int64_t scaleYD = scaleValues[1 ];
1750+ const int64_t scaleXN = scaleValues[2 ];
1751+ const int64_t scaleXD = scaleValues[3 ];
1752+
1753+ const int64_t offsetY = offsetValues[0 ];
1754+ const int64_t offsetX = offsetValues[1 ];
1755+
1756+ const int64_t borderY = borderValues[0 ];
1757+ const int64_t borderX = borderValues[1 ];
1758+
1759+ auto idivCheck = [](const int64_t lhs,
1760+ const int64_t rhs) -> std::optional<int64_t > {
1761+ if (lhs % rhs != 0 )
1762+ return std::nullopt ;
1763+ return lhs / rhs;
1764+ };
1765+
1766+ // Don't check with input height that could be broadcast (ih != 1)
1767+ // since Linalg, a consumer of TOSA, expects broadcasting support
1768+ // in resize to be available. Taking the cautious approach for now,
1769+ // we can consider removing support for broadcasting later.
1770+ if (ih != ShapedType::kDynamic && ih != 1 ) {
1771+ const std::optional<int64_t > calculatedOutHeightMinusOne =
1772+ idivCheck ((ih - 1 ) * scaleYN - offsetY + borderY, scaleYD);
1773+ if (!calculatedOutHeightMinusOne.has_value ())
1774+ return emitOpError (" expected (input_height - 1) * scale_y_n - offset_y + "
1775+ " border_y " )
1776+ << " to be wholly divisible by scale_y_d, got ((" << ih
1777+ << " - 1) * " << scaleYN << " - " << offsetY << " + " << borderY
1778+ << " ) / " << scaleYD;
1779+ const int64_t calculatedOutHeight = calculatedOutHeightMinusOne.value () + 1 ;
1780+ if (oh != ShapedType::kDynamic && calculatedOutHeight != oh)
1781+ return emitOpError (" calculated output height did not match expected: " )
1782+ << " calculated=" << calculatedOutHeight << " , expected=" << oh;
1783+ }
1784+
1785+ // Don't check with input width that could be broadcast (iw != 1)
1786+ // since Linalg, a consumer of TOSA, expects broadcasting support
1787+ // in resize to be available. Taking the cautious approach for now,
1788+ // we can consider removing support for broadcasting later.
1789+ if (iw != ShapedType::kDynamic && iw != 1 ) {
1790+ const int64_t scaledInWidth = (iw - 1 ) * scaleXN - offsetX + borderX;
1791+ const std::optional<int64_t > calculatedOutWidthMinusOne =
1792+ idivCheck (scaledInWidth, scaleXD);
1793+ if (!calculatedOutWidthMinusOne.has_value ())
1794+ return emitOpError (" expected (input_width - 1) * scale_x_n - offset_x + "
1795+ " border_x " )
1796+ << " to be wholly divisible by scale_x_d, got ((" << iw
1797+ << " - 1) * " << scaleXN << " - " << offsetX << " + " << borderX
1798+ << " ) / " << scaleXD;
1799+ const int64_t calculatedOutWidth = calculatedOutWidthMinusOne.value () + 1 ;
1800+ if (ow != ShapedType::kDynamic && calculatedOutWidth != ow)
1801+ return emitOpError (" calculated output width did not match expected: " )
1802+ << " calculated=" << calculatedOutWidth << " , expected=" << ow;
1803+ }
1804+
1805+ return success ();
1806+ }
1807+
17111808LogicalResult tosa::ScatterOp::inferReturnTypeComponents (
17121809 MLIRContext *context, ::std::optional<Location> location,
17131810 ScatterOp::Adaptor adaptor,
0 commit comments