[Mlir-commits] [mlir] [mlir][tosa][tosa-to-linalg] Fix resize bilinear delta computation for negative offsets (PR #184799)

Luke Hutton llvmlistbot at llvm.org
Thu Mar 5 06:14:13 PST 2026


https://github.com/lhutton1 created https://github.com/llvm/llvm-project/pull/184799

Use floor-consistent remainder when lowering floating-point tosa.resize to linalg: compute `r = in - floor(in/scale_n)*scale_n` instead of RemSIOp. This keeps bilinear deltas in-range for negative offsets and avoids invalid interpolation weights.

>From 35d2d7b4e15d66e6da495f265ed213bce0ff9c76 Mon Sep 17 00:00:00 2001
From: Luke Hutton <luke.hutton at arm.com>
Date: Thu, 5 Mar 2026 13:56:06 +0000
Subject: [PATCH] [mlir][tosa][tosa-to-linalg] Fix resize bilinear delta
 computation for negative offsets

Use floor-consistent remainder when lowering floating-point tosa.resize to linalg:
compute `r = in - floor(in/scale_n)*scale_n` instead of RemSIOp. This keeps
bilinear deltas in-range for negative offsets and avoids invalid interpolation
weights.

Change-Id: I5f0e00c651702f60898b7e26c9b99903f8ce76eb
---
 mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp    |  8 +++++---
 .../TosaToLinalg/tosa-to-linalg-resize.mlir          | 12 ++++++++----
 2 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
index b834106b10528..76346a766f1f7 100644
--- a/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
+++ b/mlir/lib/Conversion/TosaToLinalg/TosaToLinalg.cpp
@@ -2036,10 +2036,12 @@ class GenericResizeConverter : public OpRewritePattern<tosa::ResizeOp> {
         val = arith::AddIOp::create(b, val, offset);
         index = arith::FloorDivSIOp::create(b, val, scaleN);
 
-        // rx = x % scale_n
-        // dx = rx / scale_n
-        Value r = arith::RemSIOp::create(b, val, scaleN);
+        // rx = x - ix * scale_n (x % scale_n, if values are positive)
+        Value scaledIndex = arith::MulIOp::create(b, index, scaleN);
+        Value r = arith::SubIOp::create(b, val, scaledIndex);
         Value rFp = arith::SIToFPOp::create(b, floatTy, r);
+
+        // dx = rx / scale_n
         Value scaleNfp = arith::UIToFPOp::create(b, floatTy, scaleN);
         delta = arith::DivFOp::create(b, rFp, scaleNfp);
       };
diff --git a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
index 6998aee45b887..4900476b25dc5 100644
--- a/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
+++ b/mlir/test/Conversion/TosaToLinalg/tosa-to-linalg-resize.mlir
@@ -389,7 +389,8 @@ func.func @resize_nearest_fp32(%input: tensor<1x50x48x1xf32>) -> () {
   // 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: %[[SCALED_IY:.*]] = arith.muli %[[IY_TEMP]], %[[SCALE_Y_N]]
+  // CHECK: %[[RY:.*]] = arith.subi %[[Y_TEMP]], %[[SCALED_IY]]
   // 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]]
@@ -397,7 +398,8 @@ func.func @resize_nearest_fp32(%input: tensor<1x50x48x1xf32>) -> () {
   // 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: %[[SCALED_IX:.*]] = arith.muli %[[IX_TEMP]], %[[SCALE_X_N]]
+  // CHECK: %[[RX:.*]] = arith.subi %[[X_TEMP]], %[[SCALED_IX]]
   // 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]]
@@ -456,7 +458,8 @@ func.func @resize_bilinear_fp(%input: tensor<1x23x24x1xf32>) -> () {
   // 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: %[[SCALED_IY:.*]] = arith.muli %[[I_Y]], %[[SCALE_Y_N]]
+  // CHECK: %[[RY:.*]] = arith.subi %[[Y_TEMP]], %[[SCALED_IY]]
   // 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]]
@@ -464,7 +467,8 @@ func.func @resize_bilinear_fp(%input: tensor<1x23x24x1xf32>) -> () {
   // 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: %[[SCALED_IX:.*]] = arith.muli %[[I_X]], %[[SCALE_X_N]]
+  // CHECK: %[[RX:.*]] = arith.subi %[[X_TEMP]], %[[SCALED_IX]]
   // 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]]



More information about the Mlir-commits mailing list