• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 Google LLC
2 //
3 // This source code is licensed under the BSD-style license found in the
4 // LICENSE file in the root directory of this source tree.
5 
6 #include <assert.h>
7 #include <math.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 #include <stdlib.h>
11 
12 #include <xnnpack.h>
13 #include <xnnpack/allocator.h>
14 #include <xnnpack/log.h>
15 #include <xnnpack/operator.h>
16 #include <xnnpack/microparams-init.h>
17 #include <xnnpack/params.h>
18 
19 
create_constant_pad_nd(uint32_t padding_value,uint32_t flags,enum xnn_operator_type operator_type,xnn_operator_t * constant_pad_op_out)20 static enum xnn_status create_constant_pad_nd(
21     uint32_t padding_value,
22     uint32_t flags,
23     enum xnn_operator_type operator_type,
24     xnn_operator_t* constant_pad_op_out)
25 {
26   xnn_operator_t constant_pad_op = NULL;
27   enum xnn_status status = xnn_status_uninitialized;
28 
29   if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
30     xnn_log_error(
31       "failed to create %s operator: XNNPACK is not initialized",
32       xnn_operator_type_to_string(xnn_operator_type_constant_pad_nd_x32));
33     goto error;
34   }
35 
36   status = xnn_status_out_of_memory;
37 
38   constant_pad_op = xnn_allocate_zero_simd_memory(sizeof(struct xnn_operator));
39   if (constant_pad_op == NULL) {
40     xnn_log_error(
41       "failed to allocate %zu bytes for %s operator descriptor",
42       sizeof(struct xnn_operator), xnn_operator_type_to_string(xnn_operator_type_constant_pad_nd_x32));
43     goto error;
44   }
45 
46   constant_pad_op->pad_value = padding_value;
47 
48   constant_pad_op->type = operator_type;
49   constant_pad_op->flags = flags;
50 
51   constant_pad_op->state = xnn_run_state_invalid;
52 
53   *constant_pad_op_out = constant_pad_op;
54   return xnn_status_success;
55 
56 error:
57   xnn_delete_operator(constant_pad_op);
58   return status;
59 }
60 
xnn_create_constant_pad_nd_x8(const void * padding_value,uint32_t flags,xnn_operator_t * constant_pad_op_out)61 enum xnn_status xnn_create_constant_pad_nd_x8(
62   const void* padding_value,
63   uint32_t flags,
64   xnn_operator_t* constant_pad_op_out)
65 {
66   const uint32_t padding_pattern = *((const uint8_t*) padding_value);
67   return create_constant_pad_nd(
68     padding_pattern * UINT32_C(0x01010101), flags, xnn_operator_type_constant_pad_nd_x8, constant_pad_op_out);
69 }
70 
xnn_create_constant_pad_nd_x16(const void * padding_value,uint32_t flags,xnn_operator_t * constant_pad_op_out)71 enum xnn_status xnn_create_constant_pad_nd_x16(
72   const void* padding_value,
73   uint32_t flags,
74   xnn_operator_t* constant_pad_op_out)
75 {
76   const uint32_t padding_pattern = *((const uint16_t*) padding_value);
77   return create_constant_pad_nd(
78     padding_pattern * UINT32_C(0x00010001), flags, xnn_operator_type_constant_pad_nd_x16, constant_pad_op_out);
79 }
80 
xnn_create_constant_pad_nd_x32(const void * padding_value,uint32_t flags,xnn_operator_t * constant_pad_op_out)81 enum xnn_status xnn_create_constant_pad_nd_x32(
82   const void* padding_value,
83   uint32_t flags,
84   xnn_operator_t* constant_pad_op_out)
85 {
86   return create_constant_pad_nd(
87     *((const uint32_t*) padding_value), flags, xnn_operator_type_constant_pad_nd_x32, constant_pad_op_out);
88 }
89 
setup_constant_pad_nd(xnn_operator_t constant_pad_op,enum xnn_operator_type expected_operator_type,size_t num_dims,const size_t * input_shape,const size_t * pre_paddings,const size_t * post_paddings,const void * input,void * output,uint32_t log2_element_size,size_t num_threads)90 static enum xnn_status setup_constant_pad_nd(
91     xnn_operator_t constant_pad_op,
92     enum xnn_operator_type expected_operator_type,
93     size_t num_dims,
94     const size_t* input_shape,
95     const size_t* pre_paddings,
96     const size_t* post_paddings,
97     const void* input,
98     void* output,
99     uint32_t log2_element_size,
100     size_t num_threads)
101 {
102   if (constant_pad_op->type != expected_operator_type) {
103     xnn_log_error("failed to setup operator: operator type mismatch (expected %s, got %s)",
104       xnn_operator_type_to_string(expected_operator_type),
105       xnn_operator_type_to_string(constant_pad_op->type));
106     return xnn_status_invalid_parameter;
107   }
108   constant_pad_op->state = xnn_run_state_invalid;
109 
110   if ((xnn_params.init_flags & XNN_INIT_FLAG_XNNPACK) == 0) {
111     xnn_log_error("failed to setup %s operator: XNNPACK is not initialized",
112       xnn_operator_type_to_string(constant_pad_op->type));
113     return xnn_status_uninitialized;
114   }
115 
116   if (num_dims > XNN_MAX_TENSOR_DIMS) {
117     xnn_log_error(
118       "failed to setup %s operator with %zu dimensions in input shape: "
119       "the number of input dimensions must not exceed %d",
120       xnn_operator_type_to_string(constant_pad_op->type), num_dims, XNN_MAX_TENSOR_DIMS);
121     return xnn_status_unsupported_parameter;
122   }
123 
124   for (size_t i = 0; i < num_dims; i++) {
125     if (input_shape[i] == 0) {
126       xnn_log_error(
127         "failed to setup %s operator: input shape dimension #%zu is zero",
128         xnn_operator_type_to_string(constant_pad_op->type), i);
129       return xnn_status_invalid_parameter;
130     }
131   }
132 
133   size_t num_squeezed_dims = 0;
134   size_t normalized_pre_paddings[XNN_MAX_TENSOR_DIMS];
135   size_t normalized_input_shape[XNN_MAX_TENSOR_DIMS];
136   size_t normalized_output_shape[XNN_MAX_TENSOR_DIMS];
137   for (size_t i = 0; i < XNN_MAX_TENSOR_DIMS; i++) {
138     normalized_pre_paddings[i] = 0;
139     normalized_input_shape[i] = 1;
140     normalized_output_shape[i] = 1;
141   }
142 
143   bool is_previous_dim_padded = true;
144   for (size_t i = 0; i < num_dims; i++) {
145     const size_t pre_padding = pre_paddings[num_dims - 1 - i];
146     const size_t post_padding = post_paddings[num_dims - 1 - i];
147     const size_t input_dim = input_shape[num_dims - 1 - i];
148 
149     const bool is_current_dim_padded = (pre_padding | post_padding) != 0;
150     if (is_current_dim_padded || is_previous_dim_padded) {
151       normalized_pre_paddings[XNN_MAX_TENSOR_DIMS - 1 - num_squeezed_dims] = pre_padding;
152       normalized_input_shape[XNN_MAX_TENSOR_DIMS - 1 - num_squeezed_dims] = input_dim;
153       normalized_output_shape[XNN_MAX_TENSOR_DIMS - 1 - num_squeezed_dims] = pre_padding + input_dim + post_padding;
154 
155       num_squeezed_dims += 1;
156       is_previous_dim_padded = is_current_dim_padded;
157     } else {
158       assert(!is_previous_dim_padded);
159       assert(pre_padding == 0);
160       assert(post_padding == 0);
161       assert(i != 0);
162 
163       normalized_input_shape[XNN_MAX_TENSOR_DIMS - num_squeezed_dims] *= input_dim;
164       normalized_output_shape[XNN_MAX_TENSOR_DIMS - num_squeezed_dims] *= input_dim;
165     }
166   }
167 
168   constant_pad_op->context.pad = (struct pad_context) {
169     .input = input,
170     .output = output,
171     .padding_value = constant_pad_op->pad_value,
172     .fill_ukernel = xnn_params.xx.fill.ukernel,
173     .pad_ukernel = xnn_params.xx.pad.ukernel,
174   };
175 
176   for (size_t i = 0; i < XNN_MAX_TENSOR_DIMS; i++) {
177     constant_pad_op->context.pad.pre_paddings[i] = normalized_pre_paddings[XNN_MAX_TENSOR_DIMS - 1 - i];
178     constant_pad_op->context.pad.input_size[i] = normalized_input_shape[XNN_MAX_TENSOR_DIMS - 1 - i];
179   }
180   size_t input_stride = normalized_input_shape[XNN_MAX_TENSOR_DIMS - 1];
181   size_t output_stride = normalized_output_shape[XNN_MAX_TENSOR_DIMS - 1];
182   for (size_t i = 1; i < XNN_MAX_TENSOR_DIMS; i++) {
183     constant_pad_op->context.pad.input = (const void*)
184       ((uintptr_t) constant_pad_op->context.pad.input - (constant_pad_op->context.pad.pre_paddings[i] * input_stride << log2_element_size));
185     constant_pad_op->context.pad.input_stride[i - 1] = input_stride << log2_element_size;
186     constant_pad_op->context.pad.output_stride[i - 1] = output_stride << log2_element_size;
187     input_stride *= normalized_input_shape[XNN_MAX_TENSOR_DIMS - 1 - i];
188     output_stride *= normalized_output_shape[XNN_MAX_TENSOR_DIMS - 1 - i];
189   }
190   constant_pad_op->context.pad.input_size[0] <<= log2_element_size;
191   constant_pad_op->context.pad.output_size[0] = normalized_output_shape[XNN_MAX_TENSOR_DIMS - 1] << log2_element_size;
192   constant_pad_op->context.pad.pre_paddings[0] <<= log2_element_size;
193   constant_pad_op->context.pad.post_paddings[0] =
194     constant_pad_op->context.pad.output_size[0] - constant_pad_op->context.pad.pre_paddings[0] - constant_pad_op->context.pad.input_size[0];
195 
196   constant_pad_op->compute.type = xnn_parallelization_type_5d;
197   constant_pad_op->compute.task_5d = (pthreadpool_task_5d_t) xnn_compute_pad_5d;
198   constant_pad_op->compute.range[0] = normalized_output_shape[0];
199   constant_pad_op->compute.range[1] = normalized_output_shape[1];
200   constant_pad_op->compute.range[2] = normalized_output_shape[2];
201   constant_pad_op->compute.range[3] = normalized_output_shape[3];
202   constant_pad_op->compute.range[4] = normalized_output_shape[4];
203   constant_pad_op->state = xnn_run_state_ready;
204 
205   return xnn_status_success;
206 }
207 
xnn_setup_constant_pad_nd_x8(xnn_operator_t constant_pad_op,size_t num_dims,const size_t * input_shape,const size_t * pre_padding,const size_t * post_padding,const void * input,void * output,pthreadpool_t threadpool)208 enum xnn_status xnn_setup_constant_pad_nd_x8(
209     xnn_operator_t constant_pad_op,
210     size_t num_dims,
211     const size_t* input_shape,
212     const size_t* pre_padding,
213     const size_t* post_padding,
214     const void* input,
215     void* output,
216     pthreadpool_t threadpool)
217 {
218   return setup_constant_pad_nd(
219     constant_pad_op, xnn_operator_type_constant_pad_nd_x8,
220     num_dims, input_shape, pre_padding, post_padding,
221     input, output, 0 /* log2(element size) */,
222     pthreadpool_get_threads_count(threadpool));
223 }
224 
xnn_setup_constant_pad_nd_x16(xnn_operator_t constant_pad_op,size_t num_dims,const size_t * input_shape,const size_t * pre_padding,const size_t * post_padding,const void * input,void * output,pthreadpool_t threadpool)225 enum xnn_status xnn_setup_constant_pad_nd_x16(
226     xnn_operator_t constant_pad_op,
227     size_t num_dims,
228     const size_t* input_shape,
229     const size_t* pre_padding,
230     const size_t* post_padding,
231     const void* input,
232     void* output,
233     pthreadpool_t threadpool)
234 {
235   return setup_constant_pad_nd(
236     constant_pad_op, xnn_operator_type_constant_pad_nd_x16,
237     num_dims, input_shape, pre_padding, post_padding,
238     input, output, 1 /* log2(element size) */,
239     pthreadpool_get_threads_count(threadpool));
240 }
241 
xnn_setup_constant_pad_nd_x32(xnn_operator_t constant_pad_op,size_t num_dims,const size_t * input_shape,const size_t * pre_padding,const size_t * post_padding,const void * input,void * output,pthreadpool_t threadpool)242 enum xnn_status xnn_setup_constant_pad_nd_x32(
243     xnn_operator_t constant_pad_op,
244     size_t num_dims,
245     const size_t* input_shape,
246     const size_t* pre_padding,
247     const size_t* post_padding,
248     const void* input,
249     void* output,
250     pthreadpool_t threadpool)
251 {
252   return setup_constant_pad_nd(
253     constant_pad_op, xnn_operator_type_constant_pad_nd_x32,
254     num_dims, input_shape, pre_padding, post_padding,
255     input, output, 2 /* log2(element size) */,
256     pthreadpool_get_threads_count(threadpool));
257 }
258