diff --git a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp --- a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp +++ b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp @@ -20,6 +20,7 @@ #include "mlir/Dialect/Tosa/IR/TosaOps.h" #include "mlir/Dialect/Tosa/Utils/CoversionUtils.h" #include "mlir/Dialect/Utils/ReshapeOpsUtils.h" +#include "mlir/IR/ImplicitLocOpBuilder.h" #include "mlir/IR/Matchers.h" #include "mlir/IR/PatternMatch.h" #include "mlir/Transforms/DialectConversion.h" @@ -1321,7 +1322,104 @@ } }; -class ResizeConverter : public OpRewritePattern { +// Handle the case where the resize operation is a regular broadcast. We +// perform this part separately to avoid generating Extract operations which +// are difficult to vectorize / optimize. +class BroadcastResizeConverter : public OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + LogicalResult matchAndRewrite(tosa::ResizeOp op, + PatternRewriter &rewriter) const final { + Location loc = op.getLoc(); + ImplicitLocOpBuilder builder(loc, rewriter); + auto input = op.getInput(); + auto inputTy = input.getType().cast(); + auto resultTy = op.getType().cast(); + + auto imageH = inputTy.getDimSize(1); + auto imageW = inputTy.getDimSize(2); + + if (imageH != 1 || imageW != 1) { + return rewriter.notifyMatchFailure( + op, "tosa.resize is not a pure broadcast operation"); + } + + // TODO(suderman): These string values should be declared the TOSA dialect. + if (op.getMode() != "NEAREST_NEIGHBOR" && op.getMode() != "BILINEAR") + return failure(); + + const bool isBilinear = op.getMode() == "BILINEAR"; + + SmallVector scale; + getValuesFromIntArrayAttribute(op.getScale(), scale); + + // Collapse the 1 dimensions away. + SmallVector collapseMap(2); + collapseMap[0].push_back(builder.getAffineDimExpr(0)); + collapseMap[1].push_back(builder.getAffineDimExpr(1)); + collapseMap[1].push_back(builder.getAffineDimExpr(2)); + collapseMap[1].push_back(builder.getAffineDimExpr(3)); + + auto collapseTy = + RankedTensorType::get({inputTy.getDimSize(0), inputTy.getDimSize(3)}, + inputTy.getElementType()); + Value collapse = + builder.create(collapseTy, input, collapseMap); + + // Broadcast input to the output shape. + llvm::SmallVector outputDynSize; + if (inputTy.isDynamicDim(0)) + outputDynSize.push_back(builder.create(input, 0)); + + if (inputTy.isDynamicDim(3)) + outputDynSize.push_back(builder.create(input, 3)); + + llvm::SmallVector inputExprs{ + rewriter.getAffineDimExpr(0), + rewriter.getAffineDimExpr(3), + }; + + auto inputMap = AffineMap::get(/*dimCount=*/4, /*symbolCount=*/0, + inputExprs, builder.getContext()); + auto resultMap = rewriter.getMultiDimIdentityMap(resultTy.getRank()); + SmallVector iterators(4, getParallelIteratorTypeName()); + + Value empty = builder.create( + resultTy.getShape(), resultTy.getElementType(), outputDynSize); + + auto generic = builder.create( + resultTy, ValueRange{collapse}, ValueRange{empty}, + ArrayRef{inputMap, resultMap}, iterators, + [=](OpBuilder &b, Location loc, ValueRange args) { + Value value = args[0]; + // This is the quantized case. + if (inputTy.getElementType() != resultTy.getElementType()) { + value = + b.create(loc, resultTy.getElementType(), value); + + if (isBilinear && scale[0] != 0) { + Value scaleY = b.create( + loc, b.getI32IntegerAttr(scale[0])); + value = b.create(loc, value, scaleY); + } + + if (isBilinear && scale[2] != 0) { + Value scaleX = b.create( + loc, b.getI32IntegerAttr(scale[2])); + value = b.create(loc, value, scaleX); + } + } + + b.create(loc, value); + }); + + rewriter.replaceOp(op, generic.getResult(0)); + return success(); + } +}; + +class GenericResizeConverter : public OpRewritePattern { public: using OpRewritePattern::OpRewritePattern; @@ -1351,10 +1449,11 @@ SmallVector affineMaps = { rewriter.getMultiDimIdentityMap(resultTy.getRank())}; + Value resize = input; auto genericOp = rewriter.create( loc, resultTy, ValueRange({}), ValueRange{emptyTensor}, affineMaps, getNParallelLoopsAttrs(resultTy.getRank())); - rewriter.replaceOp(op, genericOp.getResult(0)); + resize = genericOp.getResult(0); OpBuilder::InsertionGuard regionGuard(rewriter); rewriter.createBlock(&genericOp.getRegion(), genericOp.getRegion().end(), @@ -1496,7 +1595,6 @@ ix = rewriter.create(loc, ix, xOffset); // Clamp the to be within the bounds of the input image. - iy = clampIntHelper(loc, iy, hwMin, hMax, rewriter); ix = clampIntHelper(loc, ix, hwMin, wMax, rewriter); @@ -1510,10 +1608,9 @@ loc, input, ValueRange{batch, iy, ix, channel}); rewriter.create(loc, result); - - return success(); } else { - // The mode here must be BILINEAR. This has been checked above. + // The mode here must be BILINEAR. + assert(op.getMode() == "BILINEAR"); Value y0 = iy; Value x0 = ix; @@ -1548,7 +1645,9 @@ if (floatingPointMode) { Value rightPart = dx; - Value leftPart = rewriter.create(loc, xScaleN, dx); + auto oneVal = rewriter.create( + loc, rewriter.getF32FloatAttr(1.0f)); + Value leftPart = rewriter.create(loc, oneVal, dx); y0x0 = rewriter.create(loc, y0x0, leftPart); y0x1 = rewriter.create(loc, y0x1, rightPart); @@ -1559,46 +1658,59 @@ Value bottomAcc = rewriter.create(loc, y1x0, y1x1); Value bottomPart = dy; - Value topPart = rewriter.create(loc, yScaleN, dy); + Value topPart = rewriter.create(loc, oneVal, dy); topAcc = rewriter.create(loc, topAcc, topPart); bottomAcc = rewriter.create(loc, bottomAcc, bottomPart); Value result = rewriter.create(loc, topAcc, bottomAcc); rewriter.create(loc, result); - return success(); - } - y0x0 = rewriter.create(loc, resultElementTy, y0x0); - y0x1 = rewriter.create(loc, resultElementTy, y0x1); - y1x0 = rewriter.create(loc, resultElementTy, y1x0); - y1x1 = rewriter.create(loc, resultElementTy, y1x1); - - if (resultElementTy.getIntOrFloatBitWidth() > 32) { - dx = rewriter.create(loc, resultElementTy, dx); - dy = rewriter.create(loc, resultElementTy, dy); - } - - Value rightPart = dx; - Value leftPart = rewriter.create(loc, xScaleN, dx); - - y0x0 = rewriter.create(loc, y0x0, leftPart); - y0x1 = rewriter.create(loc, y0x1, rightPart); - Value topAcc = rewriter.create(loc, y0x0, y0x1); + } else { + // Perform in quantized space. + y0x0 = rewriter.create(loc, resultElementTy, y0x0); + y0x1 = rewriter.create(loc, resultElementTy, y0x1); + y1x0 = rewriter.create(loc, resultElementTy, y1x0); + y1x1 = rewriter.create(loc, resultElementTy, y1x1); + + if (resultElementTy.getIntOrFloatBitWidth() > 32) { + dx = rewriter.create(loc, resultElementTy, dx); + dy = rewriter.create(loc, resultElementTy, dy); + } - y1x0 = rewriter.create(loc, y1x0, leftPart); - y1x1 = rewriter.create(loc, y1x1, rightPart); - Value bottomAcc = rewriter.create(loc, y1x0, y1x1); + Value topAcc, bottomAcc; + if (imageW == 1) { + topAcc = rewriter.create(loc, y0x0, xScaleN); + bottomAcc = rewriter.create(loc, y1x0, xScaleN); + } else { + Value rightPart = dx; + Value leftPart = rewriter.create(loc, xScaleN, dx); + + y0x0 = rewriter.create(loc, y0x0, leftPart); + y0x1 = rewriter.create(loc, y0x1, rightPart); + topAcc = rewriter.create(loc, y0x0, y0x1); + + y1x0 = rewriter.create(loc, y1x0, leftPart); + y1x1 = rewriter.create(loc, y1x1, rightPart); + bottomAcc = rewriter.create(loc, y1x0, y1x1); + } - Value bottomPart = dy; - Value topPart = rewriter.create(loc, yScaleN, dy); - topAcc = rewriter.create(loc, topAcc, topPart); - bottomAcc = rewriter.create(loc, bottomAcc, bottomPart); - Value result = rewriter.create(loc, topAcc, bottomAcc); + Value result; + if (imageH == 1) { + result = rewriter.create(loc, topAcc, yScaleN); + } else { + Value bottomPart = dy; + Value topPart = rewriter.create(loc, yScaleN, dy); + topAcc = rewriter.create(loc, topAcc, topPart); + bottomAcc = + rewriter.create(loc, bottomAcc, bottomPart); + result = rewriter.create(loc, topAcc, bottomAcc); + } rewriter.create(loc, result); - return success(); + } } - return failure(); + rewriter.replaceOp(op, resize); + return success(); } }; @@ -2210,6 +2322,13 @@ void mlir::tosa::populateTosaToLinalgConversionPatterns( RewritePatternSet *patterns) { + + // We have multiple resize coverters to handle degenerate cases. + patterns->add(patterns->getContext(), + /*benefit=*/100); + patterns->add(patterns->getContext(), + /*benefit=*/200); + patterns->add< // clang-format off PointwiseConverter, @@ -2262,7 +2381,6 @@ ReshapeConverterExpand, ReshapeConverterCollapseExpand, RescaleConverter, - ResizeConverter, ReverseConverter, TableConverter, TileConverter, diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir @@ -0,0 +1,486 @@ +// RUN: mlir-opt --split-input-file -pass-pipeline="func.func(tosa-to-linalg)" %s -o -| FileCheck %s + +// CHECK: #map0 = affine_map<(d0, d1, d2, d3) -> (d0, d3)> +// CHECK: #map1 = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)> +// CHECK-LABEL: @broadcast_resize_nearest_fp +func.func @broadcast_resize_nearest_fp(%arg0 : tensor<3x1x1x7xf32>) -> tensor<3x15x13x7xf32> { + // CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %arg0 + // CHECK-SAME{literal}: [[0], [1, 2, 3]] + // CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<3x15x13x7xf32> + // CHECK: %[[GENERIC:.+]] = linalg.generic + // CHECK-SAME: indexing_maps = [#map0, #map1] + // CHECK-SAME: iterator_types = ["parallel", "parallel", "parallel", "parallel"]} + // CHECK-SAME: ins(%[[COLLAPSE]] : tensor<3x7xf32>) + // CHECK-SAME: outs(%[[EMPTY]] : tensor<3x15x13x7xf32>) + // CHECK-NEXT: ^bb0(%[[IN:.+]]: f32, %[[OUT:.+]]: f32): + // CHECK: linalg.yield %[[IN]] + %resize = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = [2, 2, 1, 1], offset = [0, 0], border = [0, 0]} : (tensor<3x1x1x7xf32>) -> tensor<3x15x13x7xf32> + + // CHECK: return %[[GENERIC]] + return %resize : tensor<3x15x13x7xf32> +} + +// ----- + +// CHECK: #map0 = affine_map<(d0, d1, d2, d3) -> (d0, d3)> +// CHECK: #map1 = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)> +// CHECK-LABEL: @broadcast_resize_bilinear_fp +func.func @broadcast_resize_bilinear_fp(%arg0 : tensor<3x1x1x7xf32>) -> tensor<3x15x13x7xf32> { + // CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %arg0 + // CHECK-SAME{literal}: [[0], [1, 2, 3]] + // CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<3x15x13x7xf32> + // CHECK: %[[GENERIC:.+]] = linalg.generic + // CHECK-SAME: indexing_maps = [#map0, #map1] + // CHECK-SAME: iterator_types = ["parallel", "parallel", "parallel", "parallel"]} + // CHECK-SAME: ins(%[[COLLAPSE]] : tensor<3x7xf32>) + // CHECK-SAME: outs(%[[EMPTY]] : tensor<3x15x13x7xf32>) + // CHECK-NEXT: ^bb0(%[[IN:.+]]: f32, %[[OUT:.+]]: f32): + // CHECK: linalg.yield %[[IN]] + %resize = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = [2, 2, 1, 1], offset = [0, 0], border = [0, 0]} : (tensor<3x1x1x7xf32>) -> tensor<3x15x13x7xf32> + + // CHECK: return %[[GENERIC]] + return %resize : tensor<3x15x13x7xf32> +} + +// ----- + +// CHECK: #map0 = affine_map<(d0, d1, d2, d3) -> (d0, d3)> +// CHECK: #map1 = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)> +// CHECK-LABEL: @broadcast_resize_nearest_i8 +func.func @broadcast_resize_nearest_i8(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x15x13x7xi8> { + // CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %arg0 + // CHECK-SAME{literal}: [[0], [1, 2, 3]] + // CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<3x15x13x7xi8> + // CHECK: %[[GENERIC:.+]] = linalg.generic + // CHECK-SAME: indexing_maps = [#map0, #map1] + // CHECK-SAME: iterator_types = ["parallel", "parallel", "parallel", "parallel"]} + // CHECK-SAME: ins(%[[COLLAPSE]] : tensor<3x7xi8>) + // CHECK-SAME: outs(%[[EMPTY]] : tensor<3x15x13x7xi8>) + // CHECK-NEXT: ^bb0(%[[IN:.+]]: i8, %[[OUT:.+]]: i8): + // CHECK: linalg.yield %[[IN]] + %resize = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = [2, 2, 1, 1], offset = [0, 0], border = [0, 0]} : (tensor<3x1x1x7xi8>) -> tensor<3x15x13x7xi8> + + // CHECK: return %[[GENERIC]] + return %resize : tensor<3x15x13x7xi8> +} + +// ----- + +// CHECK: #map0 = affine_map<(d0, d1, d2, d3) -> (d0, d3)> +// CHECK: #map1 = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)> +// CHECK-LABEL: @broadcast_resize_nearest_i32 +func.func @broadcast_resize_nearest_i32(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x15x13x7xi32> { + // CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %arg0 + // CHECK-SAME{literal}: [[0], [1, 2, 3]] + // CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<3x15x13x7xi32> + // CHECK: %[[GENERIC:.+]] = linalg.generic + // CHECK-SAME: indexing_maps = [#map0, #map1] + // CHECK-SAME: iterator_types = ["parallel", "parallel", "parallel", "parallel"]} + // CHECK-SAME: ins(%[[COLLAPSE]] : tensor<3x7xi8>) + // CHECK-SAME: outs(%[[EMPTY]] : tensor<3x15x13x7xi32>) + // CHECK-NEXT: ^bb0(%[[IN:.+]]: i8, %[[OUT:.+]]: i32): + // CHECK: %[[EXT:.+]] = arith.extsi %[[IN]] : i8 to i32 + // CHECK: linalg.yield %[[EXT]] + %resize = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = [2, 2, 1, 1], offset = [0, 0], border = [0, 0]} : (tensor<3x1x1x7xi8>) -> tensor<3x15x13x7xi32> + + // CHECK: return %[[GENERIC]] + return %resize : tensor<3x15x13x7xi32> +} + +// ----- + +// CHECK: #map0 = affine_map<(d0, d1, d2, d3) -> (d0, d3)> +// CHECK: #map1 = affine_map<(d0, d1, d2, d3) -> (d0, d1, d2, d3)> +// CHECK-LABEL: @broadcast_resize_bilinear_i32 +func.func @broadcast_resize_bilinear_i32(%arg0 : tensor<3x1x1x7xi8>) -> tensor<3x15x13x7xi32> { + // CHECK: %[[COLLAPSE:.+]] = tensor.collapse_shape %arg0 + // CHECK-SAME{literal}: [[0], [1, 2, 3]] + // CHECK: %[[EMPTY:.+]] = tensor.empty() : tensor<3x15x13x7xi32> + // CHECK: %[[GENERIC:.+]] = linalg.generic + // CHECK-SAME: indexing_maps = [#map0, #map1] + // CHECK-SAME: iterator_types = ["parallel", "parallel", "parallel", "parallel"]} + // CHECK-SAME: ins(%[[COLLAPSE]] : tensor<3x7xi8>) + // CHECK-SAME: outs(%[[EMPTY]] : tensor<3x15x13x7xi32>) + // CHECK-NEXT: ^bb0(%[[IN:.+]]: i8, %[[OUT:.+]]: i32): + // CHECK: %[[EXT:.+]] = arith.extsi %[[IN]] : i8 to i32 + // CHECK-DAG: %[[C2:.+]] = arith.constant 2 : i32 + // CHECK: %[[MUL1:.+]] = arith.muli %[[EXT]], %[[C2]] : i32 + // CHECK-DAG: %[[C1:.+]] = arith.constant 1 : i32 + // CHECK: %[[MUL2:.+]] = arith.muli %[[MUL1]], %[[C1]] : i32 + // CHECK: linalg.yield %[[MUL2]] + %resize = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = [2, 2, 1, 1], offset = [0, 0], border = [0, 0]} : (tensor<3x1x1x7xi8>) -> tensor<3x15x13x7xi32> + + // CHECK: return %[[GENERIC]] + return %resize : tensor<3x15x13x7xi32> +} + +// ----- + +// CHECK-LABEL: @resize_nearest_int +func.func @resize_nearest_int(%arg0: tensor<1x15x13x1xi8>) -> () { + // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x23x179x1xi8> + // CHECK: %[[GENERIC:.+]] = linalg.generic + // CHECK: %[[IDX_0:.+]] = linalg.index 0 + // CHECK: %[[IDX_1:.+]] = linalg.index 1 + // CHECK: %[[IDX_2:.+]] = linalg.index 2 + // CHECK: %[[IDX_3:.+]] = linalg.index 3 + // CHECK-DAG: %[[XY_MIN:.+]] = arith.constant 0 + // CHECK-DAG: %[[Y_MAX:.+]] = arith.constant 14 + // CHECK-DAG: %[[X_MAX:.+]] = arith.constant 12 + + // CHECK: %[[Y:.+]] = arith.index_cast %[[IDX_1]] + // CHECK: %[[X:.+]] = arith.index_cast %[[IDX_2]] + // CHECK-DAG: %[[SCALE_Y_N:.*]] = arith.constant 11 + // CHECK-DAG: %[[SCALE_Y_D:.*]] = arith.constant 7 + // CHECK-DAG: %[[SCALE_X_N:.*]] = arith.constant 89 + // CHECK-DAG: %[[SCALE_X_D:.*]] = arith.constant 6 + // CHECK-DAG: %[[OFFSET_Y:.*]] = arith.constant 0 + // CHECK-DAG: %[[OFFSET_X:.*]] = arith.constant 0 + // CHECK-DAG: %[[BORDER_Y:.*]] = arith.constant 0 + // CHECK-DAG: %[[BORDER_X:.*]] = arith.constant 0 + + // find the remainder and integer component of the target index. + + // CHECK: %[[TEMP_Y:.*]] = arith.muli %[[Y]], %[[SCALE_Y_D]] + // CHECK: %[[TEMP_X:.*]] = arith.muli %[[X]], %[[SCALE_X_D]] + // CHECK: %[[Y:.*]] = arith.addi %[[TEMP_Y]], %[[OFFSET_Y]] + // CHECK: %[[X:.*]] = arith.addi %[[TEMP_X]], %[[OFFSET_X]] + // CHECK: %[[I_Y:.*]] = arith.divui %[[Y]], %[[SCALE_Y_N]] + // CHECK: %[[I_X:.*]] = arith.divui %[[X]], %[[SCALE_X_N]] + // CHECK: %[[TEMP_Y:.*]] = arith.muli %[[I_Y]], %[[SCALE_Y_N]] + // CHECK: %[[TEMP_X:.*]] = arith.muli %[[I_X]], %[[SCALE_X_N]] + // CHECK: %[[D_Y:.*]] = arith.subi %[[Y]], %[[TEMP_Y]] + // CHECK: %[[D_X:.*]] = arith.subi %[[X]], %[[TEMP_X]] + + // Round to the nearest neighor. + + // CHECK-DAG: %[[ZERO:.*]] = arith.constant 0 + // CHECK-DAG: %[[ONE:.*]] = arith.constant 1 + // CHECK: %[[SCALE_Y_N_HALF:.*]] = arith.shrsi %[[SCALE_Y_N]], %[[ONE]] + // CHECK: %[[SCALE_X_N_HALF:.*]] = arith.shrsi %[[SCALE_X_N]], %[[ONE]] + // CHECK: %[[PRED_Y:.*]] = arith.cmpi sge, %[[D_Y]], %[[SCALE_Y_N_HALF]] + // CHECK: %[[PRED_X:.*]] = arith.cmpi sge, %[[D_X]], %[[SCALE_X_N_HALF]] + // CHECK: %[[VAL_37:.*]] = arith.select %[[PRED_Y]], %[[ONE]], %[[ZERO]] + // CHECK: %[[VAL_38:.*]] = arith.select %[[PRED_X]], %[[ONE]], %[[ZERO]] + // CHECK: %[[VAL_39:.*]] = arith.addi %[[I_Y]], %[[VAL_37]] + // CHECK: %[[VAL_40:.*]] = arith.addi %[[I_X]], %[[VAL_38]] + + // This section applies bound checking to be within the input image. + + // CHECK: %[[VAL_41:.*]] = arith.cmpi slt, %[[VAL_39]], %[[XY_MIN]] + // CHECK: %[[VAL_42:.*]] = arith.select %[[VAL_41]], %[[XY_MIN]], %[[VAL_39]] + // CHECK: %[[VAL_43:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[VAL_39]] + // CHECK: %[[VAL_44:.*]] = arith.select %[[VAL_43]], %[[Y_MAX]], %[[VAL_42]] + // CHECK: %[[VAL_45:.*]] = arith.cmpi slt, %[[VAL_40]], %[[XY_MIN]] + // CHECK: %[[VAL_46:.*]] = arith.select %[[VAL_45]], %[[XY_MIN]], %[[VAL_40]] + // CHECK: %[[VAL_47:.*]] = arith.cmpi slt, %[[X_MAX]], %[[VAL_40]] + // CHECK: %[[VAL_48:.*]] = arith.select %[[VAL_47]], %[[X_MAX]], %[[VAL_46]] + + // Extract the nearest value using the computed indices. + + // CHECK: %[[IDY:.+]] = arith.index_cast %[[VAL_44]] + // CHECK: %[[IDX:.+]] = arith.index_cast %[[VAL_48]] + // CHECK: %[[EXTRACT:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[IDY]], %[[IDX]], %[[IDX_3]]] + // CHECK: linalg.yield %[[EXTRACT]] + + // Round to the nearest index. + %0 = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = [11, 7, 89, 6], offset = [0, 0], border = [0, 0]} : (tensor<1x15x13x1xi8>) -> tensor<1x23x179x1xi8> + return +} + +// ----- + +// CHECK-LABEL: @resize_bilinear_int +// CHECK-SAME: (%[[ARG0:[0-9a-zA-Z_]*]]: +func.func @resize_bilinear_int(%arg0: tensor<1x19x19x1xi8>) { + // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x289x289x1xi32> + // CHECK: %[[GENERIC:.+]] = linalg.generic + // CHECK: %[[IDX_0:.+]] = linalg.index 0 + // CHECK: %[[IDX_1:.+]] = linalg.index 1 + // CHECK: %[[IDX_2:.+]] = linalg.index 2 + // CHECK: %[[IDX_3:.+]] = linalg.index 3 + // CHECK-DAG: %[[XY_MIN:.+]] = arith.constant 0 + // CHECK-DAG: %[[Y_MAX:.+]] = arith.constant 18 + // CHECK-DAG: %[[X_MAX:.+]] = arith.constant 18 + // CHECK: %[[Y:.+]] = arith.index_cast %[[IDX_1]] + // CHECK: %[[X:.+]] = arith.index_cast %[[IDX_2]] + // CHECK-DAG: %[[SCALE_Y_N:.*]] = arith.constant 16 + // CHECK-DAG: %[[SCALE_Y_D:.*]] = arith.constant 1 + // CHECK-DAG: %[[SCALE_X_N:.*]] = arith.constant 16 + // CHECK-DAG: %[[SCALE_X_D:.*]] = arith.constant 1 + // CHECK-DAG: %[[OFFSET_Y:.*]] = arith.constant 0 + // CHECK-DAG: %[[OFFSET_X:.*]] = arith.constant 0 + // CHECK-DAG: %[[BORDER_Y:.*]] = arith.constant 0 + // CHECK-DAG: %[[BORDER_X:.*]] = arith.constant 0 + + // CHECK: %[[TEMP_Y:.*]] = arith.muli %[[Y]], %[[SCALE_Y_D]] + // CHECK: %[[TEMP_X:.*]] = arith.muli %[[X]], %[[SCALE_X_D]] + // CHECK: %[[Y:.*]] = arith.addi %[[TEMP_Y]], %[[OFFSET_Y]] + // CHECK: %[[X:.*]] = arith.addi %[[TEMP_X]], %[[OFFSET_X]] + // CHECK: %[[I_Y:.*]] = arith.divui %[[Y]], %[[SCALE_Y_N]] + // CHECK: %[[I_X:.*]] = arith.divui %[[X]], %[[SCALE_X_N]] + // CHECK: %[[TEMP_Y:.*]] = arith.muli %[[I_Y]], %[[SCALE_Y_N]] + // CHECK: %[[TEMP_X:.*]] = arith.muli %[[I_X]], %[[SCALE_X_N]] + // CHECK: %[[D_Y:.*]] = arith.subi %[[Y]], %[[TEMP_Y]] + // CHECK: %[[D_X:.*]] = arith.subi %[[X]], %[[TEMP_X]] + + // Compute the left, right, and top indices for the bilinear interpolation. + + // CHECK-DAG: %[[ONE:.*]] = arith.constant 1 + // CHECK: %[[Y1:.*]] = arith.addi %[[I_Y]], %[[ONE]] + // CHECK: %[[X1:.*]] = arith.addi %[[I_X]], %[[ONE]] + + // Bound check each dimension. + + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[I_Y]], %[[XY_MIN]] + // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[I_Y]] + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[I_Y]] + // CHECK: %[[YLO:.*]] = arith.select %[[PRED]], %[[Y_MAX]], %[[BOUND]] + + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y1]], %[[XY_MIN]] + // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[Y1]] + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[Y1]] + // CHECK: %[[YHI:.*]] = arith.select %[[PRED]], %[[Y_MAX]], %[[BOUND]] + + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[I_X]], %[[XY_MIN]] + // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[I_X]] + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X_MAX]], %[[I_X]] + // CHECK: %[[XLO:.*]] = arith.select %[[PRED]], %[[X_MAX]], %[[BOUND]] + + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X1]], %[[XY_MIN]] + // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[X1]] + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X_MAX]], %[[X1]] + // CHECK: %[[XHI:.*]] = arith.select %[[PRED]], %[[X_MAX]], %[[BOUND]] + + // Extract each corner of the bilinear interpolation. + + // CHECK: %[[YLOI:.+]] = arith.index_cast %[[YLO]] + // CHECK: %[[YHII:.+]] = arith.index_cast %[[YHI]] + // CHECK: %[[XLOI:.+]] = arith.index_cast %[[XLO]] + // CHECK: %[[XHII:.+]] = arith.index_cast %[[XHI]] + + // CHECK: %[[LOLO:.+]] = tensor.extract %[[ARG0]][%[[IDX_0]], %[[YLOI]], %[[XLOI]], %[[IDX_3]]] + // CHECK: %[[LOHI:.+]] = tensor.extract %[[ARG0]][%[[IDX_0]], %[[YLOI]], %[[XHII]], %[[IDX_3]]] + // CHECK: %[[HILO:.+]] = tensor.extract %[[ARG0]][%[[IDX_0]], %[[YHII]], %[[XLOI]], %[[IDX_3]]] + // CHECK: %[[HIHI:.+]] = tensor.extract %[[ARG0]][%[[IDX_0]], %[[YHII]], %[[XHII]], %[[IDX_3]]] + + // CHECK: %[[XLOLO:.+]] = arith.extsi %[[LOLO]] + // CHECK: %[[XLOHI:.+]] = arith.extsi %[[LOHI]] + // CHECK: %[[XHILO:.+]] = arith.extsi %[[HILO]] + // CHECK: %[[XHIHI:.+]] = arith.extsi %[[HIHI]] + + // Compute the bilinear interpolation. + + // CHECK: %[[NDX:.+]] = arith.subi %[[SCALE_X_N]], %[[D_X]] + // CHECK: %[[WLOLO:.+]] = arith.muli %[[XLOLO]], %[[NDX]] + // CHECK: %[[WLOHI:.+]] = arith.muli %[[XLOHI]], %[[D_X]] + // CHECK: %[[LO:.+]] = arith.addi %[[WLOLO]], %[[WLOHI]] + // CHECK: %[[WHILO:.+]] = arith.muli %[[XHILO]], %[[NDX]] + // CHECK: %[[WHIHI:.+]] = arith.muli %[[XHIHI]], %[[D_X]] + // CHECK: %[[HI:.+]] = arith.addi %[[WHILO]], %[[WHIHI]] + // CHECK: %[[NDY:.+]] = arith.subi %[[SCALE_Y_N]], %[[D_Y]] + // CHECK: %[[WLO:.+]] = arith.muli %[[LO]], %[[NDY]] + // CHECK: %[[WHI:.+]] = arith.muli %[[HI]], %[[D_Y]] + // CHECK: %[[RESULT:.+]] = arith.addi %[[WLO]], %[[WHI]] + // CHECK: linalg.yield %[[RESULT]] + + // Round to the nearest index. + %0 = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = [16, 1, 16, 1], offset = [0, 0], border = [0, 0]} : (tensor<1x19x19x1xi8>) -> tensor<1x289x289x1xi32> + return +} + +// ----- + +// CHECK-LABEL: @resize_nearest_fp +func.func @resize_nearest_fp(%input: tensor<1x50x48x1xf32>) -> () { + // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x1600x1536x1xf32> + // CHECK: %[[GENERIC:.+]] = linalg.generic + // CHECK: %[[IDX0:.+]] = linalg.index 0 + // CHECK: %[[IDX1:.+]] = linalg.index 1 + // CHECK: %[[IDX2:.+]] = linalg.index 2 + // CHECK: %[[IDX3:.+]] = linalg.index 3 + // CHECK-DAG: %[[XYMIN:.*]] = arith.constant 0 + // CHECK-DAG: %[[YMAX:.*]] = arith.constant 49 + // CHECK-DAG: %[[XMAX:.*]] = arith.constant 47 + // CHECK: %[[Y:.+]] = arith.index_cast %[[IDX1]] + // CHECK: %[[X:.+]] = arith.index_cast %[[IDX2]] + // CHECK-DAG: %[[ISCALE_Y_N:.*]] = arith.constant 64 + // CHECK-DAG: %[[ISCALE_Y_D:.*]] = arith.constant 2 + // CHECK-DAG: %[[ISCALE_X_N:.*]] = arith.constant 64 + // CHECK-DAG: %[[ISCALE_X_D:.*]] = arith.constant 2 + // CHECK-DAG: %[[IOFFSET_Y:.*]] = arith.constant -31 + // CHECK-DAG: %[[IOFFSET_X:.*]] = arith.constant -31 + // CHECK-DAG: %[[IBORDER_Y:.*]] = arith.constant 31 + // CHECK-DAG: %[[IBORDER_X:.*]] = arith.constant 31 + + // CHECK: %[[Y0:.+]] = arith.uitofp %[[Y]] + // CHECK: %[[X0:.+]] = arith.uitofp %[[X]] + // CHECK: %[[SCALE_Y_N:.*]] = arith.uitofp %[[ISCALE_Y_N]] + // CHECK: %[[SCALE_Y_D:.*]] = arith.uitofp %[[ISCALE_Y_D]] + // CHECK: %[[SCALE_X_N:.*]] = arith.uitofp %[[ISCALE_X_N]] + // CHECK: %[[SCALE_X_D:.*]] = arith.uitofp %[[ISCALE_X_D]] + // CHECK: %[[OFFSET_Y:.*]] = arith.uitofp %[[IOFFSET_Y]] + // CHECK: %[[OFFSET_X:.*]] = arith.uitofp %[[IOFFSET_X]] + + // CHECK: %[[VAL_29:.*]] = arith.mulf %[[Y0]], %[[SCALE_Y_D]] + // CHECK: %[[VAL_30:.*]] = arith.mulf %[[X0]], %[[SCALE_X_D]] + // CHECK: %[[VAL_31:.*]] = arith.addf %[[VAL_29]], %[[OFFSET_Y]] + // CHECK: %[[VAL_32:.*]] = arith.addf %[[VAL_30]], %[[OFFSET_X]] + // CHECK: %[[VAL_33:.*]] = arith.divf %[[VAL_31]], %[[SCALE_Y_N]] + // CHECK: %[[VAL_34:.*]] = arith.divf %[[VAL_32]], %[[SCALE_X_N]] + + // Find the remainder and integer component of the target index. + + // CHECK: %[[VAL_35:.*]] = math.floor %[[VAL_33]] + // CHECK: %[[VAL_36:.*]] = math.floor %[[VAL_34]] + // CHECK: %[[D_Y:.*]] = arith.subf %[[VAL_33]], %[[VAL_35]] + // CHECK: %[[D_X:.*]] = arith.subf %[[VAL_34]], %[[VAL_36]] + // CHECK: %[[VAL_39:.*]] = arith.fptosi %[[VAL_35]] + // CHECK: %[[VAL_40:.*]] = arith.fptosi %[[VAL_36]] + + // CHECK-DAG: %[[ZERO:.*]] = arith.constant 0 + // CHECK-DAG: %[[ONE:.*]] = arith.constant 1 + // CHECK-DAG: %[[HALF:.*]] = arith.constant 5.000000e-01 + // CHECK: %[[PRED_Y:.*]] = arith.cmpf oge, %[[D_Y]], %[[HALF]] + // CHECK: %[[PRED_X:.*]] = arith.cmpf oge, %[[D_X]], %[[HALF]] + // CHECK: %[[ROUND_Y:.*]] = arith.select %[[PRED_Y]], %[[ONE]], %[[ZERO]] + // CHECK: %[[ROUND_X:.*]] = arith.select %[[PRED_X]], %[[ONE]], %[[ZERO]] + // CHECK: %[[VAL_48:.*]] = arith.addi %[[VAL_39]], %[[ROUND_Y]] + // CHECK: %[[VAL_49:.*]] = arith.addi %[[VAL_40]], %[[ROUND_X]] + + // CHECK: %[[VAL_50:.*]] = arith.cmpi slt, %[[VAL_48]], %[[XYMIN]] + // CHECK: %[[VAL_51:.*]] = arith.select %[[VAL_50]], %[[XYMIN]], %[[VAL_48]] + // CHECK: %[[VAL_52:.*]] = arith.cmpi slt, %[[YMAX]], %[[VAL_48]] + // CHECK: %[[VAL_53:.*]] = arith.select %[[VAL_52]], %[[YMAX]], %[[VAL_51]] + // CHECK: %[[VAL_54:.*]] = arith.cmpi slt, %[[VAL_49]], %[[XYMIN]] + // CHECK: %[[VAL_55:.*]] = arith.select %[[VAL_54]], %[[XYMIN]], %[[VAL_49]] + // CHECK: %[[VAL_56:.*]] = arith.cmpi slt, %[[XMAX]], %[[VAL_49]] + // CHECK: %[[VAL_57:.*]] = arith.select %[[VAL_56]], %[[XMAX]], %[[VAL_55]] + + // CHECK: %[[IDY:.*]] = arith.index_cast %[[VAL_53]] + // CHECK: %[[IDX:.*]] = arith.index_cast %[[VAL_57]] + // CHECK: %[[EXTRACT:.+]] = tensor.extract %arg0[%[[IDX0]], %[[IDY]], %[[IDX]], %[[IDX3]]] + // CHECK: linalg.yield %[[EXTRACT]] + + %output = "tosa.resize"(%input) {mode = "NEAREST_NEIGHBOR", scale = [64, 2, 64, 2], offset = [-31, -31], border = [31, 31]} : (tensor<1x50x48x1xf32>) -> tensor<1x1600x1536x1xf32> + + return +} + +// ----- + +// CHECK-LABEL: @resize_bilinear_fp +func.func @resize_bilinear_fp(%input: tensor<1x23x23x1xf32>) -> () { + // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x89x89x1xf32> + // CHECK: %[[GENERIC:.+]] = linalg.generic + // CHECK: %[[IDX_0:.+]] = linalg.index 0 + // CHECK: %[[IDX_1:.+]] = linalg.index 1 + // CHECK: %[[IDX_2:.+]] = linalg.index 2 + // CHECK: %[[IDX_3:.+]] = linalg.index 3 + // CHECK-DAG: %[[XY_MIN:.*]] = arith.constant 0 + // CHECK-DAG: %[[Y_MAX:.*]] = arith.constant 22 + // CHECK-DAG: %[[X_MAX:.*]] = arith.constant 22 + // CHECK: %[[Y:.+]] = arith.index_cast %[[IDX_1]] + // CHECK: %[[X:.+]] = arith.index_cast %[[IDX_2]] + // CHECK-DAG: %[[ISCALE_Y_N:.*]] = arith.constant 4 + // CHECK-DAG: %[[ISCALE_Y_D:.*]] = arith.constant 1 + // CHECK-DAG: %[[ISCALE_X_N:.*]] = arith.constant 4 + // CHECK-DAG: %[[ISCALE_X_D:.*]] = arith.constant 1 + // CHECK-DAG: %[[IOFFSET_Y:.*]] = arith.constant 0 + // CHECK-DAG: %[[IOFFSET_X:.*]] = arith.constant 0 + // CHECK-DAG: %[[IBORDER_Y:.*]] = arith.constant 0 + // CHECK-DAG: %[[IBORDER_X:.*]] = arith.constant 0 + + // CHECK: %[[Y0:.+]] = arith.uitofp %[[Y]] + // CHECK: %[[X0:.+]] = arith.uitofp %[[X]] + // CHECK: %[[SCALE_Y_N:.*]] = arith.uitofp %[[ISCALE_Y_N]] + // CHECK: %[[SCALE_Y_D:.*]] = arith.uitofp %[[ISCALE_Y_D]] + // CHECK: %[[SCALE_X_N:.*]] = arith.uitofp %[[ISCALE_X_N]] + // CHECK: %[[SCALE_X_D:.*]] = arith.uitofp %[[ISCALE_X_D]] + // CHECK: %[[OFFSET_Y:.*]] = arith.uitofp %[[IOFFSET_Y]] + // CHECK: %[[OFFSET_X:.*]] = arith.uitofp %[[IOFFSET_X]] + + // CHECK: %[[VAL_29:.*]] = arith.mulf %[[Y0]], %[[SCALE_Y_D]] + // CHECK: %[[VAL_30:.*]] = arith.mulf %[[X0]], %[[SCALE_X_D]] + // CHECK: %[[VAL_31:.*]] = arith.addf %[[VAL_29]], %[[OFFSET_Y]] + // CHECK: %[[VAL_32:.*]] = arith.addf %[[VAL_30]], %[[OFFSET_X]] + // CHECK: %[[VAL_33:.*]] = arith.divf %[[VAL_31]], %[[SCALE_Y_N]] + // CHECK: %[[VAL_34:.*]] = arith.divf %[[VAL_32]], %[[SCALE_X_N]] + + // CHECK: %[[VAL_35:.*]] = math.floor %[[VAL_33]] + // CHECK: %[[VAL_36:.*]] = math.floor %[[VAL_34]] + // CHECK: %[[D_Y:.*]] = arith.subf %[[VAL_33]], %[[VAL_35]] + // CHECK: %[[D_X:.*]] = arith.subf %[[VAL_34]], %[[VAL_36]] + // CHECK: %[[I_Y:.*]] = arith.fptosi %[[VAL_35]] + // CHECK: %[[I_X:.*]] = arith.fptosi %[[VAL_36]] + + // Compute the left, right, and top indices for the bilinear interpolation. + + // CHECK-DAG: %[[ONE:.*]] = arith.constant 1 + // CHECK: %[[Y1:.*]] = arith.addi %[[I_Y]], %[[ONE]] + // CHECK: %[[X1:.*]] = arith.addi %[[I_X]], %[[ONE]] + + // Bound check each dimension. + + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[I_Y]], %[[XY_MIN]] + // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[I_Y]] + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[I_Y]] + // CHECK: %[[YLO:.*]] = arith.select %[[PRED]], %[[Y_MAX]], %[[BOUND]] + + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y1]], %[[XY_MIN]] + // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[Y1]] + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[Y1]] + // CHECK: %[[YHI:.*]] = arith.select %[[PRED]], %[[Y_MAX]], %[[BOUND]] + + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[I_X]], %[[XY_MIN]] + // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[I_X]] + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X_MAX]], %[[I_X]] + // CHECK: %[[XLO:.*]] = arith.select %[[PRED]], %[[X_MAX]], %[[BOUND]] + + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X1]], %[[XY_MIN]] + // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[X1]] + // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X_MAX]], %[[X1]] + // CHECK: %[[XHI:.*]] = arith.select %[[PRED]], %[[X_MAX]], %[[BOUND]] + + // CHECK: %[[YLOI:.+]] = arith.index_cast %[[YLO]] + // CHECK: %[[YHII:.+]] = arith.index_cast %[[YHI]] + // CHECK: %[[XLOI:.+]] = arith.index_cast %[[XLO]] + // CHECK: %[[XHII:.+]] = arith.index_cast %[[XHI]] + + // CHECK: %[[LOLO:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[YLOI]], %[[XLOI]], %[[IDX_3]]] + // CHECK: %[[LOHI:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[YLOI]], %[[XHII]], %[[IDX_3]]] + // CHECK: %[[HILO:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[YHII]], %[[XLOI]], %[[IDX_3]]] + // CHECK: %[[HIHI:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[YHII]], %[[XHII]], %[[IDX_3]]] + + // CHECK-DAG: %[[ONE:.+]] = arith.constant 1.000000e+00 : f32 + // CHECK: %[[NDX:.+]] = arith.subf %[[ONE]], %[[D_X]] + // CHECK: %[[WLOLO:.+]] = arith.mulf %[[LOLO]], %[[NDX]] + // CHECK: %[[WLOHI:.+]] = arith.mulf %[[LOHI]], %[[D_X]] + // CHECK: %[[LO:.+]] = arith.addf %[[WLOLO]], %[[WLOHI]] + // CHECK: %[[WHILO:.+]] = arith.mulf %[[HILO]], %[[NDX]] + // CHECK: %[[WHIHI:.+]] = arith.mulf %[[HIHI]], %[[D_X]] + // CHECK: %[[HI:.+]] = arith.addf %[[WHILO]], %[[WHIHI]] + // CHECK: %[[NDY:.+]] = arith.subf %[[ONE]], %[[D_Y]] + // CHECK: %[[WLO:.+]] = arith.mulf %[[LO]], %[[NDY]] + // CHECK: %[[WHI:.+]] = arith.mulf %[[HI]], %[[D_Y]] + // CHECK: %[[RESULT:.+]] = arith.addf %[[WLO]], %[[WHI]] + // CHECK: linalg.yield %[[RESULT]] + + // Round by bilinear interpolation + %output = "tosa.resize"(%input) {mode = "BILINEAR", scale = [4, 1, 4, 1], offset = [0, 0], border = [0, 0]} : (tensor<1x23x23x1xf32>) -> tensor<1x89x89x1xf32> + + return +} + +// ----- + +// CHECK-LABEL: @resize_dyn +// CHECK-SAME: (%[[ARG0:[0-9a-zA-Z_]*]]: +func.func @resize_dyn(%input: tensor) -> () { + // CHECK-DAG: %[[C0:.+]] = arith.constant 0 + // CHECK: %[[BATCH:.+]] = tensor.dim %arg0, %[[C0]] + // CHECK: %[[INIT:.+]] = tensor.empty(%[[BATCH]]) : tensor + // CHECK: %[[GENERIC:.+]] = linalg.generic + %output = "tosa.resize"(%input) { scale = [4, 2, 4, 2], offset = [-1, -1], border = [1, 1], mode = "BILINEAR" } : (tensor) -> (tensor) + return +} diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir --- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir +++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg.mlir @@ -1643,376 +1643,6 @@ // ----- -// CHECK-LABEL: @resize_nearest_int -func.func @resize_nearest_int(%arg0: tensor<1x15x13x1xi8>) -> () { - // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x23x179x1xi8> - // CHECK: %[[GENERIC:.+]] = linalg.generic - // CHECK: %[[IDX_0:.+]] = linalg.index 0 - // CHECK: %[[IDX_1:.+]] = linalg.index 1 - // CHECK: %[[IDX_2:.+]] = linalg.index 2 - // CHECK: %[[IDX_3:.+]] = linalg.index 3 - // CHECK: %[[XY_MIN:.+]] = arith.constant 0 - // CHECK: %[[Y_MAX:.+]] = arith.constant 14 - // CHECK: %[[X_MAX:.+]] = arith.constant 12 - - // CHECK: %[[Y:.+]] = arith.index_cast %[[IDX_1]] - // CHECK: %[[X:.+]] = arith.index_cast %[[IDX_2]] - // CHECK: %[[SCALE_Y_N:.*]] = arith.constant 11 - // CHECK: %[[SCALE_Y_D:.*]] = arith.constant 7 - // CHECK: %[[SCALE_X_N:.*]] = arith.constant 89 - // CHECK: %[[SCALE_X_D:.*]] = arith.constant 6 - // CHECK: %[[OFFSET_Y:.*]] = arith.constant 0 - // CHECK: %[[OFFSET_X:.*]] = arith.constant 0 - // CHECK: %[[BORDER_Y:.*]] = arith.constant 0 - // CHECK: %[[BORDER_X:.*]] = arith.constant 0 - - // find the remainder and integer component of the target index. - - // CHECK: %[[TEMP_Y:.*]] = arith.muli %[[Y]], %[[SCALE_Y_D]] - // CHECK: %[[TEMP_X:.*]] = arith.muli %[[X]], %[[SCALE_X_D]] - // CHECK: %[[Y:.*]] = arith.addi %[[TEMP_Y]], %[[OFFSET_Y]] - // CHECK: %[[X:.*]] = arith.addi %[[TEMP_X]], %[[OFFSET_X]] - // CHECK: %[[I_Y:.*]] = arith.divui %[[Y]], %[[SCALE_Y_N]] - // CHECK: %[[I_X:.*]] = arith.divui %[[X]], %[[SCALE_X_N]] - // CHECK: %[[TEMP_Y:.*]] = arith.muli %[[I_Y]], %[[SCALE_Y_N]] - // CHECK: %[[TEMP_X:.*]] = arith.muli %[[I_X]], %[[SCALE_X_N]] - // CHECK: %[[D_Y:.*]] = arith.subi %[[Y]], %[[TEMP_Y]] - // CHECK: %[[D_X:.*]] = arith.subi %[[X]], %[[TEMP_X]] - - // Round to the nearest neighor. - - // CHECK: %[[ZERO:.*]] = arith.constant 0 - // CHECK: %[[ONE:.*]] = arith.constant 1 - // CHECK: %[[SCALE_Y_N_HALF:.*]] = arith.shrsi %[[SCALE_Y_N]], %[[ONE]] - // CHECK: %[[SCALE_X_N_HALF:.*]] = arith.shrsi %[[SCALE_X_N]], %[[ONE]] - // CHECK: %[[PRED_Y:.*]] = arith.cmpi sge, %[[D_Y]], %[[SCALE_Y_N_HALF]] - // CHECK: %[[PRED_X:.*]] = arith.cmpi sge, %[[D_X]], %[[SCALE_X_N_HALF]] - // CHECK: %[[VAL_37:.*]] = arith.select %[[PRED_Y]], %[[ONE]], %[[ZERO]] - // CHECK: %[[VAL_38:.*]] = arith.select %[[PRED_X]], %[[ONE]], %[[ZERO]] - // CHECK: %[[VAL_39:.*]] = arith.addi %[[I_Y]], %[[VAL_37]] - // CHECK: %[[VAL_40:.*]] = arith.addi %[[I_X]], %[[VAL_38]] - - // This section applies bound checking to be within the input image. - - // CHECK: %[[VAL_41:.*]] = arith.cmpi slt, %[[VAL_39]], %[[XY_MIN]] - // CHECK: %[[VAL_42:.*]] = arith.select %[[VAL_41]], %[[XY_MIN]], %[[VAL_39]] - // CHECK: %[[VAL_43:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[VAL_39]] - // CHECK: %[[VAL_44:.*]] = arith.select %[[VAL_43]], %[[Y_MAX]], %[[VAL_42]] - // CHECK: %[[VAL_45:.*]] = arith.cmpi slt, %[[VAL_40]], %[[XY_MIN]] - // CHECK: %[[VAL_46:.*]] = arith.select %[[VAL_45]], %[[XY_MIN]], %[[VAL_40]] - // CHECK: %[[VAL_47:.*]] = arith.cmpi slt, %[[X_MAX]], %[[VAL_40]] - // CHECK: %[[VAL_48:.*]] = arith.select %[[VAL_47]], %[[X_MAX]], %[[VAL_46]] - - // Extract the nearest value using the computed indices. - - // CHECK: %[[IDY:.+]] = arith.index_cast %[[VAL_44]] - // CHECK: %[[IDX:.+]] = arith.index_cast %[[VAL_48]] - // CHECK: %[[EXTRACT:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[IDY]], %[[IDX]], %[[IDX_3]]] - // CHECK: linalg.yield %[[EXTRACT]] - - // Round to the nearest index. - %0 = "tosa.resize"(%arg0) {mode = "NEAREST_NEIGHBOR", scale = [11, 7, 89, 6], offset = [0, 0], border = [0, 0]} : (tensor<1x15x13x1xi8>) -> tensor<1x23x179x1xi8> - return -} - -// ----- - -// CHECK-LABEL: @resize_bilinear_int -// CHECK-SAME: (%[[ARG0:[0-9a-zA-Z_]*]]: -func.func @resize_bilinear_int(%arg0: tensor<1x19x19x1xi8>) { - // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x289x289x1xi32> - // CHECK: %[[GENERIC:.+]] = linalg.generic - // CHECK: %[[IDX_0:.+]] = linalg.index 0 - // CHECK: %[[IDX_1:.+]] = linalg.index 1 - // CHECK: %[[IDX_2:.+]] = linalg.index 2 - // CHECK: %[[IDX_3:.+]] = linalg.index 3 - // CHECK: %[[XY_MIN:.+]] = arith.constant 0 - // CHECK: %[[Y_MAX:.+]] = arith.constant 18 - // CHECK: %[[X_MAX:.+]] = arith.constant 18 - // CHECK: %[[Y:.+]] = arith.index_cast %[[IDX_1]] - // CHECK: %[[X:.+]] = arith.index_cast %[[IDX_2]] - // CHECK: %[[SCALE_Y_N:.*]] = arith.constant 16 - // CHECK: %[[SCALE_Y_D:.*]] = arith.constant 1 - // CHECK: %[[SCALE_X_N:.*]] = arith.constant 16 - // CHECK: %[[SCALE_X_D:.*]] = arith.constant 1 - // CHECK: %[[OFFSET_Y:.*]] = arith.constant 0 - // CHECK: %[[OFFSET_X:.*]] = arith.constant 0 - // CHECK: %[[BORDER_Y:.*]] = arith.constant 0 - // CHECK: %[[BORDER_X:.*]] = arith.constant 0 - - // CHECK: %[[TEMP_Y:.*]] = arith.muli %[[Y]], %[[SCALE_Y_D]] - // CHECK: %[[TEMP_X:.*]] = arith.muli %[[X]], %[[SCALE_X_D]] - // CHECK: %[[Y:.*]] = arith.addi %[[TEMP_Y]], %[[OFFSET_Y]] - // CHECK: %[[X:.*]] = arith.addi %[[TEMP_X]], %[[OFFSET_X]] - // CHECK: %[[I_Y:.*]] = arith.divui %[[Y]], %[[SCALE_Y_N]] - // CHECK: %[[I_X:.*]] = arith.divui %[[X]], %[[SCALE_X_N]] - // CHECK: %[[TEMP_Y:.*]] = arith.muli %[[I_Y]], %[[SCALE_Y_N]] - // CHECK: %[[TEMP_X:.*]] = arith.muli %[[I_X]], %[[SCALE_X_N]] - // CHECK: %[[D_Y:.*]] = arith.subi %[[Y]], %[[TEMP_Y]] - // CHECK: %[[D_X:.*]] = arith.subi %[[X]], %[[TEMP_X]] - - // Compute the left, right, and top indices for the bilinear interpolation. - - // CHECK: %[[ONE:.*]] = arith.constant 1 - // CHECK: %[[Y1:.*]] = arith.addi %[[I_Y]], %[[ONE]] - // CHECK: %[[X1:.*]] = arith.addi %[[I_X]], %[[ONE]] - - // Bound check each dimension. - - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[I_Y]], %[[XY_MIN]] - // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[I_Y]] - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[I_Y]] - // CHECK: %[[YLO:.*]] = arith.select %[[PRED]], %[[Y_MAX]], %[[BOUND]] - - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y1]], %[[XY_MIN]] - // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[Y1]] - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[Y1]] - // CHECK: %[[YHI:.*]] = arith.select %[[PRED]], %[[Y_MAX]], %[[BOUND]] - - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[I_X]], %[[XY_MIN]] - // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[I_X]] - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X_MAX]], %[[I_X]] - // CHECK: %[[XLO:.*]] = arith.select %[[PRED]], %[[X_MAX]], %[[BOUND]] - - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X1]], %[[XY_MIN]] - // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[X1]] - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X_MAX]], %[[X1]] - // CHECK: %[[XHI:.*]] = arith.select %[[PRED]], %[[X_MAX]], %[[BOUND]] - - // Extract each corner of the bilinear interpolation. - - // CHECK: %[[YLOI:.+]] = arith.index_cast %[[YLO]] - // CHECK: %[[YHII:.+]] = arith.index_cast %[[YHI]] - // CHECK: %[[XLOI:.+]] = arith.index_cast %[[XLO]] - // CHECK: %[[XHII:.+]] = arith.index_cast %[[XHI]] - - // CHECK: %[[LOLO:.+]] = tensor.extract %[[ARG0]][%[[IDX_0]], %[[YLOI]], %[[XLOI]], %[[IDX_3]]] - // CHECK: %[[LOHI:.+]] = tensor.extract %[[ARG0]][%[[IDX_0]], %[[YLOI]], %[[XHII]], %[[IDX_3]]] - // CHECK: %[[HILO:.+]] = tensor.extract %[[ARG0]][%[[IDX_0]], %[[YHII]], %[[XLOI]], %[[IDX_3]]] - // CHECK: %[[HIHI:.+]] = tensor.extract %[[ARG0]][%[[IDX_0]], %[[YHII]], %[[XHII]], %[[IDX_3]]] - - // CHECK: %[[XLOLO:.+]] = arith.extsi %[[LOLO]] - // CHECK: %[[XLOHI:.+]] = arith.extsi %[[LOHI]] - // CHECK: %[[XHILO:.+]] = arith.extsi %[[HILO]] - // CHECK: %[[XHIHI:.+]] = arith.extsi %[[HIHI]] - - // Compute the bilinear interpolation. - - // CHECK: %[[NDX:.+]] = arith.subi %[[SCALE_X_N]], %[[D_X]] - // CHECK: %[[WLOLO:.+]] = arith.muli %[[XLOLO]], %[[NDX]] - // CHECK: %[[WLOHI:.+]] = arith.muli %[[XLOHI]], %[[D_X]] - // CHECK: %[[LO:.+]] = arith.addi %[[WLOLO]], %[[WLOHI]] - // CHECK: %[[WHILO:.+]] = arith.muli %[[XHILO]], %[[NDX]] - // CHECK: %[[WHIHI:.+]] = arith.muli %[[XHIHI]], %[[D_X]] - // CHECK: %[[HI:.+]] = arith.addi %[[WHILO]], %[[WHIHI]] - // CHECK: %[[NDY:.+]] = arith.subi %[[SCALE_Y_N]], %[[D_Y]] - // CHECK: %[[WLO:.+]] = arith.muli %[[LO]], %[[NDY]] - // CHECK: %[[WHI:.+]] = arith.muli %[[HI]], %[[D_Y]] - // CHECK: %[[RESULT:.+]] = arith.addi %[[WLO]], %[[WHI]] - // CHECK: linalg.yield %[[RESULT]] - - // Round to the nearest index. - %0 = "tosa.resize"(%arg0) {mode = "BILINEAR", scale = [16, 1, 16, 1], offset = [0, 0], border = [0, 0]} : (tensor<1x19x19x1xi8>) -> tensor<1x289x289x1xi32> - return -} - -// ----- - -// CHECK-LABEL: @resize_nearest_fp -func.func @resize_nearest_fp(%input: tensor<1x50x48x1xf32>) -> () { - // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x1600x1536x1xf32> - // CHECK: %[[GENERIC:.+]] = linalg.generic - // CHECK: %[[IDX0:.+]] = linalg.index 0 - // CHECK: %[[IDX1:.+]] = linalg.index 1 - // CHECK: %[[IDX2:.+]] = linalg.index 2 - // CHECK: %[[IDX3:.+]] = linalg.index 3 - // CHECK: %[[XYMIN:.*]] = arith.constant 0 - // CHECK: %[[YMAX:.*]] = arith.constant 49 - // CHECK: %[[XMAX:.*]] = arith.constant 47 - // CHECK: %[[Y:.+]] = arith.index_cast %[[IDX1]] - // CHECK: %[[X:.+]] = arith.index_cast %[[IDX2]] - // CHECK: %[[ISCALE_Y_N:.*]] = arith.constant 64 - // CHECK: %[[ISCALE_Y_D:.*]] = arith.constant 2 - // CHECK: %[[ISCALE_X_N:.*]] = arith.constant 64 - // CHECK: %[[ISCALE_X_D:.*]] = arith.constant 2 - // CHECK: %[[IOFFSET_Y:.*]] = arith.constant -31 - // CHECK: %[[IOFFSET_X:.*]] = arith.constant -31 - // CHECK: %[[IBORDER_Y:.*]] = arith.constant 31 - // CHECK: %[[IBORDER_X:.*]] = arith.constant 31 - - // CHECK: %[[Y0:.+]] = arith.uitofp %[[Y]] - // CHECK: %[[X0:.+]] = arith.uitofp %[[X]] - // CHECK: %[[SCALE_Y_N:.*]] = arith.uitofp %[[ISCALE_Y_N]] - // CHECK: %[[SCALE_Y_D:.*]] = arith.uitofp %[[ISCALE_Y_D]] - // CHECK: %[[SCALE_X_N:.*]] = arith.uitofp %[[ISCALE_X_N]] - // CHECK: %[[SCALE_X_D:.*]] = arith.uitofp %[[ISCALE_X_D]] - // CHECK: %[[OFFSET_Y:.*]] = arith.uitofp %[[IOFFSET_Y]] - // CHECK: %[[OFFSET_X:.*]] = arith.uitofp %[[IOFFSET_X]] - - // CHECK: %[[VAL_29:.*]] = arith.mulf %[[Y0]], %[[SCALE_Y_D]] - // CHECK: %[[VAL_30:.*]] = arith.mulf %[[X0]], %[[SCALE_X_D]] - // CHECK: %[[VAL_31:.*]] = arith.addf %[[VAL_29]], %[[OFFSET_Y]] - // CHECK: %[[VAL_32:.*]] = arith.addf %[[VAL_30]], %[[OFFSET_X]] - // CHECK: %[[VAL_33:.*]] = arith.divf %[[VAL_31]], %[[SCALE_Y_N]] - // CHECK: %[[VAL_34:.*]] = arith.divf %[[VAL_32]], %[[SCALE_X_N]] - - // Find the remainder and integer component of the target index. - - // CHECK: %[[VAL_35:.*]] = math.floor %[[VAL_33]] - // CHECK: %[[VAL_36:.*]] = math.floor %[[VAL_34]] - // CHECK: %[[D_Y:.*]] = arith.subf %[[VAL_33]], %[[VAL_35]] - // CHECK: %[[D_X:.*]] = arith.subf %[[VAL_34]], %[[VAL_36]] - // CHECK: %[[VAL_39:.*]] = arith.fptosi %[[VAL_35]] - // CHECK: %[[VAL_40:.*]] = arith.fptosi %[[VAL_36]] - - // CHECK: %[[ZERO:.*]] = arith.constant 0 - // CHECK: %[[ONE:.*]] = arith.constant 1 - // CHECK: %[[HALF:.*]] = arith.constant 5.000000e-01 - // CHECK: %[[PRED_Y:.*]] = arith.cmpf oge, %[[D_Y]], %[[HALF]] - // CHECK: %[[PRED_X:.*]] = arith.cmpf oge, %[[D_X]], %[[HALF]] - // CHECK: %[[ROUND_Y:.*]] = arith.select %[[PRED_Y]], %[[ONE]], %[[ZERO]] - // CHECK: %[[ROUND_X:.*]] = arith.select %[[PRED_X]], %[[ONE]], %[[ZERO]] - // CHECK: %[[VAL_48:.*]] = arith.addi %[[VAL_39]], %[[ROUND_Y]] - // CHECK: %[[VAL_49:.*]] = arith.addi %[[VAL_40]], %[[ROUND_X]] - - // CHECK: %[[VAL_50:.*]] = arith.cmpi slt, %[[VAL_48]], %[[XYMIN]] - // CHECK: %[[VAL_51:.*]] = arith.select %[[VAL_50]], %[[XYMIN]], %[[VAL_48]] - // CHECK: %[[VAL_52:.*]] = arith.cmpi slt, %[[YMAX]], %[[VAL_48]] - // CHECK: %[[VAL_53:.*]] = arith.select %[[VAL_52]], %[[YMAX]], %[[VAL_51]] - // CHECK: %[[VAL_54:.*]] = arith.cmpi slt, %[[VAL_49]], %[[XYMIN]] - // CHECK: %[[VAL_55:.*]] = arith.select %[[VAL_54]], %[[XYMIN]], %[[VAL_49]] - // CHECK: %[[VAL_56:.*]] = arith.cmpi slt, %[[XMAX]], %[[VAL_49]] - // CHECK: %[[VAL_57:.*]] = arith.select %[[VAL_56]], %[[XMAX]], %[[VAL_55]] - - // CHECK: %[[IDY:.*]] = arith.index_cast %[[VAL_53]] - // CHECK: %[[IDX:.*]] = arith.index_cast %[[VAL_57]] - // CHECK: %[[EXTRACT:.+]] = tensor.extract %arg0[%[[IDX0]], %[[IDY]], %[[IDX]], %[[IDX3]]] - // CHECK: linalg.yield %[[EXTRACT]] - - %output = "tosa.resize"(%input) {mode = "NEAREST_NEIGHBOR", scale = [64, 2, 64, 2], offset = [-31, -31], border = [31, 31]} : (tensor<1x50x48x1xf32>) -> tensor<1x1600x1536x1xf32> - - return -} - -// ----- - -// CHECK-LABEL: @resize_bilinear_fp -func.func @resize_bilinear_fp(%input: tensor<1x23x23x1xf32>) -> () { - // CHECK: %[[INIT:.+]] = tensor.empty() : tensor<1x89x89x1xf32> - // CHECK: %[[GENERIC:.+]] = linalg.generic - // CHECK: %[[IDX_0:.+]] = linalg.index 0 - // CHECK: %[[IDX_1:.+]] = linalg.index 1 - // CHECK: %[[IDX_2:.+]] = linalg.index 2 - // CHECK: %[[IDX_3:.+]] = linalg.index 3 - // CHECK: %[[XY_MIN:.*]] = arith.constant 0 - // CHECK: %[[Y_MAX:.*]] = arith.constant 22 - // CHECK: %[[X_MAX:.*]] = arith.constant 22 - // CHECK: %[[Y:.+]] = arith.index_cast %[[IDX_1]] - // CHECK: %[[X:.+]] = arith.index_cast %[[IDX_2]] - // CHECK: %[[ISCALE_Y_N:.*]] = arith.constant 4 - // CHECK: %[[ISCALE_Y_D:.*]] = arith.constant 1 - // CHECK: %[[ISCALE_X_N:.*]] = arith.constant 4 - // CHECK: %[[ISCALE_X_D:.*]] = arith.constant 1 - // CHECK: %[[IOFFSET_Y:.*]] = arith.constant 0 - // CHECK: %[[IOFFSET_X:.*]] = arith.constant 0 - // CHECK: %[[IBORDER_Y:.*]] = arith.constant 0 - // CHECK: %[[IBORDER_X:.*]] = arith.constant 0 - - // CHECK: %[[Y0:.+]] = arith.uitofp %[[Y]] - // CHECK: %[[X0:.+]] = arith.uitofp %[[X]] - // CHECK: %[[SCALE_Y_N:.*]] = arith.uitofp %[[ISCALE_Y_N]] - // CHECK: %[[SCALE_Y_D:.*]] = arith.uitofp %[[ISCALE_Y_D]] - // CHECK: %[[SCALE_X_N:.*]] = arith.uitofp %[[ISCALE_X_N]] - // CHECK: %[[SCALE_X_D:.*]] = arith.uitofp %[[ISCALE_X_D]] - // CHECK: %[[OFFSET_Y:.*]] = arith.uitofp %[[IOFFSET_Y]] - // CHECK: %[[OFFSET_X:.*]] = arith.uitofp %[[IOFFSET_X]] - - // CHECK: %[[VAL_29:.*]] = arith.mulf %[[Y0]], %[[SCALE_Y_D]] - // CHECK: %[[VAL_30:.*]] = arith.mulf %[[X0]], %[[SCALE_X_D]] - // CHECK: %[[VAL_31:.*]] = arith.addf %[[VAL_29]], %[[OFFSET_Y]] - // CHECK: %[[VAL_32:.*]] = arith.addf %[[VAL_30]], %[[OFFSET_X]] - // CHECK: %[[VAL_33:.*]] = arith.divf %[[VAL_31]], %[[SCALE_Y_N]] - // CHECK: %[[VAL_34:.*]] = arith.divf %[[VAL_32]], %[[SCALE_X_N]] - - // CHECK: %[[VAL_35:.*]] = math.floor %[[VAL_33]] - // CHECK: %[[VAL_36:.*]] = math.floor %[[VAL_34]] - // CHECK: %[[D_Y:.*]] = arith.subf %[[VAL_33]], %[[VAL_35]] - // CHECK: %[[D_X:.*]] = arith.subf %[[VAL_34]], %[[VAL_36]] - // CHECK: %[[I_Y:.*]] = arith.fptosi %[[VAL_35]] - // CHECK: %[[I_X:.*]] = arith.fptosi %[[VAL_36]] - - // Compute the left, right, and top indices for the bilinear interpolation. - - // CHECK: %[[ONE:.*]] = arith.constant 1 - // CHECK: %[[Y1:.*]] = arith.addi %[[I_Y]], %[[ONE]] - // CHECK: %[[X1:.*]] = arith.addi %[[I_X]], %[[ONE]] - - // Bound check each dimension. - - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[I_Y]], %[[XY_MIN]] - // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[I_Y]] - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[I_Y]] - // CHECK: %[[YLO:.*]] = arith.select %[[PRED]], %[[Y_MAX]], %[[BOUND]] - - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y1]], %[[XY_MIN]] - // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[Y1]] - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[Y_MAX]], %[[Y1]] - // CHECK: %[[YHI:.*]] = arith.select %[[PRED]], %[[Y_MAX]], %[[BOUND]] - - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[I_X]], %[[XY_MIN]] - // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[I_X]] - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X_MAX]], %[[I_X]] - // CHECK: %[[XLO:.*]] = arith.select %[[PRED]], %[[X_MAX]], %[[BOUND]] - - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X1]], %[[XY_MIN]] - // CHECK: %[[BOUND:.*]] = arith.select %[[PRED]], %[[XY_MIN]], %[[X1]] - // CHECK: %[[PRED:.*]] = arith.cmpi slt, %[[X_MAX]], %[[X1]] - // CHECK: %[[XHI:.*]] = arith.select %[[PRED]], %[[X_MAX]], %[[BOUND]] - - // CHECK: %[[YLOI:.+]] = arith.index_cast %[[YLO]] - // CHECK: %[[YHII:.+]] = arith.index_cast %[[YHI]] - // CHECK: %[[XLOI:.+]] = arith.index_cast %[[XLO]] - // CHECK: %[[XHII:.+]] = arith.index_cast %[[XHI]] - - // CHECK: %[[LOLO:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[YLOI]], %[[XLOI]], %[[IDX_3]]] - // CHECK: %[[LOHI:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[YLOI]], %[[XHII]], %[[IDX_3]]] - // CHECK: %[[HILO:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[YHII]], %[[XLOI]], %[[IDX_3]]] - // CHECK: %[[HIHI:.+]] = tensor.extract %arg0[%[[IDX_0]], %[[YHII]], %[[XHII]], %[[IDX_3]]] - - // CHECK: %[[NDX:.+]] = arith.subf %[[SCALE_X_N]], %[[D_X]] - // CHECK: %[[WLOLO:.+]] = arith.mulf %[[LOLO]], %[[NDX]] - // CHECK: %[[WLOHI:.+]] = arith.mulf %[[LOHI]], %[[D_X]] - // CHECK: %[[LO:.+]] = arith.addf %[[WLOLO]], %[[WLOHI]] - // CHECK: %[[WHILO:.+]] = arith.mulf %[[HILO]], %[[NDX]] - // CHECK: %[[WHIHI:.+]] = arith.mulf %[[HIHI]], %[[D_X]] - // CHECK: %[[HI:.+]] = arith.addf %[[WHILO]], %[[WHIHI]] - // CHECK: %[[NDY:.+]] = arith.subf %[[SCALE_Y_N]], %[[D_Y]] - // CHECK: %[[WLO:.+]] = arith.mulf %[[LO]], %[[NDY]] - // CHECK: %[[WHI:.+]] = arith.mulf %[[HI]], %[[D_Y]] - // CHECK: %[[RESULT:.+]] = arith.addf %[[WLO]], %[[WHI]] - // CHECK: linalg.yield %[[RESULT]] - - // Round by bilinear interpolation - %output = "tosa.resize"(%input) {mode = "BILINEAR", scale = [4, 1, 4, 1], offset = [0, 0], border = [0, 0]} : (tensor<1x23x23x1xf32>) -> tensor<1x89x89x1xf32> - - return -} - -// ----- - -// CHECK-LABEL: @resize_dyn -// CHECK-SAME: (%[[ARG0:[0-9a-zA-Z_]*]]: -func.func @resize_dyn(%input: tensor) -> () { - // CHECK: %[[C0:.+]] = arith.constant 0 - // CHECK: %[[BATCH:.+]] = tensor.dim %arg0, %[[C0]] - // CHECK: %[[INIT:.+]] = tensor.empty(%[[BATCH]]) : tensor - // CHECK: %[[GENERIC:.+]] = linalg.generic - %output = "tosa.resize"(%input) { scale = [4, 2, 4, 2], offset = [-1, -1], border = [1, 1], mode = "BILINEAR" } : (tensor) -> (tensor) - return -} - -// ----- - // Regression test for using the wrong rank. // CHECK-DAG: affine_map<(d0, d1, d2, d3) -> (d0, d2, d3)>