[Mlir-commits] [mlir] [mlir][tosa] Add clamp op support to `TosaNarrowI64ToI32` pass (PR #169308)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Nov 24 02:10:25 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Luke Hutton (lhutton1)

<details>
<summary>Changes</summary>

This commit allows the narrowing of `tosa.clamp` when the min/max attributes are within the int32 range.

---
Full diff: https://github.com/llvm/llvm-project/pull/169308.diff


3 Files Affected:

- (modified) mlir/lib/Dialect/Tosa/Transforms/TosaNarrowI64ToI32.cpp (+38) 
- (modified) mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32-aggressive.mlir (+9) 
- (modified) mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32.mlir (+9) 


``````````diff
diff --git a/mlir/lib/Dialect/Tosa/Transforms/TosaNarrowI64ToI32.cpp b/mlir/lib/Dialect/Tosa/Transforms/TosaNarrowI64ToI32.cpp
index ddaf7d8a5e033..be442cc4f88ca 100644
--- a/mlir/lib/Dialect/Tosa/Transforms/TosaNarrowI64ToI32.cpp
+++ b/mlir/lib/Dialect/Tosa/Transforms/TosaNarrowI64ToI32.cpp
@@ -176,6 +176,42 @@ class ConvertCastOpWithBoundsChecking
   }
 };
 
+class ConvertClampOpWithBoundsChecking
+    : public OpConversionPattern<tosa::ClampOp> {
+  using OpConversionPattern::OpConversionPattern;
+
+  LogicalResult
+  matchAndRewrite(tosa::ClampOp op, OpAdaptor adaptor,
+                  ConversionPatternRewriter &rewriter) const final {
+    const auto minAttr = dyn_cast<IntegerAttr>(op.getMinValAttr());
+    const auto maxAttr = dyn_cast<IntegerAttr>(op.getMaxValAttr());
+    if (!minAttr || !maxAttr)
+      return failure();
+
+    const int64_t min = minAttr.getInt();
+    const int64_t max = maxAttr.getInt();
+
+    if (min < std::numeric_limits<int32_t>::min() ||
+        max > std::numeric_limits<int32_t>::max())
+      return rewriter.notifyMatchFailure(
+          op, "Clamp bounds exceed int32 range. Narrowing cast may lead to "
+              "data loss.");
+
+    const Type resultType = op.getOutput().getType();
+    const Type newResultType = typeConverter->convertType(resultType);
+
+    const IntegerType int32Type = IntegerType::get(rewriter.getContext(), 32);
+    const IntegerAttr newMinAttr =
+        rewriter.getIntegerAttr(int32Type, static_cast<int32_t>(min));
+    const IntegerAttr newMaxAttr =
+        rewriter.getIntegerAttr(int32Type, static_cast<int32_t>(max));
+    rewriter.replaceOpWithNewOp<tosa::ClampOp>(op, newResultType,
+                                               adaptor.getInput(), newMinAttr,
+                                               newMaxAttr, op.getNanModeAttr());
+    return success();
+  }
+};
+
 template <typename OpTy>
 class ConvertTypedOp : public OpConversionPattern<OpTy> {
   using OpConversionPattern<OpTy>::OpConversionPattern;
@@ -285,6 +321,8 @@ struct TosaNarrowI64ToI32
     } else {
       // Tensor
       patterns.add<ConvertArgMaxOpWithBoundsChecking>(typeConverter, context);
+      // Activation functions
+      patterns.add<ConvertClampOpWithBoundsChecking>(typeConverter, context);
       // Data layout
       patterns.add<ConvertTypedOp<tosa::ConcatOp>>(typeConverter, context);
       patterns.add<ConvertTypedOp<tosa::PadOp>>(typeConverter, context);
diff --git a/mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32-aggressive.mlir b/mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32-aggressive.mlir
index 1a36177a37033..9848fe4abb345 100644
--- a/mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32-aggressive.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32-aggressive.mlir
@@ -79,3 +79,12 @@ func.func @test_const() -> tensor<2xi64> {
   // FUNCBOUND: return %[[CONST]] : tensor<2xi32>
   return %0 : tensor<2xi64>
 }
+
+// -----
+
+// CHECK-LABEL: test_clamp_trunc
+func.func @test_clamp_trunc(%arg0: tensor<100xi64>) -> tensor<100xi64> {
+  // COMMON: tosa.clamp %{{.*}} {max_val = 2147483647 : i32, min_val = -2147483648 : i32} : (tensor<100xi32>) -> tensor<100xi32>
+  %1 = tosa.clamp %arg0 {max_val = 3000000000 : i64, min_val = -2147483648 : i64} : (tensor<100xi64>) -> tensor<100xi64>
+  return %1 : tensor<100xi64>
+}
diff --git a/mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32.mlir b/mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32.mlir
index a14483fcdd7b0..c10393296a5df 100644
--- a/mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32.mlir
+++ b/mlir/test/Dialect/Tosa/tosa-narrow-i64-to-i32.mlir
@@ -160,3 +160,12 @@ func.func @test_transition_from_i64(%arg0: tensor<1xi64>) -> tensor<1xi32> {
   // COMMON: return %[[OUT_CAST]] : tensor<1xi32>
   return %2 : tensor<1xi32>
 }
+
+// -----
+
+// CHECK-LABEL: test_clamp
+func.func @test_clamp(%arg0: tensor<100xi64>) -> tensor<100xi64> {
+  // COMMON: tosa.clamp %{{.*}} {max_val = 2147483647 : i32, min_val = -2147483648 : i32} : (tensor<100xi32>) -> tensor<100xi32>
+  %1 = tosa.clamp %arg0 {max_val = 2147483647 : i64, min_val = -2147483648 : i64} : (tensor<100xi64>) -> tensor<100xi64>
+  return %1 : tensor<100xi64>
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/169308


More information about the Mlir-commits mailing list