[Mlir-commits] [mlir] [mlir][tosa] Fix tosa.Resize-to-linalg lowering (PR #88514)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Apr 12 06:48:40 PDT 2024


https://github.com/fabrizio-indirli created https://github.com/llvm/llvm-project/pull/88514

Simplify the lowering of tosa.resize to linalg, to match more closely the implementation from the TOSA specification: some internal arithmetic operations are now performed on the integer types (rather than in floating point) to reduce the loss of precision and the num of generated operations.

>From e12435523d8fa2716cee37d6f7097096281d32cb Mon Sep 17 00:00:00 2001
From: Fabrizio Indirli <Fabrizio.Indirli at arm.com>
Date: Fri, 12 Apr 2024 13:15:44 +0100
Subject: [PATCH] [mlir][tosa] Fix tosa.Resize-to-linalg lowering

Simplify the lowering of tosa.resize to linalg, to match
more closely the implementation from the TOSA specification:
some internal arithmetic operations are now performed on
the integer types (rather than in floating point) to reduce
the loss of precision and the num of generated operations.

Signed-off-by: Fabrizio Indirli <Fabrizio.Indirli at arm.com>
---
 .../Conversion/TosaToLinalg/TosaToLinalg.cpp  |  21 ++--
 .../TosaToLinalg/tosa-to-linalg-resize.mlir   | 112 ++++++++----------
 2 files changed, 60 insertions(+), 73 deletions(-)

diff --git a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
index 7c477f2e1412be..1a743282adc487 100644
--- a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
+++ b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
@@ -1578,17 +1578,16 @@ class GenericResizeConverter : public OpRewritePattern<tosa::ResizeOp> {
         }
         // x = x * scale_d + offset;
         // ix = floor(x / scale_n)
-        // dx = x / scale_n - ix
-        Value val = b.create<arith::UIToFPOp>(floatTy, in);
-        scaleN = b.create<arith::UIToFPOp>(floatTy, scaleN);
-        scaleD = b.create<arith::UIToFPOp>(floatTy, scaleD);
-        offset = b.create<arith::SIToFPOp>(floatTy, offset);
-        val = b.create<arith::MulFOp>(val, scaleD);
-        val = b.create<arith::AddFOp>(val, offset);
-        val = b.create<arith::DivFOp>(val, scaleN);
-        index = b.create<math::FloorOp>(val);
-        delta = b.create<arith::SubFOp>(val, index);
-        index = b.create<arith::FPToSIOp>(b.getI32Type(), index);
+        Value val = b.create<arith::MulIOp>(in, scaleD);
+        val = b.create<arith::AddIOp>(val, offset);
+        index = b.create<arith::FloorDivSIOp>(val, scaleN);
+
+        // rx = x % scale_n
+        // dx = rx / scale_n
+        Value r = b.create<arith::RemSIOp>(val, scaleN);
+        Value rFp = b.create<arith::SIToFPOp>(floatTy, r);
+        Value scaleNfp = b.create<arith::UIToFPOp>(floatTy, scaleN);
+        delta = b.create<arith::DivFOp>(rFp, scaleNfp);
       };
 
       // Compute the ix and dx values for the X and Y dimensions - int case.
diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
index 468e92e2a2661f..d42d0a46692d47 100644
--- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
+++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
@@ -304,42 +304,36 @@ func.func @resize_nearest_fp32(%input: tensor<1x50x48x1xf32>) -> () {
   // 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: %[[SCALE_Y_N:.*]] = arith.uitofp %[[ISCALE_Y_N]]
-  // CHECK: %[[SCALE_Y_D:.*]] = arith.uitofp %[[ISCALE_Y_D]]
-  // CHECK: %[[OFFSET_Y:.*]] = arith.sitofp %[[IOFFSET_Y]]
-  // CHECK: %[[VAL_29:.*]] = arith.mulf %[[Y0]], %[[SCALE_Y_D]]
-  // CHECK: %[[VAL_31:.*]] = arith.addf %[[VAL_29]], %[[OFFSET_Y]]
-  // CHECK: %[[VAL_33:.*]] = arith.divf %[[VAL_31]], %[[SCALE_Y_N]]
-  // CHECK: %[[VAL_35:.*]] = math.floor %[[VAL_33]]
-  // CHECK: %[[D_Y:.*]] = arith.subf %[[VAL_33]], %[[VAL_35]]
-  // CHECK: %[[VAL_39:.*]] = arith.fptosi %[[VAL_35]]
-
-  // CHECK: %[[X0:.+]] = arith.uitofp %[[X]]
-  // CHECK: %[[SCALE_X_N:.*]] = arith.uitofp %[[ISCALE_X_N]]
-  // CHECK: %[[SCALE_X_D:.*]] = arith.uitofp %[[ISCALE_X_D]]
-  // CHECK: %[[OFFSET_X:.*]] = arith.sitofp %[[IOFFSET_X]]
-  // CHECK: %[[VAL_30:.*]] = arith.mulf %[[X0]], %[[SCALE_X_D]]
-  // CHECK: %[[VAL_32:.*]] = arith.addf %[[VAL_30]], %[[OFFSET_X]]
-  // CHECK: %[[VAL_34:.*]] = arith.divf %[[VAL_32]], %[[SCALE_X_N]]
-  // CHECK: %[[VAL_36:.*]] = math.floor %[[VAL_34]]
-  // CHECK: %[[D_X:.*]] = arith.subf %[[VAL_34]], %[[VAL_36]]
-  // CHECK: %[[VAL_40:.*]] = arith.fptosi %[[VAL_36]]
+  // CHECK-DAG: %[[SCALE_Y_N:.*]] = arith.constant 64
+  // CHECK-DAG: %[[SCALE_Y_D:.*]] = arith.constant 2
+  // CHECK-DAG: %[[SCALE_X_N:.*]] = arith.constant 64
+  // CHECK-DAG: %[[SCALE_X_D:.*]] = arith.constant 2
+  // CHECK-DAG: %[[OFFSET_Y:.*]] = arith.constant -31
+  // CHECK-DAG: %[[OFFSET_X:.*]] = arith.constant -31
+  // CHECK-DAG: %[[BORDER_Y:.*]] = arith.constant 31
+  // CHECK-DAG: %[[BORDER_X:.*]] = arith.constant 31
+
+  // CHECK: %[[VAL_29:.*]] = arith.muli %[[Y]], %[[SCALE_Y_D]]
+  // CHECK: %[[Y_TEMP:.*]] = arith.addi %[[VAL_29]], %[[OFFSET_Y]]
+  // CHECK: %[[IY_TEMP:.*]] = arith.floordivsi %[[Y_TEMP]], %[[SCALE_Y_N]]
+  // CHECK: %[[RY:.*]] = arith.remsi %[[Y_TEMP]], %[[SCALE_Y_N]]
+  // CHECK: %[[RY_FP:.*]] = arith.sitofp %[[RY]]
+  // CHECK: %[[SCALE_Y_N_FP:.*]] = arith.uitofp %[[SCALE_Y_N]]
+  // CHECK: %[[D_Y:.*]] = arith.divf %[[RY_FP]], %[[SCALE_Y_N_FP]]
+
+  // CHECK: %[[VAL_30:.*]] = arith.muli %[[X]], %[[SCALE_X_D]]
+  // CHECK: %[[X_TEMP:.*]] = arith.addi %[[VAL_30]], %[[OFFSET_X]]
+  // CHECK: %[[IX_TEMP:.*]] = arith.floordivsi %[[X_TEMP]], %[[SCALE_X_N]]
+  // CHECK: %[[RX:.*]] = arith.remsi %[[X_TEMP]], %[[SCALE_X_N]]
+  // CHECK: %[[RX_FP:.*]] = arith.sitofp %[[RX]]
+  // CHECK: %[[SCALE_X_N_FP:.*]] = arith.uitofp %[[SCALE_X_N]]
+  // CHECK: %[[D_X:.*]] = arith.divf %[[RX_FP]], %[[SCALE_X_N_FP]]
 
   // CHECK-DAG: %[[ONE:.*]] = arith.constant 1
   // CHECK-DAG: %[[HALF:.*]] = arith.constant 5.000000e-01
   // CHECK: %[[PRED_Y:.*]] = arith.cmpf oge, %[[D_Y]], %[[HALF]]
   // CHECK: %[[ROUND_Y:.*]] = arith.select %[[PRED_Y]], %[[ONE]], %[[ZERO]]
-  // CHECK: %[[VAL_48:.*]] = arith.addi %[[VAL_39]], %[[ROUND_Y]]
+  // CHECK: %[[VAL_48:.*]] = arith.addi %[[IY_TEMP]], %[[ROUND_Y]]
   // CHECK: %[[LOWER:.*]] = arith.maxsi %[[ZERO]], %[[VAL_48]]
   // CHECK: %[[CLAMPED:.*]] = arith.minsi %[[YMAX]], %[[LOWER]]
   // CHECK: %[[IDY:.*]] = arith.index_cast %[[CLAMPED]]
@@ -347,7 +341,7 @@ func.func @resize_nearest_fp32(%input: tensor<1x50x48x1xf32>) -> () {
   // CHECK-DAG: %[[HALF:.*]] = arith.constant 5.000000e-01
   // CHECK: %[[PRED_X:.*]] = arith.cmpf oge, %[[D_X]], %[[HALF]]
   // CHECK: %[[ROUND_X:.*]] = arith.select %[[PRED_X]], %[[ONE]], %[[ZERO]]
-  // CHECK: %[[VAL_49:.*]] = arith.addi %[[VAL_40]], %[[ROUND_X]]
+  // CHECK: %[[VAL_49:.*]] = arith.addi %[[IX_TEMP]], %[[ROUND_X]]
   // CHECK: %[[LOWER:.*]] = arith.maxsi %[[ZERO]], %[[VAL_49]]
   // CHECK: %[[CLAMPED:.*]] = arith.minsi %[[XMAX]], %[[LOWER]]
   // CHECK: %[[IDX:.*]] = arith.index_cast %[[CLAMPED]]
@@ -374,36 +368,30 @@ func.func @resize_bilinear_fp(%input: tensor<1x23x24x1xf32>) -> () {
   // CHECK-DAG: %[[X_MAX:.*]] = arith.constant 23
   // 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: %[[SCALE_Y_N:.*]] = arith.uitofp %[[ISCALE_Y_N]]
-  // CHECK: %[[SCALE_Y_D:.*]] = arith.uitofp %[[ISCALE_Y_D]]
-  // CHECK: %[[OFFSET_Y:.*]] = arith.sitofp %[[IOFFSET_Y]]
-  // CHECK: %[[VAL_29:.*]] = arith.mulf %[[Y0]], %[[SCALE_Y_D]]
-  // CHECK: %[[VAL_31:.*]] = arith.addf %[[VAL_29]], %[[OFFSET_Y]]
-  // CHECK: %[[VAL_33:.*]] = arith.divf %[[VAL_31]], %[[SCALE_Y_N]]
-  // CHECK: %[[VAL_35:.*]] = math.floor %[[VAL_33]]
-  // CHECK: %[[D_Y:.*]] = arith.subf %[[VAL_33]], %[[VAL_35]]
-  // CHECK: %[[I_Y:.*]] = arith.fptosi %[[VAL_35]]
-
-  // CHECK: %[[X0:.+]] = arith.uitofp %[[X]]
-  // CHECK: %[[SCALE_X_N:.*]] = arith.uitofp %[[ISCALE_X_N]]
-  // CHECK: %[[SCALE_X_D:.*]] = arith.uitofp %[[ISCALE_X_D]]
-  // CHECK: %[[OFFSET_X:.*]] = arith.sitofp %[[IOFFSET_X]]
-  // CHECK: %[[VAL_30:.*]] = arith.mulf %[[X0]], %[[SCALE_X_D]]
-  // CHECK: %[[VAL_32:.*]] = arith.addf %[[VAL_30]], %[[OFFSET_X]]
-  // CHECK: %[[VAL_34:.*]] = arith.divf %[[VAL_32]], %[[SCALE_X_N]]
-  // CHECK: %[[VAL_36:.*]] = math.floor %[[VAL_34]]
-  // CHECK: %[[D_X:.*]] = arith.subf %[[VAL_34]], %[[VAL_36]]
-  // CHECK: %[[I_X:.*]] = arith.fptosi %[[VAL_36]]
+  // CHECK-DAG: %[[SCALE_Y_N:.*]] = arith.constant 4
+  // CHECK-DAG: %[[SCALE_Y_D:.*]] = arith.constant 1
+  // CHECK-DAG: %[[SCALE_X_N:.*]] = arith.constant 4
+  // 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: %[[VAL_29:.*]] = arith.muli %[[Y]], %[[SCALE_Y_D]]
+  // CHECK: %[[Y_TEMP:.*]] = arith.addi %[[VAL_29]], %[[OFFSET_Y]]
+  // CHECK: %[[I_Y:.*]] = arith.floordivsi %[[Y_TEMP]], %[[SCALE_Y_N]]
+  // CHECK: %[[RY:.*]] = arith.remsi %[[Y_TEMP]], %[[SCALE_Y_N]]
+  // CHECK: %[[RY_FP:.*]] = arith.sitofp %[[RY]]
+  // CHECK: %[[SCALE_Y_N_FP:.*]] = arith.uitofp %[[SCALE_Y_N]]
+  // CHECK: %[[D_Y:.*]] = arith.divf %[[RY_FP]], %[[SCALE_Y_N_FP]]
+
+  // CHECK: %[[VAL_30:.*]] = arith.muli %[[X]], %[[SCALE_X_D]]
+  // CHECK: %[[X_TEMP:.*]] = arith.addi %[[VAL_30]], %[[OFFSET_X]]
+  // CHECK: %[[I_X:.*]] = arith.floordivsi %[[X_TEMP]], %[[SCALE_X_N]]
+  // CHECK: %[[RX:.*]] = arith.remsi %[[X_TEMP]], %[[SCALE_X_N]]
+  // CHECK: %[[RX_FP:.*]] = arith.sitofp %[[RX]]
+  // CHECK: %[[SCALE_X_N_FP:.*]] = arith.uitofp %[[SCALE_X_N]]
+  // CHECK: %[[D_X:.*]] = arith.divf %[[RX_FP]], %[[SCALE_X_N_FP]]
 
   // Compute the left, right, and top indices for the bilinear interpolation.
 



More information about the Mlir-commits mailing list