[M-146] Don't replace minimum/maximum operators with clamp when input is broadcast
When the rank of the minimum/maximum argument is greater than the input rank the broadcasting behavior is necessary for the following nodes in the graph so replacement with a single-input (non-broadcasting) clamp operator is inappropriate.
(Cherry-picked from 82367b51bf738ce41a28515b348c3434eb6d2060.)
PiperOrigin-RevId: 871408578
Bug: 483445078
Change-Id: I6855afcb77d67e425d45105755164f8c4ade7720
diff --git a/src/subgraph.c b/src/subgraph.c
index 750e2df..e5107bf 100644
--- a/src/subgraph.c
+++ b/src/subgraph.c
@@ -2866,19 +2866,32 @@
return xnn_status_success;
}
- // Check that `arg_value` is a static scalar value.
+ // `arg_value` must be a static scalar value, but we can swap the arguments to
+ // make that true.
struct xnn_value* input_value = &subgraph->values[node->inputs[0]];
struct xnn_value* arg_value = &subgraph->values[node->inputs[1]];
- if (!xnn_value_is_const(arg_value->flags) &&
- !(xnn_shape_multiply_all_dims(&arg_value->shape) == 1 &&
- xnn_value_is_static(arg_value->allocation_type))) {
- if (xnn_value_is_const(input_value->flags) ||
- (xnn_shape_multiply_all_dims(&input_value->shape) == 1 &&
- xnn_value_is_static(input_value->allocation_type))) {
+
+ const bool input_is_static_scalar =
+ xnn_value_is_const(input_value->flags) ||
+ (xnn_shape_multiply_all_dims(&input_value->shape) == 1 &&
+ xnn_value_is_static(input_value->allocation_type));
+ const bool arg_is_static_scalar =
+ xnn_value_is_const(arg_value->flags) ||
+ (xnn_shape_multiply_all_dims(&arg_value->shape) == 1 &&
+ xnn_value_is_static(arg_value->allocation_type));
+
+ if (input_is_static_scalar) {
+ if (!arg_is_static_scalar) {
swap_value_pointers(&arg_value, &input_value);
- } else {
- return xnn_status_success;
}
+ } else if (!arg_is_static_scalar) {
+ return xnn_status_success;
+ }
+
+ if (arg_value->shape.num_dims > input_value->shape.num_dims) {
+ // The min or max operator is broadcasting the input to match the scalar's
+ // rank, so we can't replace the operator.
+ return xnn_status_success;
}
// Extract the min/max argument.
diff --git a/test/subgraph/rewrites.cc b/test/subgraph/rewrites.cc
index 6029c5f..433cd89 100644
--- a/test/subgraph/rewrites.cc
+++ b/test/subgraph/rewrites.cc
@@ -620,9 +620,9 @@
uint32_t static_min_value_id;
uint32_t static_max_value_id;
std::tie(static_min_tensor, static_min_value_id) =
- add_static_tensor<float>(rng, subgraph, {1});
+ add_static_tensor<float>(rng, subgraph, {});
std::tie(static_max_tensor, static_max_value_id) =
- add_static_tensor<float>(rng, subgraph, {1});
+ add_static_tensor<float>(rng, subgraph, {});
// Add the binary `minimum` op.
uint32_t min_capped_value_id =
@@ -674,9 +674,9 @@
uint32_t static_min_value_id;
uint32_t static_max_value_id;
std::tie(static_min_tensor, static_min_value_id) =
- add_static_tensor<float>(rng, subgraph, /*shape=*/{1});
+ add_static_tensor<float>(rng, subgraph, /*shape=*/{});
std::tie(static_max_tensor, static_max_value_id) =
- add_static_tensor<float>(rng, subgraph, /*shape=*/{1});
+ add_static_tensor<float>(rng, subgraph, /*shape=*/{});
// Add the binary `maximum` op.
uint32_t max_capped_value_id =