Skip to content

Conversation

@Tai78641
Copy link
Contributor

This commit uses mulBinaryFolder for reduce_prod operations that have a constant 1D input of two values.

@llvmbot
Copy link
Member

llvmbot commented Feb 20, 2025

@llvm/pr-subscribers-mlir

@llvm/pr-subscribers-mlir-tosa

Author: Tai Ly (Tai78641)

Changes

This commit uses mulBinaryFolder for reduce_prod operations that have a constant 1D input of two values.


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

2 Files Affected:

  • (modified) mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp (+25-1)
  • (modified) mlir/test/Dialect/Tosa/canonicalize.mlir (+11)
diff --git a/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp b/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
index 9bfc2aae1d6a5..45bcacff19caa 100644
--- a/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
+++ b/mlir/lib/Dialect/Tosa/IR/TosaCanonicalizations.cpp
@@ -963,10 +963,34 @@ REDUCE_FOLDER(ReduceAllOp)
 REDUCE_FOLDER(ReduceAnyOp)
 REDUCE_FOLDER(ReduceMaxOp)
 REDUCE_FOLDER(ReduceMinOp)
-REDUCE_FOLDER(ReduceProdOp)
 REDUCE_FOLDER(ReduceSumOp)
 #undef REDUCE_FOLDER
 
+OpFoldResult ReduceProdOp::fold(FoldAdaptor adaptor) {
+  ShapedType inputTy = llvm::cast<ShapedType>(getInput().getType());
+  if (!inputTy.hasRank())
+    return {};
+  if (inputTy == getType() && (inputTy.getRank() == 0 || inputTy.getDimSize(getAxis()) == 1))
+    return getInput();
+
+  // Fold multiply like reduce_prod operators using mulBinaryFolder
+  if (inputTy.getRank() == 1 && inputTy.getDimSize(0) == 2) {
+    const auto resultTy = llvm::dyn_cast<RankedTensorType>(getType());
+    if (!resultTy)
+      return {};
+
+    const auto elements = llvm::dyn_cast_if_present<DenseElementsAttr>(adaptor.getInput());
+    if (!elements)
+      return {};
+
+    const auto lhsAttr = DenseElementsAttr::get(resultTy, {elements.getValues<Attribute>()[0]});
+    const auto rhsAttr = DenseElementsAttr::get(resultTy, {elements.getValues<Attribute>()[1]});
+    return mulBinaryFolder(lhsAttr, rhsAttr, resultTy, 0);
+  }
+
+  return {};
+}
+
 OpFoldResult ReshapeOp::fold(FoldAdaptor adaptor) {
   auto inputTy = llvm::dyn_cast<RankedTensorType>(getInput1().getType());
   auto outputTy = llvm::dyn_cast<RankedTensorType>(getType());
diff --git a/mlir/test/Dialect/Tosa/canonicalize.mlir b/mlir/test/Dialect/Tosa/canonicalize.mlir
index 0e177a076ee7a..316f22f88fc69 100644
--- a/mlir/test/Dialect/Tosa/canonicalize.mlir
+++ b/mlir/test/Dialect/Tosa/canonicalize.mlir
@@ -1012,3 +1012,14 @@ func.func nested @do_not_fold_reciprocal_int() -> tensor<3x600x1200xi32> {
   %2 = "tosa.reciprocal"(%1): (tensor<3x600x1200xi32>) -> tensor<3x600x1200xi32>
   return %2 : tensor<3x600x1200xi32>
 }
+
+// -----
+
+// CHECK-LABEL: @fold_reduce_prod_is_mul
+func.func @fold_reduce_prod_is_mul() -> tensor<1xi32> {
+  // CHECK-DAG: %[[VAL_0:.*]] = "tosa.const"() <{value = dense<77> : tensor<1xi32>}> : () -> tensor<1xi32>
+  // CHECK: return %[[VAL_0]] : tensor<1xi32>
+  %0 = "tosa.const"() <{value = dense<[1, 77]> : tensor<2xi32>}> : () -> tensor<2xi32>
+  %1 = "tosa.reduce_prod"(%0) <{axis = 0 : i32}> : (tensor<2xi32>) -> tensor<1xi32>
+  return %1 : tensor<1xi32>
+}

@github-actions
Copy link

github-actions bot commented Feb 20, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@Tai78641 Tai78641 force-pushed the pr_add_mul_folder branch 2 times, most recently from a4b507e to 62b2409 Compare February 20, 2025 21:28
@Jerry-Ge Jerry-Ge changed the title [mlir][TOSA] Add folder for multiply like reduce_prod operation [mlir][tosa] Add folder for multiply like reduce_prod operation Feb 20, 2025
(inputTy.getRank() == 0 || inputTy.getDimSize(getAxis()) == 1))
return getInput();

// Fold multiply like reduce_prod operators using mulBinaryFolder
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is quite limited special-cased. What is the motivation behind this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed it's quite special cased, it was observed while legalizing a model with dynamic shapes

Copy link
Contributor

@FranklandJack FranklandJack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove the change ID from the commit message?

OpFoldResult ReduceProdOp::fold(FoldAdaptor adaptor) {
ShapedType inputTy = llvm::cast<ShapedType>(getInput().getType());
if (!inputTy.hasRank())
return {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add a newline after the return here to aid readability?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

#undef REDUCE_FOLDER

OpFoldResult ReduceProdOp::fold(FoldAdaptor adaptor) {
ShapedType inputTy = llvm::cast<ShapedType>(getInput().getType());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use auto here since the type is already explicit on the RHS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return getInput();

// Fold multiply like reduce_prod operators using mulBinaryFolder
if (inputTy.getRank() == 1 && inputTy.getDimSize(0) == 2) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we invert the condition here and do an early exit to avoid the indention and big conditional block?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

return %2 : tensor<3x600x1200xi32>
}

// -----
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add some negative tests here? From the above logic it seems like the following cases should fail:

  1. input tensor of rank > 1
  2. input tensor of rank 1 with dim[0] > 1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

@Tai78641 Tai78641 force-pushed the pr_add_mul_folder branch from 62b2409 to 835c8db Compare March 3, 2025 21:52
@Tai78641 Tai78641 requested a review from FranklandJack March 3, 2025 21:53
@Tai78641 Tai78641 force-pushed the pr_add_mul_folder branch 3 times, most recently from 98ff8a5 to b2026c2 Compare March 7, 2025 19:57
This commit uses mulBinaryFolder for reduce_prod operations that have
a constant 1D input of two values.

Change-Id: Icb234282c70898189083231506ed38a3ab40efb2
Signed-off-by: Luke Hutton <[email protected]>
@Tai78641 Tai78641 force-pushed the pr_add_mul_folder branch from b2026c2 to a8fd688 Compare March 7, 2025 21:05
@lhutton1
Copy link
Contributor

No longer needed

@lhutton1 lhutton1 closed this May 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants