@@ -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