@@ -1598,9 +1598,14 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
1598
1598
(inputWidth == ShapedType::kDynamic ))
1599
1599
return failure ();
1600
1600
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
+ }
1604
1609
1605
1610
// Compute the output shape based on attributes: scale, offset, and border.
1606
1611
outputShape[1 ] =
@@ -1617,6 +1622,98 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
1617
1622
return success ();
1618
1623
}
1619
1624
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
+
1620
1717
LogicalResult tosa::ScatterOp::inferReturnTypeComponents (
1621
1718
MLIRContext *context, ::std::optional<Location> location,
1622
1719
ScatterOp::Adaptor adaptor,
0 commit comments