ethosu: Fix concatenation OFM scaling

Some pooling operations like concatenation are NOPs requiring different
scaling calculations.

Signed-off-by: Rob Herring (Arm) <robh@kernel.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/39975>
This commit is contained in:
Rob Herring (Arm) 2026-04-14 09:17:20 -05:00 committed by Marge Bot
parent d772f36741
commit aaaca26fd2
5 changed files with 55 additions and 38 deletions

View file

@ -472,38 +472,45 @@ emit_pooling(struct ethosu_subgraph *subgraph, struct ethosu_operation *operatio
emit_common(subgraph, operation, false); emit_common(subgraph, operation, false);
switch (operation->pooling.type) { if (operation->pooling.nop) {
case ETHOSU_POOLING_TYPE_MAX: { scale = ethosu_quantize_scale(
if (!ethosu_ml_device(subgraph->base.device)->is_u65) { operation->ifm.scale / operation->ofm.scale,
EMIT1(NPU_SET_OFM_SCALE, NPU_SET_OFM_SCALE_ROUND_MODE(1), 1); &scale_shift, true);
break;
} else
FALLTHROUGH;
}
case ETHOSU_POOLING_TYPE_AVG: {
scale = pooling_emit_ofm_scaling(
operation->ifm.scale,
operation->ofm.scale,
operation->kernel.height,
operation->kernel.width,
&scale_shift);
EMIT1(NPU_SET_OFM_SCALE, NPU_SET_OFM_SCALE_SHIFT(scale_shift), scale); EMIT1(NPU_SET_OFM_SCALE, NPU_SET_OFM_SCALE_SHIFT(scale_shift), scale);
break; } else {
} switch (operation->pooling.type) {
case ETHOSU_POOLING_TYPE_SUM: { case ETHOSU_POOLING_TYPE_MAX: {
scale = sum_emit_ofm_scaling( if (!ethosu_ml_device(subgraph->base.device)->is_u65) {
operation->ifm.scale, EMIT1(NPU_SET_OFM_SCALE, NPU_SET_OFM_SCALE_ROUND_MODE(1), 1);
operation->ofm.scale, break;
operation->kernel.height, } else
operation->kernel.width, FALLTHROUGH;
&scale_shift); }
case ETHOSU_POOLING_TYPE_AVG: {
scale = pooling_emit_ofm_scaling(
operation->ifm.scale,
operation->ofm.scale,
operation->kernel.height,
operation->kernel.width,
&scale_shift);
EMIT1(NPU_SET_OFM_SCALE, NPU_SET_OFM_SCALE_SHIFT(scale_shift) | NPU_SET_OFM_SCALE_ROUND_MODE(1), scale); EMIT1(NPU_SET_OFM_SCALE, NPU_SET_OFM_SCALE_SHIFT(scale_shift), scale);
break; break;
} }
default: case ETHOSU_POOLING_TYPE_SUM: {
UNREACHABLE("Invalid pooling type"); scale = sum_emit_ofm_scaling(
operation->ifm.scale,
operation->ofm.scale,
operation->kernel.height,
operation->kernel.width,
&scale_shift);
EMIT1(NPU_SET_OFM_SCALE, NPU_SET_OFM_SCALE_SHIFT(scale_shift) | NPU_SET_OFM_SCALE_ROUND_MODE(1), scale);
break;
}
default:
UNREACHABLE("Invalid pooling type");
}
} }
emit_block_config(subgraph, operation); emit_block_config(subgraph, operation);
@ -658,8 +665,8 @@ eltwise_emit_ofm_scaling(
input_rescale = min_input_scale * input_shift_val / (2.0 * max_input_scale); input_rescale = min_input_scale * input_shift_val / (2.0 * max_input_scale);
output_rescale = (2.0 * max_input_scale) / (output_scale * input_shift_val); output_rescale = (2.0 * max_input_scale) / (output_scale * input_shift_val);
opa_scale = ethosu_quantize_scale(input_rescale, &opa_shift); opa_scale = ethosu_quantize_scale(input_rescale, &opa_shift, false);
ofm_scale = ethosu_quantize_scale(output_rescale, &ofm_shift); ofm_scale = ethosu_quantize_scale(output_rescale, &ofm_shift, false);
if (DBG_ENABLED(ETHOSU_DBG_MSGS)) { if (DBG_ENABLED(ETHOSU_DBG_MSGS)) {
fprintf(stderr, "ADD advanced scaling: ifm1_scale=%f ifm2_scale=%f ofm_scale=%f\n", fprintf(stderr, "ADD advanced scaling: ifm1_scale=%f ifm2_scale=%f ofm_scale=%f\n",
@ -711,7 +718,7 @@ simplified_elementwise_add_sub_scale(
output_rescale_val = (2.0 * max_input_scale) / (output_scale * input_shift_val); output_rescale_val = (2.0 * max_input_scale) / (output_scale * input_shift_val);
} }
*out_out_scale = ethosu_quantize_scale(output_rescale_val, out_out_shift); *out_out_scale = ethosu_quantize_scale(output_rescale_val, out_out_shift, false);
} }
/* /*
@ -739,8 +746,8 @@ eltwise_emit_ofm_scaling_u85(
&input1_rescale, &input2_rescale, &input1_rescale, &input2_rescale,
&ofm_scale, &ofm_shift); &ofm_scale, &ofm_shift);
opa_scale = ethosu_quantize_scale(input1_rescale, &opa_shift); opa_scale = ethosu_quantize_scale(input1_rescale, &opa_shift, false);
opb_scale = ethosu_quantize_scale(input2_rescale, &opb_shift); opb_scale = ethosu_quantize_scale(input2_rescale, &opb_shift, false);
EMIT1(NPU_SET_OPA_SCALE, EMIT1(NPU_SET_OPA_SCALE,
NPU_SET_OPA_SCALE_SHIFT(opa_shift) | NPU_SET_OPA_SCALE_DBL_RND(input_shift), NPU_SET_OPA_SCALE_SHIFT(opa_shift) | NPU_SET_OPA_SCALE_DBL_RND(input_shift),

View file

@ -85,7 +85,7 @@ fill_scale_and_biases(struct ethosu_subgraph *subgraph, struct ethosu_operation
} }
int32_t shift; int32_t shift;
int scale = ethosu_quantize_scale(conv_scale, &shift); int scale = ethosu_quantize_scale(conv_scale, &shift, false);
uint64_t bias = biases ? biases[i] : 0; uint64_t bias = biases ? biases[i] : 0;

View file

@ -264,6 +264,7 @@ ethosu_lower_concatenation(struct ethosu_subgraph *subgraph,
operation->round_mode = ETHOSU_ROUNDING_NATURAL; operation->round_mode = ETHOSU_ROUNDING_NATURAL;
} else } else
operation->pooling.type = ETHOSU_POOLING_TYPE_SUM; operation->pooling.type = ETHOSU_POOLING_TYPE_SUM;
operation->pooling.nop = true;
set_feature_maps(subgraph, poperation->input_tensors[input_idx], poperation->output_tensors[0], operation); set_feature_maps(subgraph, poperation->input_tensors[input_idx], poperation->output_tensors[0], operation);
operation->ofm.shape.depth = operation->ifm.shape.depth; operation->ofm.shape.depth = operation->ifm.shape.depth;

View file

@ -83,12 +83,20 @@ ethosu_round_up_divide(int a, int b)
} }
int int
ethosu_quantize_scale(double scale, int32_t *shift) ethosu_quantize_scale(double scale, int32_t *shift, bool reduced)
{ {
int exponent = 0; int exponent = 0;
double significand = frexp(scale, &exponent); double significand = frexp(scale, &exponent);
int32_t quantized_scale = round(significand * (double)(1LL << 31)); int32_t quantized_scale = round(significand * (double)(1LL << 31));
*shift = 31 - exponent; *shift = 31 - exponent;
if (reduced) {
quantized_scale = (quantized_scale >> 16) + (quantized_scale >> 15 & 1);
// make sure reduced scale does not overflow
quantized_scale = MIN2(quantized_scale, 0x7FFF);
*shift -= 16;
}
if (*shift > 63) { if (*shift > 63) {
if (quantized_scale > exp2(*shift - 63)) { if (quantized_scale > exp2(*shift - 63)) {
quantized_scale = quantized_scale >> (*shift - 63); quantized_scale = quantized_scale >> (*shift - 63);

View file

@ -168,6 +168,7 @@ struct ethosu_operation {
struct { struct {
enum ethosu_pooling_type type; enum ethosu_pooling_type type;
bool nop;
} pooling; } pooling;
struct { struct {
@ -278,6 +279,6 @@ int ethosu_round_up_to_multiple(int a, int b);
int ethosu_round_up_divide(int a, int b); int ethosu_round_up_divide(int a, int b);
int ethosu_quantize_scale(double scale, int32_t *shift); int ethosu_quantize_scale(double scale, int32_t *shift, bool reduced);
#endif /* ETHOSU_ML_H */ #endif /* ETHOSU_ML_H */