1*4bdc9457SAndroid Build Coastguard Worker // Copyright (c) Facebook, Inc. and its affiliates.
2*4bdc9457SAndroid Build Coastguard Worker // All rights reserved.
3*4bdc9457SAndroid Build Coastguard Worker //
4*4bdc9457SAndroid Build Coastguard Worker // Copyright 2019 Google LLC
5*4bdc9457SAndroid Build Coastguard Worker //
6*4bdc9457SAndroid Build Coastguard Worker // This source code is licensed under the BSD-style license found in the
7*4bdc9457SAndroid Build Coastguard Worker // LICENSE file in the root directory of this source tree.
8*4bdc9457SAndroid Build Coastguard Worker
9*4bdc9457SAndroid Build Coastguard Worker #include <assert.h>
10*4bdc9457SAndroid Build Coastguard Worker #include <math.h>
11*4bdc9457SAndroid Build Coastguard Worker #include <stdbool.h>
12*4bdc9457SAndroid Build Coastguard Worker #include <stddef.h>
13*4bdc9457SAndroid Build Coastguard Worker #include <stdint.h>
14*4bdc9457SAndroid Build Coastguard Worker #include <stdlib.h>
15*4bdc9457SAndroid Build Coastguard Worker #include <string.h>
16*4bdc9457SAndroid Build Coastguard Worker
17*4bdc9457SAndroid Build Coastguard Worker #include <fp16.h>
18*4bdc9457SAndroid Build Coastguard Worker
19*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack.h>
20*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/allocator.h>
21*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/operator.h>
22*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/common.h>
23*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/log.h>
24*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/math.h>
25*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/microparams-init.h>
26*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/params.h>
27*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/indirection.h>
28*4bdc9457SAndroid Build Coastguard Worker
29*4bdc9457SAndroid Build Coastguard Worker
compute_output_dimension_with_tf_same_padding(size_t input_dimension,size_t stride_dimension)30*4bdc9457SAndroid Build Coastguard Worker static inline size_t compute_output_dimension_with_tf_same_padding(
31*4bdc9457SAndroid Build Coastguard Worker size_t input_dimension,
32*4bdc9457SAndroid Build Coastguard Worker size_t stride_dimension)
33*4bdc9457SAndroid Build Coastguard Worker {
34*4bdc9457SAndroid Build Coastguard Worker return divide_round_up(input_dimension, stride_dimension);
35*4bdc9457SAndroid Build Coastguard Worker }
36*4bdc9457SAndroid Build Coastguard Worker
xnn_create_average_pooling2d_nhwc_qu8(uint32_t input_padding_top,uint32_t input_padding_right,uint32_t input_padding_bottom,uint32_t input_padding_left,uint32_t pooling_height,uint32_t pooling_width,uint32_t stride_height,uint32_t stride_width,size_t channels,size_t input_pixel_stride,size_t output_pixel_stride,uint8_t input_zero_point,float input_scale,uint8_t output_zero_point,float output_scale,uint8_t output_min,uint8_t output_max,uint32_t flags,xnn_operator_t * average_pooling_op_out)37*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_average_pooling2d_nhwc_qu8(
38*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_top,
39*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_right,
40*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_bottom,
41*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_left,
42*4bdc9457SAndroid Build Coastguard Worker uint32_t pooling_height,
43*4bdc9457SAndroid Build Coastguard Worker uint32_t pooling_width,
44*4bdc9457SAndroid Build Coastguard Worker uint32_t stride_height,
45*4bdc9457SAndroid Build Coastguard Worker uint32_t stride_width,
46*4bdc9457SAndroid Build Coastguard Worker size_t channels,
47*4bdc9457SAndroid Build Coastguard Worker size_t input_pixel_stride,
48*4bdc9457SAndroid Build Coastguard Worker size_t output_pixel_stride,
49*4bdc9457SAndroid Build Coastguard Worker uint8_t input_zero_point,
50*4bdc9457SAndroid Build Coastguard Worker float input_scale,
51*4bdc9457SAndroid Build Coastguard Worker uint8_t output_zero_point,
52*4bdc9457SAndroid Build Coastguard Worker float output_scale,
53*4bdc9457SAndroid Build Coastguard Worker uint8_t output_min,
54*4bdc9457SAndroid Build Coastguard Worker uint8_t output_max,
55*4bdc9457SAndroid Build Coastguard Worker uint32_t flags,
56*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t* average_pooling_op_out)
57*4bdc9457SAndroid Build Coastguard Worker {
58*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t average_pooling_op = NULL;
59*4bdc9457SAndroid Build Coastguard Worker enum xnn_status status = xnn_status_uninitialized;
60*4bdc9457SAndroid Build Coastguard Worker
61*4bdc9457SAndroid Build Coastguard Worker if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
62*4bdc9457SAndroid Build Coastguard Worker xnn_log_error("failed to create %s operator: XNNPACK is not initialized",
63*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8));
64*4bdc9457SAndroid Build Coastguard Worker goto error;
65*4bdc9457SAndroid Build Coastguard Worker }
66*4bdc9457SAndroid Build Coastguard Worker
67*4bdc9457SAndroid Build Coastguard Worker status = xnn_status_invalid_parameter;
68*4bdc9457SAndroid Build Coastguard Worker
69*4bdc9457SAndroid Build Coastguard Worker const uint32_t pooling_size = pooling_height * pooling_width;
70*4bdc9457SAndroid Build Coastguard Worker if (pooling_size == 0) {
71*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
72*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %" PRIu32 "x%" PRIu32 " pooling size: "
73*4bdc9457SAndroid Build Coastguard Worker "pooling size dimensions must be non-zero",
74*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), pooling_width, pooling_height);
75*4bdc9457SAndroid Build Coastguard Worker goto error;
76*4bdc9457SAndroid Build Coastguard Worker }
77*4bdc9457SAndroid Build Coastguard Worker
78*4bdc9457SAndroid Build Coastguard Worker if (pooling_size == 1) {
79*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
80*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with 1 pooling element: 1x1 pooling is meaningless",
81*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8));
82*4bdc9457SAndroid Build Coastguard Worker goto error;
83*4bdc9457SAndroid Build Coastguard Worker }
84*4bdc9457SAndroid Build Coastguard Worker
85*4bdc9457SAndroid Build Coastguard Worker if (stride_height == 0 || stride_width == 0) {
86*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
87*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %" PRIu32 "x%" PRIu32 " stride: stride dimensions must be non-zero",
88*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), stride_width, stride_height);
89*4bdc9457SAndroid Build Coastguard Worker goto error;
90*4bdc9457SAndroid Build Coastguard Worker }
91*4bdc9457SAndroid Build Coastguard Worker
92*4bdc9457SAndroid Build Coastguard Worker if (stride_height > pooling_height) {
93*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
94*4bdc9457SAndroid Build Coastguard Worker "failed to define %s operator with %" PRIu32 " stride height: must be less than pooling height %" PRIu32,
95*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), stride_height, pooling_height);
96*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
97*4bdc9457SAndroid Build Coastguard Worker }
98*4bdc9457SAndroid Build Coastguard Worker
99*4bdc9457SAndroid Build Coastguard Worker if (stride_width > pooling_width) {
100*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
101*4bdc9457SAndroid Build Coastguard Worker "failed to define %s operator with %" PRIu32 " stride width: must be less than pooling width %" PRIu32,
102*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), stride_width, pooling_width);
103*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
104*4bdc9457SAndroid Build Coastguard Worker }
105*4bdc9457SAndroid Build Coastguard Worker
106*4bdc9457SAndroid Build Coastguard Worker if (channels == 0) {
107*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
108*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %zu channels: number of channels must be non-zero",
109*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), channels);
110*4bdc9457SAndroid Build Coastguard Worker goto error;
111*4bdc9457SAndroid Build Coastguard Worker }
112*4bdc9457SAndroid Build Coastguard Worker
113*4bdc9457SAndroid Build Coastguard Worker if (input_pixel_stride < channels) {
114*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
115*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with input pixel stride of %zu: "
116*4bdc9457SAndroid Build Coastguard Worker "stride must be at least as large as the number of channels (%zu)",
117*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), input_pixel_stride, channels);
118*4bdc9457SAndroid Build Coastguard Worker goto error;
119*4bdc9457SAndroid Build Coastguard Worker }
120*4bdc9457SAndroid Build Coastguard Worker
121*4bdc9457SAndroid Build Coastguard Worker if (output_pixel_stride < channels) {
122*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
123*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with output pixel stride of %zu: "
124*4bdc9457SAndroid Build Coastguard Worker "stride must be at least as large as the number of channels (%zu)",
125*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), output_pixel_stride, channels);
126*4bdc9457SAndroid Build Coastguard Worker goto error;
127*4bdc9457SAndroid Build Coastguard Worker }
128*4bdc9457SAndroid Build Coastguard Worker
129*4bdc9457SAndroid Build Coastguard Worker if (input_scale <= 0.0f || !isnormal(input_scale)) {
130*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
131*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %.7g input scale: scale must be finite, normalized, and positive",
132*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), input_scale);
133*4bdc9457SAndroid Build Coastguard Worker goto error;
134*4bdc9457SAndroid Build Coastguard Worker }
135*4bdc9457SAndroid Build Coastguard Worker
136*4bdc9457SAndroid Build Coastguard Worker if (output_scale <= 0.0f || !isnormal(output_scale)) {
137*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
138*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %.7g output scale: scale must be finite, normalized, and positive",
139*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), output_scale);
140*4bdc9457SAndroid Build Coastguard Worker goto error;
141*4bdc9457SAndroid Build Coastguard Worker }
142*4bdc9457SAndroid Build Coastguard Worker
143*4bdc9457SAndroid Build Coastguard Worker if (output_min >= output_max) {
144*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
145*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with [%" PRIu8 ", %" PRIu8 "] output range: range min must be below range max",
146*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8), output_min, output_max);
147*4bdc9457SAndroid Build Coastguard Worker goto error;
148*4bdc9457SAndroid Build Coastguard Worker }
149*4bdc9457SAndroid Build Coastguard Worker
150*4bdc9457SAndroid Build Coastguard Worker const bool any_padding = (input_padding_left | input_padding_top | input_padding_right | input_padding_bottom) != 0;
151*4bdc9457SAndroid Build Coastguard Worker if ((flags & XNN_FLAG_TENSORFLOW_SAME_PADDING) != 0) {
152*4bdc9457SAndroid Build Coastguard Worker if (any_padding) {
153*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
154*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %" PRIu32 "+%" PRIu32 "x%" PRIu32 "+%" PRIu32" padding: "
155*4bdc9457SAndroid Build Coastguard Worker "TensorFlow SAME padding can't be combined with explicit padding specification",
156*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8),
157*4bdc9457SAndroid Build Coastguard Worker input_padding_top, input_padding_left, input_padding_bottom, input_padding_right);
158*4bdc9457SAndroid Build Coastguard Worker goto error;
159*4bdc9457SAndroid Build Coastguard Worker }
160*4bdc9457SAndroid Build Coastguard Worker }
161*4bdc9457SAndroid Build Coastguard Worker
162*4bdc9457SAndroid Build Coastguard Worker status = xnn_status_unsupported_parameter;
163*4bdc9457SAndroid Build Coastguard Worker
164*4bdc9457SAndroid Build Coastguard Worker const float input_output_scale = input_scale / output_scale;
165*4bdc9457SAndroid Build Coastguard Worker if (input_output_scale < 0x1.0p-8f || input_output_scale >= 0x1.0p+8f) {
166*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
167*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %.7g input scale and %.7g output scale: "
168*4bdc9457SAndroid Build Coastguard Worker "input-to-output scale ratio (%.7f) must be in [2**-8, 2**8) range",
169*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8),
170*4bdc9457SAndroid Build Coastguard Worker input_scale, output_scale, input_output_scale);
171*4bdc9457SAndroid Build Coastguard Worker goto error;
172*4bdc9457SAndroid Build Coastguard Worker }
173*4bdc9457SAndroid Build Coastguard Worker
174*4bdc9457SAndroid Build Coastguard Worker if (pooling_size >= 16777216) {
175*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
176*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %"PRIu32" (%" PRIu32 "x%" PRIu32 ") pooling elements: "
177*4bdc9457SAndroid Build Coastguard Worker "the number of elements in the pooling area must be below 2**24",
178*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8),
179*4bdc9457SAndroid Build Coastguard Worker pooling_size, pooling_width, pooling_height);
180*4bdc9457SAndroid Build Coastguard Worker goto error;
181*4bdc9457SAndroid Build Coastguard Worker }
182*4bdc9457SAndroid Build Coastguard Worker
183*4bdc9457SAndroid Build Coastguard Worker status = xnn_status_out_of_memory;
184*4bdc9457SAndroid Build Coastguard Worker
185*4bdc9457SAndroid Build Coastguard Worker average_pooling_op = xnn_allocate_zero_simd_memory(sizeof(struct xnn_operator));
186*4bdc9457SAndroid Build Coastguard Worker if (average_pooling_op == NULL) {
187*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
188*4bdc9457SAndroid Build Coastguard Worker "failed to allocate %zu bytes for %s operator descriptor",
189*4bdc9457SAndroid Build Coastguard Worker sizeof(struct xnn_operator), xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8));
190*4bdc9457SAndroid Build Coastguard Worker goto error;
191*4bdc9457SAndroid Build Coastguard Worker }
192*4bdc9457SAndroid Build Coastguard Worker
193*4bdc9457SAndroid Build Coastguard Worker const size_t zero_bytes = channels * sizeof(uint8_t) + XNN_EXTRA_BYTES;
194*4bdc9457SAndroid Build Coastguard Worker void* zero_buffer = xnn_allocate_simd_memory(zero_bytes);
195*4bdc9457SAndroid Build Coastguard Worker if (zero_buffer == NULL) {
196*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
197*4bdc9457SAndroid Build Coastguard Worker "failed to allocate %zu bytes for %s operator zero padding",
198*4bdc9457SAndroid Build Coastguard Worker zero_bytes, xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8));
199*4bdc9457SAndroid Build Coastguard Worker goto error;
200*4bdc9457SAndroid Build Coastguard Worker }
201*4bdc9457SAndroid Build Coastguard Worker memset(zero_buffer, input_zero_point, channels * sizeof(uint8_t));
202*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->zero_buffer = zero_buffer;
203*4bdc9457SAndroid Build Coastguard Worker
204*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_top = input_padding_top;
205*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_right = input_padding_right;
206*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_bottom = input_padding_bottom;
207*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_left = input_padding_left;
208*4bdc9457SAndroid Build Coastguard Worker
209*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->kernel_height = pooling_height;
210*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->kernel_width = pooling_width;
211*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->stride_height = stride_height;
212*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->stride_width = stride_width;
213*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->dilation_height = 1;
214*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->dilation_width = 1;
215*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->channels = channels;
216*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->input_pixel_stride = input_pixel_stride;
217*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->output_pixel_stride = output_pixel_stride;
218*4bdc9457SAndroid Build Coastguard Worker
219*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->input_zero_point = (int32_t) (uint32_t) input_zero_point;
220*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->input_scale = input_scale;
221*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->output_scale = output_scale;
222*4bdc9457SAndroid Build Coastguard Worker
223*4bdc9457SAndroid Build Coastguard Worker // Number of rows read in the AVGPOOL micro-kernel.
224*4bdc9457SAndroid Build Coastguard Worker const size_t avgpool_nrows =
225*4bdc9457SAndroid Build Coastguard Worker round_up(doz(pooling_size, xnn_params.qu8.avgpool.primary_tile), xnn_params.qu8.avgpool.incremental_tile) + xnn_params.qu8.avgpool.primary_tile;
226*4bdc9457SAndroid Build Coastguard Worker const float requantization_scale = input_scale / (output_scale * (float) pooling_size);
227*4bdc9457SAndroid Build Coastguard Worker xnn_params.qu8.avgpool.init.qu8(&average_pooling_op->params.qu8_avgpool,
228*4bdc9457SAndroid Build Coastguard Worker (int32_t) -((uint32_t) input_zero_point * (uint32_t) avgpool_nrows),
229*4bdc9457SAndroid Build Coastguard Worker requantization_scale, output_zero_point, output_min, output_max);
230*4bdc9457SAndroid Build Coastguard Worker xnn_params.qu8.gavgpool.init.qu8(&average_pooling_op->params.qu8_gavgpool,
231*4bdc9457SAndroid Build Coastguard Worker 0 /* bias */, requantization_scale, output_zero_point, output_min, output_max);
232*4bdc9457SAndroid Build Coastguard Worker
233*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->type = xnn_operator_type_average_pooling_nhwc_qu8;
234*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->ukernel.type = xnn_ukernel_type_average_pooling;
235*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->flags = flags;
236*4bdc9457SAndroid Build Coastguard Worker
237*4bdc9457SAndroid Build Coastguard Worker *average_pooling_op_out = average_pooling_op;
238*4bdc9457SAndroid Build Coastguard Worker return xnn_status_success;
239*4bdc9457SAndroid Build Coastguard Worker
240*4bdc9457SAndroid Build Coastguard Worker error:
241*4bdc9457SAndroid Build Coastguard Worker xnn_delete_operator(average_pooling_op);
242*4bdc9457SAndroid Build Coastguard Worker return status;
243*4bdc9457SAndroid Build Coastguard Worker }
244*4bdc9457SAndroid Build Coastguard Worker
xnn_create_average_pooling2d_nhwc_f16(uint32_t input_padding_top,uint32_t input_padding_right,uint32_t input_padding_bottom,uint32_t input_padding_left,uint32_t pooling_height,uint32_t pooling_width,uint32_t stride_height,uint32_t stride_width,size_t channels,size_t input_pixel_stride,size_t output_pixel_stride,float output_min,float output_max,uint32_t flags,xnn_operator_t * average_pooling_op_out)245*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_average_pooling2d_nhwc_f16(
246*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_top,
247*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_right,
248*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_bottom,
249*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_left,
250*4bdc9457SAndroid Build Coastguard Worker uint32_t pooling_height,
251*4bdc9457SAndroid Build Coastguard Worker uint32_t pooling_width,
252*4bdc9457SAndroid Build Coastguard Worker uint32_t stride_height,
253*4bdc9457SAndroid Build Coastguard Worker uint32_t stride_width,
254*4bdc9457SAndroid Build Coastguard Worker size_t channels,
255*4bdc9457SAndroid Build Coastguard Worker size_t input_pixel_stride,
256*4bdc9457SAndroid Build Coastguard Worker size_t output_pixel_stride,
257*4bdc9457SAndroid Build Coastguard Worker float output_min,
258*4bdc9457SAndroid Build Coastguard Worker float output_max,
259*4bdc9457SAndroid Build Coastguard Worker uint32_t flags,
260*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t* average_pooling_op_out)
261*4bdc9457SAndroid Build Coastguard Worker {
262*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t average_pooling_op = NULL;
263*4bdc9457SAndroid Build Coastguard Worker enum xnn_status status = xnn_status_uninitialized;
264*4bdc9457SAndroid Build Coastguard Worker
265*4bdc9457SAndroid Build Coastguard Worker if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
266*4bdc9457SAndroid Build Coastguard Worker xnn_log_error("failed to create %s operator: XNNPACK is not initialized",
267*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16));
268*4bdc9457SAndroid Build Coastguard Worker goto error;
269*4bdc9457SAndroid Build Coastguard Worker }
270*4bdc9457SAndroid Build Coastguard Worker
271*4bdc9457SAndroid Build Coastguard Worker status = xnn_status_unsupported_hardware;
272*4bdc9457SAndroid Build Coastguard Worker
273*4bdc9457SAndroid Build Coastguard Worker if ((xnn_params.init_flags & XNN_INIT_FLAG_F16) != XNN_INIT_FLAG_F16) {
274*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
275*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator: operations on data type are not supported",
276*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16));
277*4bdc9457SAndroid Build Coastguard Worker goto error;
278*4bdc9457SAndroid Build Coastguard Worker }
279*4bdc9457SAndroid Build Coastguard Worker
280*4bdc9457SAndroid Build Coastguard Worker status = xnn_status_invalid_parameter;
281*4bdc9457SAndroid Build Coastguard Worker
282*4bdc9457SAndroid Build Coastguard Worker const uint32_t pooling_size = pooling_height * pooling_width;
283*4bdc9457SAndroid Build Coastguard Worker if (pooling_size == 0) {
284*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
285*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %" PRIu32 "x%" PRIu32 " pooling size: "
286*4bdc9457SAndroid Build Coastguard Worker "pooling size dimensions must be non-zero",
287*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16), pooling_width, pooling_height);
288*4bdc9457SAndroid Build Coastguard Worker goto error;
289*4bdc9457SAndroid Build Coastguard Worker }
290*4bdc9457SAndroid Build Coastguard Worker
291*4bdc9457SAndroid Build Coastguard Worker if (pooling_size == 1) {
292*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
293*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with 1 pooling element: 1x1 pooling is meaningless",
294*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16));
295*4bdc9457SAndroid Build Coastguard Worker goto error;
296*4bdc9457SAndroid Build Coastguard Worker }
297*4bdc9457SAndroid Build Coastguard Worker
298*4bdc9457SAndroid Build Coastguard Worker if (stride_height == 0 || stride_width == 0) {
299*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
300*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %" PRIu32 "x%" PRIu32 " stride: stride dimensions must be non-zero",
301*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16), stride_width, stride_height);
302*4bdc9457SAndroid Build Coastguard Worker goto error;
303*4bdc9457SAndroid Build Coastguard Worker }
304*4bdc9457SAndroid Build Coastguard Worker
305*4bdc9457SAndroid Build Coastguard Worker if (stride_height > pooling_height) {
306*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
307*4bdc9457SAndroid Build Coastguard Worker "failed to define %s operator with %" PRIu32 " stride height: must be less than pooling height %" PRIu32,
308*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16), stride_height, pooling_height);
309*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
310*4bdc9457SAndroid Build Coastguard Worker }
311*4bdc9457SAndroid Build Coastguard Worker
312*4bdc9457SAndroid Build Coastguard Worker if (stride_width > pooling_width) {
313*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
314*4bdc9457SAndroid Build Coastguard Worker "failed to define %s operator with %" PRIu32 " stride width: must be less than pooling width %" PRIu32,
315*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16), stride_width, pooling_width);
316*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
317*4bdc9457SAndroid Build Coastguard Worker }
318*4bdc9457SAndroid Build Coastguard Worker
319*4bdc9457SAndroid Build Coastguard Worker if (channels == 0) {
320*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
321*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %zu channels: number of channels must be non-zero",
322*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16), channels);
323*4bdc9457SAndroid Build Coastguard Worker goto error;
324*4bdc9457SAndroid Build Coastguard Worker }
325*4bdc9457SAndroid Build Coastguard Worker
326*4bdc9457SAndroid Build Coastguard Worker if (input_pixel_stride < channels) {
327*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
328*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with input pixel stride of %zu: "
329*4bdc9457SAndroid Build Coastguard Worker "stride must be at least as large as the number of channels (%zu)",
330*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16), input_pixel_stride, channels);
331*4bdc9457SAndroid Build Coastguard Worker goto error;
332*4bdc9457SAndroid Build Coastguard Worker }
333*4bdc9457SAndroid Build Coastguard Worker
334*4bdc9457SAndroid Build Coastguard Worker if (output_pixel_stride < channels) {
335*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
336*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with output pixel stride of %zu: "
337*4bdc9457SAndroid Build Coastguard Worker "stride must be at least as large as the number of channels (%zu)",
338*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16), output_pixel_stride, channels);
339*4bdc9457SAndroid Build Coastguard Worker goto error;
340*4bdc9457SAndroid Build Coastguard Worker }
341*4bdc9457SAndroid Build Coastguard Worker
342*4bdc9457SAndroid Build Coastguard Worker if (isnan(output_min)) {
343*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
344*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with NaN output lower bound: lower bound must be non-NaN",
345*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16));
346*4bdc9457SAndroid Build Coastguard Worker goto error;
347*4bdc9457SAndroid Build Coastguard Worker }
348*4bdc9457SAndroid Build Coastguard Worker
349*4bdc9457SAndroid Build Coastguard Worker if (isnan(output_max)) {
350*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
351*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with NaN output upper bound: upper bound must be non-NaN",
352*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16));
353*4bdc9457SAndroid Build Coastguard Worker goto error;
354*4bdc9457SAndroid Build Coastguard Worker }
355*4bdc9457SAndroid Build Coastguard Worker
356*4bdc9457SAndroid Build Coastguard Worker const uint16_t fp16_output_min = fp16_ieee_from_fp32_value(output_min);
357*4bdc9457SAndroid Build Coastguard Worker const uint16_t fp16_output_max = fp16_ieee_from_fp32_value(output_max);
358*4bdc9457SAndroid Build Coastguard Worker const float rounded_output_min = fp16_ieee_to_fp32_value(fp16_output_min);
359*4bdc9457SAndroid Build Coastguard Worker const float rounded_output_max = fp16_ieee_to_fp32_value(fp16_output_max);
360*4bdc9457SAndroid Build Coastguard Worker if (rounded_output_min >= rounded_output_max) {
361*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
362*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with [%.7g, %.7g] output range: lower bound must be below upper bound",
363*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16), rounded_output_min, rounded_output_max);
364*4bdc9457SAndroid Build Coastguard Worker goto error;
365*4bdc9457SAndroid Build Coastguard Worker }
366*4bdc9457SAndroid Build Coastguard Worker
367*4bdc9457SAndroid Build Coastguard Worker const bool any_padding = (input_padding_left | input_padding_top | input_padding_right | input_padding_bottom) != 0;
368*4bdc9457SAndroid Build Coastguard Worker if ((flags & XNN_FLAG_TENSORFLOW_SAME_PADDING) != 0) {
369*4bdc9457SAndroid Build Coastguard Worker if (any_padding) {
370*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
371*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %" PRIu32 "+%" PRIu32 "x%" PRIu32 "+%" PRIu32" padding: "
372*4bdc9457SAndroid Build Coastguard Worker "TensorFlow SAME padding can't be combined with explicit padding specification",
373*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16),
374*4bdc9457SAndroid Build Coastguard Worker input_padding_top, input_padding_left, input_padding_bottom, input_padding_right);
375*4bdc9457SAndroid Build Coastguard Worker goto error;
376*4bdc9457SAndroid Build Coastguard Worker }
377*4bdc9457SAndroid Build Coastguard Worker }
378*4bdc9457SAndroid Build Coastguard Worker
379*4bdc9457SAndroid Build Coastguard Worker status = xnn_status_out_of_memory;
380*4bdc9457SAndroid Build Coastguard Worker
381*4bdc9457SAndroid Build Coastguard Worker average_pooling_op = xnn_allocate_zero_simd_memory(sizeof(struct xnn_operator));
382*4bdc9457SAndroid Build Coastguard Worker if (average_pooling_op == NULL) {
383*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
384*4bdc9457SAndroid Build Coastguard Worker "failed to allocate %zu bytes for %s operator descriptor",
385*4bdc9457SAndroid Build Coastguard Worker sizeof(struct xnn_operator), xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16));
386*4bdc9457SAndroid Build Coastguard Worker goto error;
387*4bdc9457SAndroid Build Coastguard Worker }
388*4bdc9457SAndroid Build Coastguard Worker
389*4bdc9457SAndroid Build Coastguard Worker const size_t zero_bytes = channels * sizeof(uint16_t) + XNN_EXTRA_BYTES;
390*4bdc9457SAndroid Build Coastguard Worker void* zero_buffer = xnn_allocate_zero_simd_memory(zero_bytes);
391*4bdc9457SAndroid Build Coastguard Worker if (zero_buffer == NULL) {
392*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
393*4bdc9457SAndroid Build Coastguard Worker "failed to allocate %zu bytes for %s operator zero padding",
394*4bdc9457SAndroid Build Coastguard Worker zero_bytes, xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16));
395*4bdc9457SAndroid Build Coastguard Worker goto error;
396*4bdc9457SAndroid Build Coastguard Worker }
397*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->zero_buffer = zero_buffer;
398*4bdc9457SAndroid Build Coastguard Worker
399*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_top = input_padding_top;
400*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_right = input_padding_right;
401*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_bottom = input_padding_bottom;
402*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_left = input_padding_left;
403*4bdc9457SAndroid Build Coastguard Worker
404*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->kernel_height = pooling_height;
405*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->kernel_width = pooling_width;
406*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->stride_height = stride_height;
407*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->stride_width = stride_width;
408*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->dilation_height = 1;
409*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->dilation_width = 1;
410*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->channels = channels;
411*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->input_pixel_stride = input_pixel_stride;
412*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->output_pixel_stride = output_pixel_stride;
413*4bdc9457SAndroid Build Coastguard Worker
414*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->type = xnn_operator_type_average_pooling_nhwc_f16;
415*4bdc9457SAndroid Build Coastguard Worker xnn_params.f16.avgpool.init.f16(&average_pooling_op->params.f16_scaleminmax,
416*4bdc9457SAndroid Build Coastguard Worker fp16_ieee_from_fp32_value(1.0f / (float) (int32_t) pooling_size), fp16_output_min, fp16_output_max);
417*4bdc9457SAndroid Build Coastguard Worker const bool tf_same_padding = (flags & XNN_FLAG_TENSORFLOW_SAME_PADDING) != 0;
418*4bdc9457SAndroid Build Coastguard Worker if (any_padding || tf_same_padding) {
419*4bdc9457SAndroid Build Coastguard Worker xnn_params.f16.pavgpool.init.f16(&average_pooling_op->params.f16_minmax, fp16_output_min, fp16_output_max);
420*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->ukernel.type = xnn_ukernel_type_pixelwise_average_pooling;
421*4bdc9457SAndroid Build Coastguard Worker } else {
422*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->ukernel.type = xnn_ukernel_type_average_pooling;
423*4bdc9457SAndroid Build Coastguard Worker }
424*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->flags = flags;
425*4bdc9457SAndroid Build Coastguard Worker
426*4bdc9457SAndroid Build Coastguard Worker *average_pooling_op_out = average_pooling_op;
427*4bdc9457SAndroid Build Coastguard Worker return xnn_status_success;
428*4bdc9457SAndroid Build Coastguard Worker
429*4bdc9457SAndroid Build Coastguard Worker error:
430*4bdc9457SAndroid Build Coastguard Worker xnn_delete_operator(average_pooling_op);
431*4bdc9457SAndroid Build Coastguard Worker return status;
432*4bdc9457SAndroid Build Coastguard Worker }
433*4bdc9457SAndroid Build Coastguard Worker
xnn_create_average_pooling2d_nhwc_f32(uint32_t input_padding_top,uint32_t input_padding_right,uint32_t input_padding_bottom,uint32_t input_padding_left,uint32_t pooling_height,uint32_t pooling_width,uint32_t stride_height,uint32_t stride_width,size_t channels,size_t input_pixel_stride,size_t output_pixel_stride,float output_min,float output_max,uint32_t flags,xnn_operator_t * average_pooling_op_out)434*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_create_average_pooling2d_nhwc_f32(
435*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_top,
436*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_right,
437*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_bottom,
438*4bdc9457SAndroid Build Coastguard Worker uint32_t input_padding_left,
439*4bdc9457SAndroid Build Coastguard Worker uint32_t pooling_height,
440*4bdc9457SAndroid Build Coastguard Worker uint32_t pooling_width,
441*4bdc9457SAndroid Build Coastguard Worker uint32_t stride_height,
442*4bdc9457SAndroid Build Coastguard Worker uint32_t stride_width,
443*4bdc9457SAndroid Build Coastguard Worker size_t channels,
444*4bdc9457SAndroid Build Coastguard Worker size_t input_pixel_stride,
445*4bdc9457SAndroid Build Coastguard Worker size_t output_pixel_stride,
446*4bdc9457SAndroid Build Coastguard Worker float output_min,
447*4bdc9457SAndroid Build Coastguard Worker float output_max,
448*4bdc9457SAndroid Build Coastguard Worker uint32_t flags,
449*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t* average_pooling_op_out)
450*4bdc9457SAndroid Build Coastguard Worker {
451*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t average_pooling_op = NULL;
452*4bdc9457SAndroid Build Coastguard Worker enum xnn_status status = xnn_status_uninitialized;
453*4bdc9457SAndroid Build Coastguard Worker
454*4bdc9457SAndroid Build Coastguard Worker if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
455*4bdc9457SAndroid Build Coastguard Worker xnn_log_error("failed to create %s operator: XNNPACK is not initialized",
456*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32));
457*4bdc9457SAndroid Build Coastguard Worker goto error;
458*4bdc9457SAndroid Build Coastguard Worker }
459*4bdc9457SAndroid Build Coastguard Worker
460*4bdc9457SAndroid Build Coastguard Worker status = xnn_status_invalid_parameter;
461*4bdc9457SAndroid Build Coastguard Worker
462*4bdc9457SAndroid Build Coastguard Worker const uint32_t pooling_size = pooling_height * pooling_width;
463*4bdc9457SAndroid Build Coastguard Worker if (pooling_size == 0) {
464*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
465*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %" PRIu32 "x%" PRIu32 " pooling size: "
466*4bdc9457SAndroid Build Coastguard Worker "pooling size dimensions must be non-zero",
467*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32), pooling_width, pooling_height);
468*4bdc9457SAndroid Build Coastguard Worker goto error;
469*4bdc9457SAndroid Build Coastguard Worker }
470*4bdc9457SAndroid Build Coastguard Worker
471*4bdc9457SAndroid Build Coastguard Worker if (pooling_size == 1) {
472*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
473*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with 1 pooling element: 1x1 pooling is meaningless",
474*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32));
475*4bdc9457SAndroid Build Coastguard Worker goto error;
476*4bdc9457SAndroid Build Coastguard Worker }
477*4bdc9457SAndroid Build Coastguard Worker
478*4bdc9457SAndroid Build Coastguard Worker if (stride_height == 0 || stride_width == 0) {
479*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
480*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %" PRIu32 "x%" PRIu32 " stride: stride dimensions must be non-zero",
481*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32), stride_width, stride_height);
482*4bdc9457SAndroid Build Coastguard Worker goto error;
483*4bdc9457SAndroid Build Coastguard Worker }
484*4bdc9457SAndroid Build Coastguard Worker
485*4bdc9457SAndroid Build Coastguard Worker if (stride_height > pooling_height) {
486*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
487*4bdc9457SAndroid Build Coastguard Worker "failed to define %s operator with %" PRIu32 " stride height: must be less than pooling height %" PRIu32,
488*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32), stride_height, pooling_height);
489*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
490*4bdc9457SAndroid Build Coastguard Worker }
491*4bdc9457SAndroid Build Coastguard Worker
492*4bdc9457SAndroid Build Coastguard Worker if (stride_width > pooling_width) {
493*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
494*4bdc9457SAndroid Build Coastguard Worker "failed to define %s operator with %" PRIu32 " stride width: must be less than pooling width %" PRIu32,
495*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32), stride_width, pooling_width);
496*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
497*4bdc9457SAndroid Build Coastguard Worker }
498*4bdc9457SAndroid Build Coastguard Worker
499*4bdc9457SAndroid Build Coastguard Worker if (channels == 0) {
500*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
501*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %zu channels: number of channels must be non-zero",
502*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32), channels);
503*4bdc9457SAndroid Build Coastguard Worker goto error;
504*4bdc9457SAndroid Build Coastguard Worker }
505*4bdc9457SAndroid Build Coastguard Worker
506*4bdc9457SAndroid Build Coastguard Worker if (input_pixel_stride < channels) {
507*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
508*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with input pixel stride of %zu: "
509*4bdc9457SAndroid Build Coastguard Worker "stride must be at least as large as the number of channels (%zu)",
510*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32), input_pixel_stride, channels);
511*4bdc9457SAndroid Build Coastguard Worker goto error;
512*4bdc9457SAndroid Build Coastguard Worker }
513*4bdc9457SAndroid Build Coastguard Worker
514*4bdc9457SAndroid Build Coastguard Worker if (output_pixel_stride < channels) {
515*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
516*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with output pixel stride of %zu: "
517*4bdc9457SAndroid Build Coastguard Worker "stride must be at least as large as the number of channels (%zu)",
518*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32), output_pixel_stride, channels);
519*4bdc9457SAndroid Build Coastguard Worker goto error;
520*4bdc9457SAndroid Build Coastguard Worker }
521*4bdc9457SAndroid Build Coastguard Worker
522*4bdc9457SAndroid Build Coastguard Worker if (isnan(output_min)) {
523*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
524*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with NaN output lower bound: lower bound must be non-NaN",
525*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32));
526*4bdc9457SAndroid Build Coastguard Worker goto error;
527*4bdc9457SAndroid Build Coastguard Worker }
528*4bdc9457SAndroid Build Coastguard Worker
529*4bdc9457SAndroid Build Coastguard Worker if (isnan(output_max)) {
530*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
531*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with NaN output upper bound: upper bound must be non-NaN",
532*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32));
533*4bdc9457SAndroid Build Coastguard Worker goto error;
534*4bdc9457SAndroid Build Coastguard Worker }
535*4bdc9457SAndroid Build Coastguard Worker
536*4bdc9457SAndroid Build Coastguard Worker if (output_min >= output_max) {
537*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
538*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with [%.7g, %.7g] output range: lower bound must be below upper bound",
539*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32), output_min, output_max);
540*4bdc9457SAndroid Build Coastguard Worker goto error;
541*4bdc9457SAndroid Build Coastguard Worker }
542*4bdc9457SAndroid Build Coastguard Worker
543*4bdc9457SAndroid Build Coastguard Worker const bool any_padding = (input_padding_left | input_padding_top | input_padding_right | input_padding_bottom) != 0;
544*4bdc9457SAndroid Build Coastguard Worker if ((flags & XNN_FLAG_TENSORFLOW_SAME_PADDING) != 0) {
545*4bdc9457SAndroid Build Coastguard Worker if (any_padding) {
546*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
547*4bdc9457SAndroid Build Coastguard Worker "failed to create %s operator with %" PRIu32 "+%" PRIu32 "x%" PRIu32 "+%" PRIu32" padding: "
548*4bdc9457SAndroid Build Coastguard Worker "TensorFlow SAME padding can't be combined with explicit padding specification",
549*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32),
550*4bdc9457SAndroid Build Coastguard Worker input_padding_top, input_padding_left, input_padding_bottom, input_padding_right);
551*4bdc9457SAndroid Build Coastguard Worker goto error;
552*4bdc9457SAndroid Build Coastguard Worker }
553*4bdc9457SAndroid Build Coastguard Worker }
554*4bdc9457SAndroid Build Coastguard Worker
555*4bdc9457SAndroid Build Coastguard Worker status = xnn_status_out_of_memory;
556*4bdc9457SAndroid Build Coastguard Worker
557*4bdc9457SAndroid Build Coastguard Worker average_pooling_op = xnn_allocate_zero_simd_memory(sizeof(struct xnn_operator));
558*4bdc9457SAndroid Build Coastguard Worker if (average_pooling_op == NULL) {
559*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
560*4bdc9457SAndroid Build Coastguard Worker "failed to allocate %zu bytes for %s operator descriptor",
561*4bdc9457SAndroid Build Coastguard Worker sizeof(struct xnn_operator), xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32));
562*4bdc9457SAndroid Build Coastguard Worker goto error;
563*4bdc9457SAndroid Build Coastguard Worker }
564*4bdc9457SAndroid Build Coastguard Worker
565*4bdc9457SAndroid Build Coastguard Worker const size_t zero_bytes = channels * sizeof(float) + XNN_EXTRA_BYTES;
566*4bdc9457SAndroid Build Coastguard Worker void* zero_buffer = xnn_allocate_zero_simd_memory(zero_bytes);
567*4bdc9457SAndroid Build Coastguard Worker if (zero_buffer == NULL) {
568*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
569*4bdc9457SAndroid Build Coastguard Worker "failed to allocate %zu bytes for %s operator zero padding",
570*4bdc9457SAndroid Build Coastguard Worker zero_bytes, xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32));
571*4bdc9457SAndroid Build Coastguard Worker goto error;
572*4bdc9457SAndroid Build Coastguard Worker }
573*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->zero_buffer = zero_buffer;
574*4bdc9457SAndroid Build Coastguard Worker
575*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_top = input_padding_top;
576*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_right = input_padding_right;
577*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_bottom = input_padding_bottom;
578*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_left = input_padding_left;
579*4bdc9457SAndroid Build Coastguard Worker
580*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->kernel_height = pooling_height;
581*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->kernel_width = pooling_width;
582*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->stride_height = stride_height;
583*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->stride_width = stride_width;
584*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->dilation_height = 1;
585*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->dilation_width = 1;
586*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->channels = channels;
587*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->input_pixel_stride = input_pixel_stride;
588*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->output_pixel_stride = output_pixel_stride;
589*4bdc9457SAndroid Build Coastguard Worker
590*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->type = xnn_operator_type_average_pooling_nhwc_f32;
591*4bdc9457SAndroid Build Coastguard Worker xnn_params.f32.avgpool.init.f32(&average_pooling_op->params.f32_scaleminmax,
592*4bdc9457SAndroid Build Coastguard Worker 1.0f / (float) (int32_t) pooling_size, output_min, output_max);
593*4bdc9457SAndroid Build Coastguard Worker const bool tf_same_padding = (flags & XNN_FLAG_TENSORFLOW_SAME_PADDING) != 0;
594*4bdc9457SAndroid Build Coastguard Worker if (any_padding || tf_same_padding) {
595*4bdc9457SAndroid Build Coastguard Worker xnn_params.f32.pavgpool.init.f32(&average_pooling_op->params.f32_minmax, output_min, output_max);
596*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->ukernel.type = xnn_ukernel_type_pixelwise_average_pooling;
597*4bdc9457SAndroid Build Coastguard Worker } else {
598*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->ukernel.type = xnn_ukernel_type_average_pooling;
599*4bdc9457SAndroid Build Coastguard Worker }
600*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->flags = flags;
601*4bdc9457SAndroid Build Coastguard Worker
602*4bdc9457SAndroid Build Coastguard Worker *average_pooling_op_out = average_pooling_op;
603*4bdc9457SAndroid Build Coastguard Worker return xnn_status_success;
604*4bdc9457SAndroid Build Coastguard Worker
605*4bdc9457SAndroid Build Coastguard Worker error:
606*4bdc9457SAndroid Build Coastguard Worker xnn_delete_operator(average_pooling_op);
607*4bdc9457SAndroid Build Coastguard Worker return status;
608*4bdc9457SAndroid Build Coastguard Worker }
609*4bdc9457SAndroid Build Coastguard Worker
setup_average_pooling2d(xnn_operator_t average_pooling_op,size_t batch_size,size_t input_height,size_t input_width,const void * input,void * output,uint32_t log2_data_element_size,uint32_t log2_weight_element_size,xnn_indirection_init_pavgpool2d_fn indirection_init_pavgpool2d,struct avgpool_parameters avgpool[restrict XNN_MIN_ELEMENTS (1)],struct pavgpool_parameters pavgpool[restrict1],struct gavgpool_parameters gavgpool[restrict XNN_MIN_ELEMENTS (1)],const void * params,size_t params_size,const void * global_params,size_t global_params_size,size_t num_threads,bool is_pixelwise)610*4bdc9457SAndroid Build Coastguard Worker static enum xnn_status setup_average_pooling2d(
611*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t average_pooling_op,
612*4bdc9457SAndroid Build Coastguard Worker size_t batch_size,
613*4bdc9457SAndroid Build Coastguard Worker size_t input_height,
614*4bdc9457SAndroid Build Coastguard Worker size_t input_width,
615*4bdc9457SAndroid Build Coastguard Worker const void* input,
616*4bdc9457SAndroid Build Coastguard Worker void* output,
617*4bdc9457SAndroid Build Coastguard Worker uint32_t log2_data_element_size,
618*4bdc9457SAndroid Build Coastguard Worker uint32_t log2_weight_element_size,
619*4bdc9457SAndroid Build Coastguard Worker xnn_indirection_init_pavgpool2d_fn indirection_init_pavgpool2d,
620*4bdc9457SAndroid Build Coastguard Worker struct avgpool_parameters avgpool[restrict XNN_MIN_ELEMENTS(1)],
621*4bdc9457SAndroid Build Coastguard Worker struct pavgpool_parameters pavgpool[restrict 1],
622*4bdc9457SAndroid Build Coastguard Worker struct gavgpool_parameters gavgpool[restrict XNN_MIN_ELEMENTS(1)],
623*4bdc9457SAndroid Build Coastguard Worker const void* params,
624*4bdc9457SAndroid Build Coastguard Worker size_t params_size,
625*4bdc9457SAndroid Build Coastguard Worker const void* global_params,
626*4bdc9457SAndroid Build Coastguard Worker size_t global_params_size,
627*4bdc9457SAndroid Build Coastguard Worker size_t num_threads,
628*4bdc9457SAndroid Build Coastguard Worker bool is_pixelwise)
629*4bdc9457SAndroid Build Coastguard Worker {
630*4bdc9457SAndroid Build Coastguard Worker assert(!is_pixelwise || pavgpool != NULL && indirection_init_pavgpool2d != NULL);
631*4bdc9457SAndroid Build Coastguard Worker
632*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->state = xnn_run_state_invalid;
633*4bdc9457SAndroid Build Coastguard Worker
634*4bdc9457SAndroid Build Coastguard Worker if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
635*4bdc9457SAndroid Build Coastguard Worker xnn_log_error("failed to setup %s operator: XNNPACK is not initialized",
636*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(average_pooling_op->type));
637*4bdc9457SAndroid Build Coastguard Worker return xnn_status_uninitialized;
638*4bdc9457SAndroid Build Coastguard Worker }
639*4bdc9457SAndroid Build Coastguard Worker
640*4bdc9457SAndroid Build Coastguard Worker if (input_width == 0 || input_height == 0) {
641*4bdc9457SAndroid Build Coastguard Worker xnn_log_error(
642*4bdc9457SAndroid Build Coastguard Worker "failed to setup %s operator with %zux%zu input: input dimensions must be non-zero",
643*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(average_pooling_op->type), input_width, input_height);
644*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
645*4bdc9457SAndroid Build Coastguard Worker }
646*4bdc9457SAndroid Build Coastguard Worker
647*4bdc9457SAndroid Build Coastguard Worker if (batch_size == 0) {
648*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->state = xnn_run_state_skip;
649*4bdc9457SAndroid Build Coastguard Worker return xnn_status_success;
650*4bdc9457SAndroid Build Coastguard Worker }
651*4bdc9457SAndroid Build Coastguard Worker
652*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->input_height = input_height;
653*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->input_width = input_width;
654*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->input = input;
655*4bdc9457SAndroid Build Coastguard Worker
656*4bdc9457SAndroid Build Coastguard Worker const bool tf_same_padding = (average_pooling_op->flags & XNN_FLAG_TENSORFLOW_SAME_PADDING) != 0;
657*4bdc9457SAndroid Build Coastguard Worker if (tf_same_padding) {
658*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->output_height = compute_output_dimension_with_tf_same_padding(
659*4bdc9457SAndroid Build Coastguard Worker input_height, average_pooling_op->stride_height);
660*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->output_width = compute_output_dimension_with_tf_same_padding(
661*4bdc9457SAndroid Build Coastguard Worker input_width, average_pooling_op->stride_width);
662*4bdc9457SAndroid Build Coastguard Worker
663*4bdc9457SAndroid Build Coastguard Worker const uint32_t kernel_height = average_pooling_op->kernel_height;
664*4bdc9457SAndroid Build Coastguard Worker const uint32_t kernel_width = average_pooling_op->kernel_width;
665*4bdc9457SAndroid Build Coastguard Worker const uint32_t total_padding_height =
666*4bdc9457SAndroid Build Coastguard Worker (average_pooling_op->output_height - 1) * average_pooling_op->stride_height + kernel_height - input_height;
667*4bdc9457SAndroid Build Coastguard Worker const uint32_t total_padding_width =
668*4bdc9457SAndroid Build Coastguard Worker (average_pooling_op->output_width - 1) * average_pooling_op->stride_width + kernel_width - input_width;
669*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_top = total_padding_height / 2;
670*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_left = total_padding_width / 2;
671*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_bottom = total_padding_height - average_pooling_op->padding_top;
672*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_right = total_padding_width - average_pooling_op->padding_left;
673*4bdc9457SAndroid Build Coastguard Worker } else {
674*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->output_height = xnn_compute_convolution_output_dimension(
675*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_top + input_height + average_pooling_op->padding_bottom,
676*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->kernel_height,
677*4bdc9457SAndroid Build Coastguard Worker 1,
678*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->stride_height);
679*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->output_width = xnn_compute_convolution_output_dimension(
680*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_left + input_width + average_pooling_op->padding_right,
681*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->kernel_width,
682*4bdc9457SAndroid Build Coastguard Worker 1,
683*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->stride_width);
684*4bdc9457SAndroid Build Coastguard Worker }
685*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->output = output;
686*4bdc9457SAndroid Build Coastguard Worker
687*4bdc9457SAndroid Build Coastguard Worker const size_t output_height = average_pooling_op->output_height;
688*4bdc9457SAndroid Build Coastguard Worker const size_t output_width = average_pooling_op->output_width;
689*4bdc9457SAndroid Build Coastguard Worker const size_t padded_input_width = average_pooling_op->padding_left + input_width + average_pooling_op->padding_right;
690*4bdc9457SAndroid Build Coastguard Worker const size_t padded_input_height = average_pooling_op->padding_top + input_height + average_pooling_op->padding_bottom;
691*4bdc9457SAndroid Build Coastguard Worker if (padded_input_width == average_pooling_op->kernel_width && padded_input_height == average_pooling_op->kernel_height) {
692*4bdc9457SAndroid Build Coastguard Worker // Global average pooling
693*4bdc9457SAndroid Build Coastguard Worker const size_t input_elements = input_height * input_width;
694*4bdc9457SAndroid Build Coastguard Worker const size_t input_stride_in_bytes = average_pooling_op->input_pixel_stride << log2_data_element_size;
695*4bdc9457SAndroid Build Coastguard Worker const size_t channels = average_pooling_op->channels;
696*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->context.global_average_pooling_nwc = (struct global_average_pooling_nwc_context) {
697*4bdc9457SAndroid Build Coastguard Worker .input = input,
698*4bdc9457SAndroid Build Coastguard Worker .zero = average_pooling_op->zero_buffer,
699*4bdc9457SAndroid Build Coastguard Worker .input_pixel_stride = input_stride_in_bytes,
700*4bdc9457SAndroid Build Coastguard Worker .input_batch_stride = input_stride_in_bytes * input_elements,
701*4bdc9457SAndroid Build Coastguard Worker .input_elements = input_elements,
702*4bdc9457SAndroid Build Coastguard Worker .channels = channels,
703*4bdc9457SAndroid Build Coastguard Worker .output = output,
704*4bdc9457SAndroid Build Coastguard Worker .output_batch_stride = average_pooling_op->output_pixel_stride << log2_data_element_size,
705*4bdc9457SAndroid Build Coastguard Worker };
706*4bdc9457SAndroid Build Coastguard Worker memcpy(&average_pooling_op->context.global_average_pooling_nwc.params, global_params, global_params_size);
707*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.type = xnn_parallelization_type_1d;
708*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.range[0] = batch_size;
709*4bdc9457SAndroid Build Coastguard Worker
710*4bdc9457SAndroid Build Coastguard Worker if (input_elements <= gavgpool->row_tile) {
711*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.task_1d = (pthreadpool_task_1d_t) xnn_compute_global_average_pooling_nwc_unipass;
712*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->context.global_average_pooling_nwc.unipass_ukernel = gavgpool->unipass;
713*4bdc9457SAndroid Build Coastguard Worker } else {
714*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.task_1d = (pthreadpool_task_1d_t) xnn_compute_global_average_pooling_nwc_multipass;
715*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->context.global_average_pooling_nwc.multipass_ukernel = gavgpool->multipass;
716*4bdc9457SAndroid Build Coastguard Worker }
717*4bdc9457SAndroid Build Coastguard Worker } else {
718*4bdc9457SAndroid Build Coastguard Worker // Non-global average pooling
719*4bdc9457SAndroid Build Coastguard Worker const size_t pooling_height = average_pooling_op->kernel_height;
720*4bdc9457SAndroid Build Coastguard Worker const size_t pooling_width = average_pooling_op->kernel_width;
721*4bdc9457SAndroid Build Coastguard Worker const size_t pooling_size = pooling_height * pooling_width;
722*4bdc9457SAndroid Build Coastguard Worker
723*4bdc9457SAndroid Build Coastguard Worker const uint32_t primary_tile = is_pixelwise ? pavgpool->primary_tile : avgpool->primary_tile;
724*4bdc9457SAndroid Build Coastguard Worker
725*4bdc9457SAndroid Build Coastguard Worker const size_t step_width = min(average_pooling_op->stride_width, pooling_width);
726*4bdc9457SAndroid Build Coastguard Worker const size_t step_height = pooling_size + (output_width - 1) * step_width * pooling_height;
727*4bdc9457SAndroid Build Coastguard Worker
728*4bdc9457SAndroid Build Coastguard Worker const size_t last_input_height = average_pooling_op->last_input_height;
729*4bdc9457SAndroid Build Coastguard Worker const size_t last_input_width = average_pooling_op->last_input_width;
730*4bdc9457SAndroid Build Coastguard Worker if (input_height != last_input_height || input_width != last_input_width) {
731*4bdc9457SAndroid Build Coastguard Worker // Micro-kernel may read up to (primary_tile - 1) elements after the end of indirection buffer.
732*4bdc9457SAndroid Build Coastguard Worker const size_t indirection_buffer_size = sizeof(void*) * ((primary_tile - 1) + output_height * step_height);
733*4bdc9457SAndroid Build Coastguard Worker
734*4bdc9457SAndroid Build Coastguard Worker const void** indirection_buffer =
735*4bdc9457SAndroid Build Coastguard Worker (const void**) xnn_reallocate_memory(average_pooling_op->indirection_buffer, indirection_buffer_size);
736*4bdc9457SAndroid Build Coastguard Worker if (indirection_buffer == NULL) {
737*4bdc9457SAndroid Build Coastguard Worker xnn_log_error("failed to allocate %zu bytes for %s operator indirection buffer",
738*4bdc9457SAndroid Build Coastguard Worker indirection_buffer_size, xnn_operator_type_to_string(average_pooling_op->type));
739*4bdc9457SAndroid Build Coastguard Worker return xnn_status_out_of_memory;
740*4bdc9457SAndroid Build Coastguard Worker }
741*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->indirection_buffer = indirection_buffer;
742*4bdc9457SAndroid Build Coastguard Worker
743*4bdc9457SAndroid Build Coastguard Worker xnn_indirection_init_dwconv2d(average_pooling_op, step_height, step_width, primary_tile, log2_data_element_size);
744*4bdc9457SAndroid Build Coastguard Worker
745*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->last_input = input;
746*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->last_input_height = input_height;
747*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->last_input_width = input_width;
748*4bdc9457SAndroid Build Coastguard Worker }
749*4bdc9457SAndroid Build Coastguard Worker
750*4bdc9457SAndroid Build Coastguard Worker const size_t channels = average_pooling_op->channels;
751*4bdc9457SAndroid Build Coastguard Worker
752*4bdc9457SAndroid Build Coastguard Worker const size_t indirect_input_height_stride = step_height * sizeof(void*);
753*4bdc9457SAndroid Build Coastguard Worker const size_t output_width_stride = average_pooling_op->output_pixel_stride << log2_data_element_size;
754*4bdc9457SAndroid Build Coastguard Worker const size_t output_height_stride = output_width * output_width_stride;
755*4bdc9457SAndroid Build Coastguard Worker
756*4bdc9457SAndroid Build Coastguard Worker if (is_pixelwise) {
757*4bdc9457SAndroid Build Coastguard Worker assert(indirection_init_pavgpool2d != NULL);
758*4bdc9457SAndroid Build Coastguard Worker
759*4bdc9457SAndroid Build Coastguard Worker if (input_height != last_input_height || input_width != last_input_width) {
760*4bdc9457SAndroid Build Coastguard Worker const size_t pixelwise_buffer_size = (output_height * output_width) << log2_weight_element_size;
761*4bdc9457SAndroid Build Coastguard Worker void* pixelwise_buffer = xnn_reallocate_memory(average_pooling_op->pixelwise_buffer, pixelwise_buffer_size);
762*4bdc9457SAndroid Build Coastguard Worker if (pixelwise_buffer == NULL) {
763*4bdc9457SAndroid Build Coastguard Worker xnn_log_error("failed to allocate %zu bytes for %s operator pixelwise buffer",
764*4bdc9457SAndroid Build Coastguard Worker pixelwise_buffer_size, xnn_operator_type_to_string(average_pooling_op->type));
765*4bdc9457SAndroid Build Coastguard Worker return xnn_status_out_of_memory;
766*4bdc9457SAndroid Build Coastguard Worker }
767*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->pixelwise_buffer = pixelwise_buffer;
768*4bdc9457SAndroid Build Coastguard Worker
769*4bdc9457SAndroid Build Coastguard Worker indirection_init_pavgpool2d(
770*4bdc9457SAndroid Build Coastguard Worker input_height, input_width,
771*4bdc9457SAndroid Build Coastguard Worker output_height, output_width,
772*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->kernel_height, average_pooling_op->kernel_width,
773*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->stride_height, average_pooling_op->stride_width,
774*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->padding_top, average_pooling_op->padding_left,
775*4bdc9457SAndroid Build Coastguard Worker pixelwise_buffer);
776*4bdc9457SAndroid Build Coastguard Worker }
777*4bdc9457SAndroid Build Coastguard Worker
778*4bdc9457SAndroid Build Coastguard Worker const uint32_t incremental_tile = pavgpool->incremental_tile;
779*4bdc9457SAndroid Build Coastguard Worker const size_t multipass_adjustment =
780*4bdc9457SAndroid Build Coastguard Worker pooling_size > primary_tile ? round_up(pooling_size - primary_tile, incremental_tile) + primary_tile - incremental_tile : 0;
781*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->context.pixelwise_average_pooling = (struct pixelwise_average_pooling_context) {
782*4bdc9457SAndroid Build Coastguard Worker .indirect_input = average_pooling_op->indirection_buffer,
783*4bdc9457SAndroid Build Coastguard Worker .indirect_input_height_stride = indirect_input_height_stride,
784*4bdc9457SAndroid Build Coastguard Worker .input_batch_stride = input_height * input_width * average_pooling_op->input_pixel_stride << log2_data_element_size,
785*4bdc9457SAndroid Build Coastguard Worker .input_offset = (size_t) ((uintptr_t) input - (uintptr_t) average_pooling_op->last_input),
786*4bdc9457SAndroid Build Coastguard Worker .pixelwise_buffer = average_pooling_op->pixelwise_buffer,
787*4bdc9457SAndroid Build Coastguard Worker .pixelwise_buffer_height_stride = output_width << log2_data_element_size,
788*4bdc9457SAndroid Build Coastguard Worker .output = output,
789*4bdc9457SAndroid Build Coastguard Worker .output_batch_stride = output_height * output_height_stride,
790*4bdc9457SAndroid Build Coastguard Worker .output_height_stride = output_height_stride,
791*4bdc9457SAndroid Build Coastguard Worker .output_width = output_width,
792*4bdc9457SAndroid Build Coastguard Worker .pooling_size = pooling_size,
793*4bdc9457SAndroid Build Coastguard Worker .channels = channels,
794*4bdc9457SAndroid Build Coastguard Worker .zero = average_pooling_op->zero_buffer,
795*4bdc9457SAndroid Build Coastguard Worker .input_increment = (pooling_height * step_width - multipass_adjustment) * sizeof(void*),
796*4bdc9457SAndroid Build Coastguard Worker .output_increment = output_width_stride - (channels << log2_data_element_size),
797*4bdc9457SAndroid Build Coastguard Worker };
798*4bdc9457SAndroid Build Coastguard Worker memcpy(&average_pooling_op->context.pixelwise_average_pooling.params, params, params_size);
799*4bdc9457SAndroid Build Coastguard Worker if (pooling_size <= primary_tile) {
800*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->context.pixelwise_average_pooling.unipass_ukernel = pavgpool->unipass;
801*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.task_2d = (pthreadpool_task_2d_t) xnn_compute_pixelwise_average_pooling_unipass;
802*4bdc9457SAndroid Build Coastguard Worker } else {
803*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->context.pixelwise_average_pooling.multipass_ukernel = pavgpool->multipass;
804*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.task_2d = (pthreadpool_task_2d_t) xnn_compute_pixelwise_average_pooling_multipass;
805*4bdc9457SAndroid Build Coastguard Worker }
806*4bdc9457SAndroid Build Coastguard Worker } else {
807*4bdc9457SAndroid Build Coastguard Worker const uint32_t incremental_tile = avgpool->incremental_tile;
808*4bdc9457SAndroid Build Coastguard Worker const size_t multipass_adjustment =
809*4bdc9457SAndroid Build Coastguard Worker pooling_size > primary_tile ? round_up(pooling_size - primary_tile, incremental_tile) + primary_tile - incremental_tile : 0;
810*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->context.average_pooling = (struct average_pooling_context) {
811*4bdc9457SAndroid Build Coastguard Worker .indirect_input = average_pooling_op->indirection_buffer,
812*4bdc9457SAndroid Build Coastguard Worker .indirect_input_height_stride = indirect_input_height_stride,
813*4bdc9457SAndroid Build Coastguard Worker .input_offset = (size_t) ((uintptr_t) input - (uintptr_t) average_pooling_op->last_input),
814*4bdc9457SAndroid Build Coastguard Worker .input_batch_stride = input_height * input_width * average_pooling_op->input_pixel_stride << log2_data_element_size,
815*4bdc9457SAndroid Build Coastguard Worker .output = output,
816*4bdc9457SAndroid Build Coastguard Worker .output_batch_stride = output_height * output_height_stride,
817*4bdc9457SAndroid Build Coastguard Worker .output_height_stride = output_height_stride,
818*4bdc9457SAndroid Build Coastguard Worker .output_width = output_width,
819*4bdc9457SAndroid Build Coastguard Worker .pooling_size = pooling_size,
820*4bdc9457SAndroid Build Coastguard Worker .channels = channels,
821*4bdc9457SAndroid Build Coastguard Worker .zero = average_pooling_op->zero_buffer,
822*4bdc9457SAndroid Build Coastguard Worker .input_increment = (pooling_height * step_width - multipass_adjustment) * sizeof(void*),
823*4bdc9457SAndroid Build Coastguard Worker .output_increment = output_width_stride - (channels << log2_data_element_size),
824*4bdc9457SAndroid Build Coastguard Worker .params.f32 = average_pooling_op->params.f32_scaleminmax,
825*4bdc9457SAndroid Build Coastguard Worker };
826*4bdc9457SAndroid Build Coastguard Worker memcpy(&average_pooling_op->context.average_pooling.params, params, params_size);
827*4bdc9457SAndroid Build Coastguard Worker if (pooling_size <= primary_tile) {
828*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->context.average_pooling.unipass_ukernel = avgpool->unipass;
829*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.task_2d = (pthreadpool_task_2d_t) xnn_compute_average_pooling_unipass;
830*4bdc9457SAndroid Build Coastguard Worker } else {
831*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->context.average_pooling.multipass_ukernel = avgpool->multipass;
832*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.task_2d = (pthreadpool_task_2d_t) xnn_compute_average_pooling_multipass;
833*4bdc9457SAndroid Build Coastguard Worker }
834*4bdc9457SAndroid Build Coastguard Worker }
835*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.type = xnn_parallelization_type_2d;
836*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.range[0] = batch_size;
837*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->compute.range[1] = output_height;
838*4bdc9457SAndroid Build Coastguard Worker }
839*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->state = xnn_run_state_ready;
840*4bdc9457SAndroid Build Coastguard Worker
841*4bdc9457SAndroid Build Coastguard Worker return xnn_status_success;
842*4bdc9457SAndroid Build Coastguard Worker }
843*4bdc9457SAndroid Build Coastguard Worker
xnn_setup_average_pooling2d_nhwc_qu8(xnn_operator_t average_pooling_op,size_t batch_size,size_t input_height,size_t input_width,const uint8_t * input,uint8_t * output,pthreadpool_t threadpool)844*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_setup_average_pooling2d_nhwc_qu8(
845*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t average_pooling_op,
846*4bdc9457SAndroid Build Coastguard Worker size_t batch_size,
847*4bdc9457SAndroid Build Coastguard Worker size_t input_height,
848*4bdc9457SAndroid Build Coastguard Worker size_t input_width,
849*4bdc9457SAndroid Build Coastguard Worker const uint8_t* input,
850*4bdc9457SAndroid Build Coastguard Worker uint8_t* output,
851*4bdc9457SAndroid Build Coastguard Worker pthreadpool_t threadpool)
852*4bdc9457SAndroid Build Coastguard Worker {
853*4bdc9457SAndroid Build Coastguard Worker if (average_pooling_op->type != xnn_operator_type_average_pooling_nhwc_qu8) {
854*4bdc9457SAndroid Build Coastguard Worker xnn_log_error("failed to setup operator: operator type mismatch (expected %s, got %s)",
855*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_qu8),
856*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(average_pooling_op->type));
857*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
858*4bdc9457SAndroid Build Coastguard Worker }
859*4bdc9457SAndroid Build Coastguard Worker
860*4bdc9457SAndroid Build Coastguard Worker assert(average_pooling_op->ukernel.type == xnn_ukernel_type_average_pooling);
861*4bdc9457SAndroid Build Coastguard Worker
862*4bdc9457SAndroid Build Coastguard Worker // Number of rows read in the GAVGPOOL micro-kernel.
863*4bdc9457SAndroid Build Coastguard Worker const size_t input_size = input_height * input_width;
864*4bdc9457SAndroid Build Coastguard Worker const size_t pooling_size = average_pooling_op->kernel_height * average_pooling_op->kernel_width;
865*4bdc9457SAndroid Build Coastguard Worker const size_t gavgpool_nrows = round_up(input_size, xnn_params.qu8.gavgpool.row_tile);
866*4bdc9457SAndroid Build Coastguard Worker xnn_params.qu8.gavgpool.update.qu8(
867*4bdc9457SAndroid Build Coastguard Worker &average_pooling_op->params.qu8_gavgpool,
868*4bdc9457SAndroid Build Coastguard Worker -(average_pooling_op->input_zero_point * (int32_t) gavgpool_nrows),
869*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->input_scale / (average_pooling_op->output_scale * (float) pooling_size));
870*4bdc9457SAndroid Build Coastguard Worker
871*4bdc9457SAndroid Build Coastguard Worker return setup_average_pooling2d(
872*4bdc9457SAndroid Build Coastguard Worker average_pooling_op,
873*4bdc9457SAndroid Build Coastguard Worker batch_size, input_height, input_width,
874*4bdc9457SAndroid Build Coastguard Worker input, output,
875*4bdc9457SAndroid Build Coastguard Worker 0 /* log2(sizeof(data element)) = log2(sizeof(uint8_t)) */,
876*4bdc9457SAndroid Build Coastguard Worker 0 /* log2(sizeof(weight element)) = log2(sizeof(uint8_t)) */,
877*4bdc9457SAndroid Build Coastguard Worker NULL /* indirection_init_pavgpool2d */,
878*4bdc9457SAndroid Build Coastguard Worker &xnn_params.qu8.avgpool,
879*4bdc9457SAndroid Build Coastguard Worker NULL /* no PAVGPOOL micro-kernel */,
880*4bdc9457SAndroid Build Coastguard Worker &xnn_params.qu8.gavgpool,
881*4bdc9457SAndroid Build Coastguard Worker &average_pooling_op->params.qu8_avgpool,
882*4bdc9457SAndroid Build Coastguard Worker sizeof(average_pooling_op->params.qu8_avgpool),
883*4bdc9457SAndroid Build Coastguard Worker &average_pooling_op->params.qu8_gavgpool,
884*4bdc9457SAndroid Build Coastguard Worker sizeof(average_pooling_op->params.qu8_gavgpool),
885*4bdc9457SAndroid Build Coastguard Worker pthreadpool_get_threads_count(threadpool),
886*4bdc9457SAndroid Build Coastguard Worker false /* pixelwise not supported */);
887*4bdc9457SAndroid Build Coastguard Worker }
888*4bdc9457SAndroid Build Coastguard Worker
xnn_setup_average_pooling2d_nhwc_f16(xnn_operator_t average_pooling_op,size_t batch_size,size_t input_height,size_t input_width,const void * input,void * output,pthreadpool_t threadpool)889*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_setup_average_pooling2d_nhwc_f16(
890*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t average_pooling_op,
891*4bdc9457SAndroid Build Coastguard Worker size_t batch_size,
892*4bdc9457SAndroid Build Coastguard Worker size_t input_height,
893*4bdc9457SAndroid Build Coastguard Worker size_t input_width,
894*4bdc9457SAndroid Build Coastguard Worker const void* input,
895*4bdc9457SAndroid Build Coastguard Worker void* output,
896*4bdc9457SAndroid Build Coastguard Worker pthreadpool_t threadpool)
897*4bdc9457SAndroid Build Coastguard Worker {
898*4bdc9457SAndroid Build Coastguard Worker if (average_pooling_op->type != xnn_operator_type_average_pooling_nhwc_f16) {
899*4bdc9457SAndroid Build Coastguard Worker xnn_log_error("failed to setup operator: operator type mismatch (expected %s, got %s)",
900*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f16),
901*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(average_pooling_op->type));
902*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
903*4bdc9457SAndroid Build Coastguard Worker }
904*4bdc9457SAndroid Build Coastguard Worker
905*4bdc9457SAndroid Build Coastguard Worker assert(average_pooling_op->ukernel.type == xnn_ukernel_type_average_pooling ||
906*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->ukernel.type == xnn_ukernel_type_pixelwise_average_pooling);
907*4bdc9457SAndroid Build Coastguard Worker
908*4bdc9457SAndroid Build Coastguard Worker const void* pooling_params = &average_pooling_op->params.f16_scaleminmax;
909*4bdc9457SAndroid Build Coastguard Worker size_t pooling_params_size = sizeof(average_pooling_op->params.f16_scaleminmax);
910*4bdc9457SAndroid Build Coastguard Worker const bool is_pixelwise = average_pooling_op->ukernel.type == xnn_ukernel_type_pixelwise_average_pooling;
911*4bdc9457SAndroid Build Coastguard Worker if (is_pixelwise) {
912*4bdc9457SAndroid Build Coastguard Worker const size_t input_size = input_height * input_width;
913*4bdc9457SAndroid Build Coastguard Worker xnn_params.f16.gavgpool.update.f16(&average_pooling_op->params.f16_scaleminmax, fp16_ieee_from_fp32_value(1.0f / (float) (int32_t) input_size));
914*4bdc9457SAndroid Build Coastguard Worker pooling_params = &average_pooling_op->params.f16_minmax;
915*4bdc9457SAndroid Build Coastguard Worker pooling_params_size = sizeof(average_pooling_op->params.f16_minmax);
916*4bdc9457SAndroid Build Coastguard Worker }
917*4bdc9457SAndroid Build Coastguard Worker
918*4bdc9457SAndroid Build Coastguard Worker return setup_average_pooling2d(
919*4bdc9457SAndroid Build Coastguard Worker average_pooling_op,
920*4bdc9457SAndroid Build Coastguard Worker batch_size, input_height, input_width,
921*4bdc9457SAndroid Build Coastguard Worker input, output,
922*4bdc9457SAndroid Build Coastguard Worker 1 /* log2(sizeof(data element)) = log2(sizeof(half)) */,
923*4bdc9457SAndroid Build Coastguard Worker 1 /* log2(sizeof(weight element)) = log2(sizeof(half)) */,
924*4bdc9457SAndroid Build Coastguard Worker (xnn_indirection_init_pavgpool2d_fn) xnn_indirection_init_pavgpool2d_f16,
925*4bdc9457SAndroid Build Coastguard Worker &xnn_params.f16.avgpool, &xnn_params.f16.pavgpool, &xnn_params.f16.gavgpool,
926*4bdc9457SAndroid Build Coastguard Worker pooling_params, pooling_params_size,
927*4bdc9457SAndroid Build Coastguard Worker &average_pooling_op->params.f16_scaleminmax, sizeof(average_pooling_op->params.f16_scaleminmax),
928*4bdc9457SAndroid Build Coastguard Worker pthreadpool_get_threads_count(threadpool),
929*4bdc9457SAndroid Build Coastguard Worker is_pixelwise);
930*4bdc9457SAndroid Build Coastguard Worker }
931*4bdc9457SAndroid Build Coastguard Worker
xnn_setup_average_pooling2d_nhwc_f32(xnn_operator_t average_pooling_op,size_t batch_size,size_t input_height,size_t input_width,const float * input,float * output,pthreadpool_t threadpool)932*4bdc9457SAndroid Build Coastguard Worker enum xnn_status xnn_setup_average_pooling2d_nhwc_f32(
933*4bdc9457SAndroid Build Coastguard Worker xnn_operator_t average_pooling_op,
934*4bdc9457SAndroid Build Coastguard Worker size_t batch_size,
935*4bdc9457SAndroid Build Coastguard Worker size_t input_height,
936*4bdc9457SAndroid Build Coastguard Worker size_t input_width,
937*4bdc9457SAndroid Build Coastguard Worker const float* input,
938*4bdc9457SAndroid Build Coastguard Worker float* output,
939*4bdc9457SAndroid Build Coastguard Worker pthreadpool_t threadpool)
940*4bdc9457SAndroid Build Coastguard Worker {
941*4bdc9457SAndroid Build Coastguard Worker if (average_pooling_op->type != xnn_operator_type_average_pooling_nhwc_f32) {
942*4bdc9457SAndroid Build Coastguard Worker xnn_log_error("failed to setup operator: operator type mismatch (expected %s, got %s)",
943*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(xnn_operator_type_average_pooling_nhwc_f32),
944*4bdc9457SAndroid Build Coastguard Worker xnn_operator_type_to_string(average_pooling_op->type));
945*4bdc9457SAndroid Build Coastguard Worker return xnn_status_invalid_parameter;
946*4bdc9457SAndroid Build Coastguard Worker }
947*4bdc9457SAndroid Build Coastguard Worker
948*4bdc9457SAndroid Build Coastguard Worker assert(average_pooling_op->ukernel.type == xnn_ukernel_type_average_pooling ||
949*4bdc9457SAndroid Build Coastguard Worker average_pooling_op->ukernel.type == xnn_ukernel_type_pixelwise_average_pooling);
950*4bdc9457SAndroid Build Coastguard Worker
951*4bdc9457SAndroid Build Coastguard Worker const void* pooling_params = &average_pooling_op->params.f32_scaleminmax;
952*4bdc9457SAndroid Build Coastguard Worker size_t pooling_params_size = sizeof(average_pooling_op->params.f32_scaleminmax);
953*4bdc9457SAndroid Build Coastguard Worker const bool is_pixelwise = average_pooling_op->ukernel.type == xnn_ukernel_type_pixelwise_average_pooling;
954*4bdc9457SAndroid Build Coastguard Worker if (is_pixelwise) {
955*4bdc9457SAndroid Build Coastguard Worker const size_t input_size = input_height * input_width;
956*4bdc9457SAndroid Build Coastguard Worker xnn_params.f32.gavgpool.update.f32(&average_pooling_op->params.f32_scaleminmax, 1.0f / (float) (int32_t) input_size);
957*4bdc9457SAndroid Build Coastguard Worker pooling_params = &average_pooling_op->params.f32_minmax;
958*4bdc9457SAndroid Build Coastguard Worker pooling_params_size = sizeof(average_pooling_op->params.f32_minmax);
959*4bdc9457SAndroid Build Coastguard Worker }
960*4bdc9457SAndroid Build Coastguard Worker
961*4bdc9457SAndroid Build Coastguard Worker return setup_average_pooling2d(
962*4bdc9457SAndroid Build Coastguard Worker average_pooling_op,
963*4bdc9457SAndroid Build Coastguard Worker batch_size, input_height, input_width,
964*4bdc9457SAndroid Build Coastguard Worker input, output,
965*4bdc9457SAndroid Build Coastguard Worker 2 /* log2(sizeof(data element)) = log2(sizeof(float)) */,
966*4bdc9457SAndroid Build Coastguard Worker 2 /* log2(sizeof(weight element)) = log2(sizeof(float)) */,
967*4bdc9457SAndroid Build Coastguard Worker (xnn_indirection_init_pavgpool2d_fn) xnn_indirection_init_pavgpool2d_f32,
968*4bdc9457SAndroid Build Coastguard Worker &xnn_params.f32.avgpool, &xnn_params.f32.pavgpool, &xnn_params.f32.gavgpool,
969*4bdc9457SAndroid Build Coastguard Worker pooling_params, pooling_params_size,
970*4bdc9457SAndroid Build Coastguard Worker &average_pooling_op->params.f32_scaleminmax, sizeof(average_pooling_op->params.f32_scaleminmax),
971*4bdc9457SAndroid Build Coastguard Worker pthreadpool_get_threads_count(threadpool),
972*4bdc9457SAndroid Build Coastguard Worker is_pixelwise);
973*4bdc9457SAndroid Build Coastguard Worker }
974