• 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 <math.h>
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 
11 #include <xnnpack.h>
12 #include <xnnpack/allocator.h>
13 #include <xnnpack/log.h>
14 #include <xnnpack/math.h>
15 #include <xnnpack/params.h>
16 #include <xnnpack/subgraph.h>
17 
18 
xnn_create_subgraph(uint32_t external_value_ids,uint32_t flags,xnn_subgraph_t * subgraph_out)19 enum xnn_status xnn_create_subgraph(
20     uint32_t external_value_ids,
21     uint32_t flags,
22     xnn_subgraph_t* subgraph_out)
23 {
24   struct xnn_subgraph* subgraph = NULL;
25   enum xnn_status status = xnn_status_uninitialized;
26 
27   if (!xnn_params.initialized) {
28     xnn_log_error("failed to create subgraph: XNNPACK is not initialized");
29     goto error;
30   }
31 
32   status = xnn_status_out_of_memory;
33 
34   subgraph = xnn_allocate_zero_memory(sizeof(struct xnn_subgraph));
35   if (subgraph == NULL) {
36     xnn_log_error("failed to allocate %zu bytes for subgraph descriptor", sizeof(struct xnn_subgraph));
37     goto error;
38   }
39 
40   subgraph->external_value_ids = external_value_ids;
41 
42   subgraph->values = xnn_allocate_zero_memory(external_value_ids * sizeof(struct xnn_value));
43   if (subgraph->values == NULL) {
44     xnn_log_error("failed to allocate %zu bytes for subgraph values", external_value_ids * sizeof(struct xnn_value));
45     goto error;
46   }
47   for (size_t i = 0; i < external_value_ids; i++) {
48     subgraph->values[i].id = i;
49   }
50   subgraph->num_values = external_value_ids;
51   subgraph->num_reserved_values = external_value_ids;
52 
53   *subgraph_out = subgraph;
54   return xnn_status_success;
55 
56 error:
57   xnn_delete_subgraph(subgraph);
58   return status;
59 }
60 
61 
xnn_subgraph_new_internal_value(xnn_subgraph_t subgraph)62 struct xnn_value* xnn_subgraph_new_internal_value(xnn_subgraph_t subgraph)
63 {
64   struct xnn_value* values = subgraph->values;
65   const size_t size = subgraph->num_values;
66   const size_t capacity = subgraph->num_reserved_values;
67   if (capacity < size + 1) {
68     const size_t new_capacity = max(min(capacity * 2, capacity + 512), capacity + 64);
69     assert(new_capacity >= size + 1);
70     values = xnn_reallocate_memory(values, new_capacity * sizeof(struct xnn_value));
71     if (values == NULL) {
72       xnn_log_error("failed to allocate %zu bytes for subgraph values",
73         capacity * sizeof(struct xnn_value));
74       return values;
75     }
76 
77     memset(values + size, 0, (new_capacity - size) * sizeof(struct xnn_value));
78     subgraph->num_reserved_values = new_capacity;
79     subgraph->values = values;
80   }
81   subgraph->num_values = size + 1;
82   struct xnn_value* new_value = values + size;
83   new_value->id = size;
84   return new_value;
85 }
86 
xnn_subgraph_new_node(xnn_subgraph_t subgraph)87 struct xnn_node* xnn_subgraph_new_node(xnn_subgraph_t subgraph)
88 {
89   struct xnn_node* nodes = subgraph->nodes;
90   const size_t size = subgraph->num_nodes;
91   const size_t capacity = subgraph->num_reserved_nodes;
92 
93   if (capacity < size + 1) {
94     const size_t new_capacity = max(min(capacity * 2, capacity + 512), capacity + 64);
95     assert(new_capacity >= size + 1);
96     nodes = xnn_reallocate_memory(nodes, new_capacity * sizeof(struct xnn_node));
97     if (nodes == NULL) {
98       xnn_log_error("failed to allocate %zu bytes for subgraph nodes",
99         capacity * sizeof(struct xnn_node));
100       return nodes;
101     }
102 
103     memset(nodes + size, 0, (new_capacity - size) * sizeof(struct xnn_node));
104     subgraph->num_reserved_nodes = new_capacity;
105     subgraph->nodes = nodes;
106   }
107   subgraph->num_nodes = size + 1;
108   struct xnn_node* new_node = nodes + size;
109   new_node->id = size;
110   return new_node;
111 }
112 
xnn_define_convolution_2d(xnn_subgraph_t subgraph,uint32_t input_padding_top,uint32_t input_padding_right,uint32_t input_padding_bottom,uint32_t input_padding_left,uint32_t kernel_height,uint32_t kernel_width,uint32_t subsampling_height,uint32_t subsampling_width,uint32_t dilation_height,uint32_t dilation_width,uint32_t groups,size_t group_input_channels,size_t group_output_channels,float output_min,float output_max,uint32_t input_id,uint32_t filter_id,uint32_t bias_id,uint32_t output_id,uint32_t flags)113 enum xnn_status xnn_define_convolution_2d(
114   xnn_subgraph_t subgraph,
115   uint32_t input_padding_top,
116   uint32_t input_padding_right,
117   uint32_t input_padding_bottom,
118   uint32_t input_padding_left,
119   uint32_t kernel_height,
120   uint32_t kernel_width,
121   uint32_t subsampling_height,
122   uint32_t subsampling_width,
123   uint32_t dilation_height,
124   uint32_t dilation_width,
125   uint32_t groups,
126   size_t group_input_channels,
127   size_t group_output_channels,
128   float output_min,
129   float output_max,
130   uint32_t input_id,
131   uint32_t filter_id,
132   uint32_t bias_id,
133   uint32_t output_id,
134   uint32_t flags)
135 {
136   if (!xnn_params.initialized) {
137     xnn_log_error("failed to define Convolution operator: XNNPACK is not initialized");
138     return xnn_status_uninitialized;
139   }
140 
141   if (kernel_width == 0 || kernel_height == 0) {
142     xnn_log_error(
143       "failed to define Convolution operator with %" PRIu32 "x%" PRIu32 " kernel: kernel dimensions must be non-zero",
144       kernel_width, kernel_height);
145     return xnn_status_invalid_parameter;
146   }
147 
148   if (subsampling_width == 0 || subsampling_height == 0) {
149     xnn_log_error(
150       "failed to define Convolution operator with %" PRIu32 "x%" PRIu32 " subsampling: "
151       "subsampling dimensions must be non-zero",
152       subsampling_width, subsampling_height);
153     return xnn_status_invalid_parameter;
154   }
155 
156   if (dilation_width == 0 || dilation_height == 0) {
157     xnn_log_error(
158       "failed to define Convolution operator with %" PRIu32 "x%" PRIu32 " dilation: "
159       "dilation dimensions must be non-zero",
160       dilation_width, dilation_height);
161     return xnn_status_invalid_parameter;
162   }
163 
164   if (groups == 0) {
165     xnn_log_error(
166       "failed to define Convolution operator with %" PRIu32 " groups: number of groups must be non-zero", groups);
167     return xnn_status_invalid_parameter;
168   }
169 
170   if (group_input_channels == 0) {
171     xnn_log_error(
172       "failed to define Convolution operator with %zu input channels per group: "
173       "number of channels must be non-zero",
174       group_input_channels);
175     return xnn_status_invalid_parameter;
176   }
177 
178   if (group_output_channels == 0) {
179     xnn_log_error(
180       "failed to define Convolution operator with %zu output channels per group: "
181       "number of channels must be non-zero",
182       group_output_channels);
183     return xnn_status_invalid_parameter;
184   }
185 
186   if (isnan(output_min)) {
187     xnn_log_error(
188       "failed to define Convolution operator with NaN output lower bound: lower bound must be non-NaN");
189     return xnn_status_invalid_parameter;
190   }
191 
192   if (isnan(output_max)) {
193     xnn_log_error(
194       "failed to define Convolution operator with NaN output upper bound: upper bound must be non-NaN");
195     return xnn_status_invalid_parameter;
196   }
197 
198   if (output_min >= output_max) {
199     xnn_log_error(
200       "failed to define Convolution operator with [%.7g, %.7g] output range: "
201       "lower bound must be below upper bound",
202       output_min, output_max);
203     return xnn_status_invalid_parameter;
204   }
205 
206   if (input_id >= subgraph->num_values) {
207     xnn_log_error(
208       "failed to define Convolution operator with input ID #%" PRIu32 ": invalid Value ID",
209       input_id);
210     return xnn_status_invalid_parameter;
211   }
212 
213   if (filter_id >= subgraph->num_values) {
214     xnn_log_error(
215       "failed to define Convolution operator with filter ID #%" PRIu32 ": invalid Value ID",
216       filter_id);
217     return xnn_status_invalid_parameter;
218   }
219 
220   if (bias_id >= subgraph->num_values) {
221     xnn_log_error(
222       "failed to define Convolution operator with bias ID #%" PRIu32 ": invalid Value ID",
223       bias_id);
224     return xnn_status_invalid_parameter;
225   }
226 
227   if (output_id >= subgraph->num_values) {
228     xnn_log_error(
229       "failed to define Convolution operator with output ID #%" PRIu32 ": invalid Value ID",
230       output_id);
231     return xnn_status_invalid_parameter;
232   }
233 
234   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
235   if (node == NULL) {
236     return xnn_status_out_of_memory;
237   }
238 
239   node->type = xnn_node_type_convolution_2d;
240   node->params.convolution_2d.input_padding_top = input_padding_top;
241   node->params.convolution_2d.input_padding_right = input_padding_right;
242   node->params.convolution_2d.input_padding_bottom = input_padding_bottom;
243   node->params.convolution_2d.input_padding_left = input_padding_left;
244   node->params.convolution_2d.kernel_height = kernel_height;
245   node->params.convolution_2d.kernel_width = kernel_width;
246   node->params.convolution_2d.subsampling_height = subsampling_height;
247   node->params.convolution_2d.subsampling_width = subsampling_width;
248   node->params.convolution_2d.dilation_height = dilation_height;
249   node->params.convolution_2d.dilation_width = dilation_width;
250   node->params.convolution_2d.groups = groups;
251   node->params.convolution_2d.group_input_channels = group_input_channels;
252   node->params.convolution_2d.group_output_channels = group_output_channels;
253   node->activation.output_min = output_min;
254   node->activation.output_max = output_max;
255   node->num_inputs = 3;
256   node->inputs.raw[0] = input_id;
257   node->inputs.raw[1] = filter_id;
258   node->inputs.raw[2] = bias_id;
259   node->num_outputs = 1;
260   node->outputs.raw[0] = output_id;
261   node->flags = flags;
262 
263   return xnn_status_success;
264 };
265 
xnn_define_depthwise_convolution_2d(xnn_subgraph_t subgraph,uint32_t input_padding_top,uint32_t input_padding_right,uint32_t input_padding_bottom,uint32_t input_padding_left,uint32_t kernel_height,uint32_t kernel_width,uint32_t subsampling_height,uint32_t subsampling_width,uint32_t dilation_height,uint32_t dilation_width,uint32_t depth_multiplier,size_t input_channels,float output_min,float output_max,uint32_t input_id,uint32_t filter_id,uint32_t bias_id,uint32_t output_id,uint32_t flags)266 enum xnn_status xnn_define_depthwise_convolution_2d(
267   xnn_subgraph_t subgraph,
268   uint32_t input_padding_top,
269   uint32_t input_padding_right,
270   uint32_t input_padding_bottom,
271   uint32_t input_padding_left,
272   uint32_t kernel_height,
273   uint32_t kernel_width,
274   uint32_t subsampling_height,
275   uint32_t subsampling_width,
276   uint32_t dilation_height,
277   uint32_t dilation_width,
278   uint32_t depth_multiplier,
279   size_t input_channels,
280   float output_min,
281   float output_max,
282   uint32_t input_id,
283   uint32_t filter_id,
284   uint32_t bias_id,
285   uint32_t output_id,
286   uint32_t flags)
287 {
288   if (!xnn_params.initialized) {
289     xnn_log_error("failed to define Depthwise Convolution operator: XNNPACK is not initialized");
290     return xnn_status_uninitialized;
291   }
292 
293   if (kernel_width == 0 || kernel_height == 0) {
294     xnn_log_error(
295       "failed to define Depthwise Convolution operator with %" PRIu32 "x%" PRIu32 " kernel: kernel dimensions must be non-zero",
296       kernel_width, kernel_height);
297     return xnn_status_invalid_parameter;
298   }
299 
300   if (subsampling_width == 0 || subsampling_height == 0) {
301     xnn_log_error(
302       "failed to define Depthwise Convolution operator with %" PRIu32 "x%" PRIu32 " subsampling: "
303       "subsampling dimensions must be non-zero",
304       subsampling_width, subsampling_height);
305     return xnn_status_invalid_parameter;
306   }
307 
308   if (dilation_width == 0 || dilation_height == 0) {
309     xnn_log_error(
310       "failed to define Depthwise Convolution operator with %" PRIu32 "x%" PRIu32 " dilation: "
311       "dilation dimensions must be non-zero",
312       dilation_width, dilation_height);
313     return xnn_status_invalid_parameter;
314   }
315 
316   if (depth_multiplier == 0) {
317     xnn_log_error(
318       "failed to define Depthwise Convolution operator with %" PRIu32 " depth multiplier: "
319       "depth multiplier must be non-zero",
320       depth_multiplier);
321     return xnn_status_invalid_parameter;
322   }
323 
324   if (input_channels == 0) {
325     xnn_log_error(
326       "failed to define Depthwise Convolution operator with %zu input channels: "
327       "number of channels must be non-zero",
328       input_channels);
329     return xnn_status_invalid_parameter;
330   }
331 
332   if (isnan(output_min)) {
333     xnn_log_error(
334       "failed to define Depthwise Convolution operator with NaN output lower bound: lower bound must be non-NaN");
335     return xnn_status_invalid_parameter;
336   }
337 
338   if (isnan(output_max)) {
339     xnn_log_error(
340       "failed to define Depthwise Convolution operator with NaN output upper bound: upper bound must be non-NaN");
341     return xnn_status_invalid_parameter;
342   }
343 
344   if (output_min >= output_max) {
345     xnn_log_error(
346       "failed to define Depthwise Convolution operator with [%.7g, %.7g] output range: "
347       "lower bound must be below upper bound",
348       output_min, output_max);
349     return xnn_status_invalid_parameter;
350   }
351 
352   if (input_id >= subgraph->num_values) {
353     xnn_log_error(
354       "failed to define Depthwise Convolution operator with input ID #%" PRIu32 ": invalid Value ID",
355       input_id);
356     return xnn_status_invalid_parameter;
357   }
358 
359   if (filter_id >= subgraph->num_values) {
360     xnn_log_error(
361       "failed to define Depthwise Convolution operator with filter ID #%" PRIu32 ": invalid Value ID",
362       filter_id);
363     return xnn_status_invalid_parameter;
364   }
365 
366   if (bias_id >= subgraph->num_values) {
367     xnn_log_error(
368       "failed to define Depthwise Convolution operator with bias ID #%" PRIu32 ": invalid Value ID",
369       bias_id);
370     return xnn_status_invalid_parameter;
371   }
372 
373   if (output_id >= subgraph->num_values) {
374     xnn_log_error(
375       "failed to define Depthwise Convolution operator with output ID #%" PRIu32 ": invalid Value ID",
376       output_id);
377     return xnn_status_invalid_parameter;
378   }
379 
380   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
381   if (node == NULL) {
382     return xnn_status_out_of_memory;
383   }
384 
385   node->type = xnn_node_type_depthwise_convolution_2d;
386   node->params.depthwise_convolution_2d.input_padding_top = input_padding_top;
387   node->params.depthwise_convolution_2d.input_padding_right = input_padding_right;
388   node->params.depthwise_convolution_2d.input_padding_bottom = input_padding_bottom;
389   node->params.depthwise_convolution_2d.input_padding_left = input_padding_left;
390   node->params.depthwise_convolution_2d.kernel_height = kernel_height;
391   node->params.depthwise_convolution_2d.kernel_width = kernel_width;
392   node->params.depthwise_convolution_2d.subsampling_height = subsampling_height;
393   node->params.depthwise_convolution_2d.subsampling_width = subsampling_width;
394   node->params.depthwise_convolution_2d.dilation_height = dilation_height;
395   node->params.depthwise_convolution_2d.dilation_width = dilation_width;
396   node->params.depthwise_convolution_2d.depth_multiplier = depth_multiplier;
397   node->params.depthwise_convolution_2d.input_channels = input_channels;
398   node->activation.output_min = output_min;
399   node->activation.output_max = output_max;
400   node->num_inputs = 3;
401   node->inputs.raw[0] = input_id;
402   node->inputs.raw[1] = filter_id;
403   node->inputs.raw[2] = bias_id;
404   node->num_outputs = 1;
405   node->outputs.raw[0] = output_id;
406   node->flags = flags;
407 
408   return xnn_status_success;
409 };
410 
xnn_define_add2(xnn_subgraph_t subgraph,float output_min,float output_max,uint32_t input1_id,uint32_t input2_id,uint32_t output_id,uint32_t flags)411 enum xnn_status xnn_define_add2(
412   xnn_subgraph_t subgraph,
413   float output_min,
414   float output_max,
415   uint32_t input1_id,
416   uint32_t input2_id,
417   uint32_t output_id,
418   uint32_t flags)
419 {
420   if (!xnn_params.initialized) {
421     xnn_log_error("failed to define Add2 operator: XNNPACK is not initialized");
422     return xnn_status_uninitialized;
423   }
424 
425   if (isnan(output_min)) {
426     xnn_log_error(
427       "failed to define Add2 operator with NaN output lower bound: lower bound must be non-NaN");
428     return xnn_status_invalid_parameter;
429   }
430 
431   if (isnan(output_max)) {
432     xnn_log_error(
433       "failed to define Add2 operator with NaN output upper bound: upper bound must be non-NaN");
434     return xnn_status_invalid_parameter;
435   }
436 
437   if (output_min >= output_max) {
438     xnn_log_error(
439       "failed to define Add2 operator with [%.7g, %.7g] output range: "
440       "lower bound must be below upper bound",
441       output_min, output_max);
442     return xnn_status_invalid_parameter;
443   }
444 
445   if (input1_id >= subgraph->num_values) {
446     xnn_log_error(
447       "failed to define Add2 operator with the first input ID #%" PRIu32 ": invalid Value ID",
448       input1_id);
449     return xnn_status_invalid_parameter;
450   }
451 
452   if (input2_id >= subgraph->num_values) {
453     xnn_log_error(
454       "failed to define Add2 operator with the second input ID #%" PRIu32 ": invalid Value ID",
455       input2_id);
456     return xnn_status_invalid_parameter;
457   }
458 
459   if (output_id >= subgraph->num_values) {
460     xnn_log_error(
461       "failed to define Add2 operator with output ID #%" PRIu32 ": invalid Value ID",
462       output_id);
463     return xnn_status_invalid_parameter;
464   }
465 
466   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
467   if (node == NULL) {
468     return xnn_status_out_of_memory;
469   }
470 
471   node->type = xnn_node_type_add2;
472   node->activation.output_min = output_min;
473   node->activation.output_max = output_max;
474   node->num_inputs = 2;
475   node->inputs.raw[0] = input1_id;
476   node->inputs.raw[1] = input2_id;
477   node->num_outputs = 1;
478   node->outputs.raw[0] = output_id;
479   node->flags = flags;
480 
481   return xnn_status_success;
482 }
483 
xnn_define_multiply2(xnn_subgraph_t subgraph,float output_min,float output_max,uint32_t input1_id,uint32_t input2_id,uint32_t output_id,uint32_t flags)484 enum xnn_status xnn_define_multiply2(
485   xnn_subgraph_t subgraph,
486   float output_min,
487   float output_max,
488   uint32_t input1_id,
489   uint32_t input2_id,
490   uint32_t output_id,
491   uint32_t flags)
492 {
493   if (!xnn_params.initialized) {
494     xnn_log_error("failed to define Multiply2 operator: XNNPACK is not initialized");
495     return xnn_status_uninitialized;
496   }
497 
498   if (isnan(output_min)) {
499     xnn_log_error(
500       "failed to define Multiply2 operator with NaN output lower bound: lower bound must be non-NaN");
501     return xnn_status_invalid_parameter;
502   }
503 
504   if (isnan(output_max)) {
505     xnn_log_error(
506       "failed to define Multiply2 operator with NaN output upper bound: upper bound must be non-NaN");
507     return xnn_status_invalid_parameter;
508   }
509 
510   if (output_min >= output_max) {
511     xnn_log_error(
512       "failed to define Multiply2 operator with [%.7g, %.7g] output range: "
513       "lower bound must be below upper bound",
514       output_min, output_max);
515     return xnn_status_invalid_parameter;
516   }
517 
518   if (input1_id >= subgraph->num_values) {
519     xnn_log_error(
520       "failed to define Multiply2 operator with the first input ID #%" PRIu32 ": invalid Value ID",
521       input1_id);
522     return xnn_status_invalid_parameter;
523   }
524 
525   if (input2_id >= subgraph->num_values) {
526     xnn_log_error(
527       "failed to define Multiply2 operator with the second input ID #%" PRIu32 ": invalid Value ID",
528       input2_id);
529     return xnn_status_invalid_parameter;
530   }
531 
532   if (output_id >= subgraph->num_values) {
533     xnn_log_error(
534       "failed to define Multiply2 operator with output ID #%" PRIu32 ": invalid Value ID",
535       output_id);
536     return xnn_status_invalid_parameter;
537   }
538 
539   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
540   if (node == NULL) {
541     return xnn_status_out_of_memory;
542   }
543 
544   node->type = xnn_node_type_multiply2;
545   node->activation.output_min = output_min;
546   node->activation.output_max = output_max;
547   node->num_inputs = 2;
548   node->inputs.raw[0] = input1_id;
549   node->inputs.raw[1] = input2_id;
550   node->num_outputs = 1;
551   node->outputs.raw[0] = output_id;
552   node->flags = flags;
553 
554   return xnn_status_success;
555 }
556 
xnn_define_prelu(xnn_subgraph_t subgraph,uint32_t input_id,uint32_t slope_id,uint32_t output_id,uint32_t flags)557 enum xnn_status xnn_define_prelu(
558   xnn_subgraph_t subgraph,
559   uint32_t input_id,
560   uint32_t slope_id,
561   uint32_t output_id,
562   uint32_t flags)
563 {
564   if (!xnn_params.initialized) {
565     xnn_log_error("failed to define PReLU operator: XNNPACK is not initialized");
566     return xnn_status_uninitialized;
567   }
568 
569   if (input_id >= subgraph->num_values) {
570     xnn_log_error(
571       "failed to define PReLU operator with input ID #%" PRIu32 ": invalid Value ID",
572       input_id);
573     return xnn_status_invalid_parameter;
574   }
575 
576   if (slope_id >= subgraph->num_values) {
577     xnn_log_error(
578       "failed to define PReLU operator with slope ID #%" PRIu32 ": invalid Value ID",
579       slope_id);
580     return xnn_status_invalid_parameter;
581   }
582 
583   if (output_id >= subgraph->num_values) {
584     xnn_log_error(
585       "failed to define PReLU operator with output ID #%" PRIu32 ": invalid Value ID",
586       output_id);
587     return xnn_status_invalid_parameter;
588   }
589 
590   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
591   if (node == NULL) {
592     return xnn_status_out_of_memory;
593   }
594 
595   node->type = xnn_node_type_prelu;
596   node->num_inputs = 2;
597   node->inputs.raw[0] = input_id;
598   node->inputs.raw[1] = slope_id;
599   node->num_outputs = 1;
600   node->outputs.raw[0] = output_id;
601   node->flags = flags;
602 
603   return xnn_status_success;
604 }
605 
xnn_define_clamp(xnn_subgraph_t subgraph,float output_min,float output_max,uint32_t input_id,uint32_t output_id,uint32_t flags)606 enum xnn_status xnn_define_clamp(
607   xnn_subgraph_t subgraph,
608   float output_min,
609   float output_max,
610   uint32_t input_id,
611   uint32_t output_id,
612   uint32_t flags)
613 {
614   if (!xnn_params.initialized) {
615     xnn_log_error("failed to define Clamp operator: XNNPACK is not initialized");
616     return xnn_status_uninitialized;
617   }
618 
619   if (input_id >= subgraph->num_values) {
620     xnn_log_error(
621       "failed to define Clamp operator with input ID #%" PRIu32 ": invalid Value ID",
622       input_id);
623     return xnn_status_invalid_parameter;
624   }
625 
626   if (output_id >= subgraph->num_values) {
627     xnn_log_error(
628       "failed to define Clamp operator with output ID #%" PRIu32 ": invalid Value ID",
629       output_id);
630     return xnn_status_invalid_parameter;
631   }
632 
633   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
634   if (node == NULL) {
635     return xnn_status_out_of_memory;
636   }
637 
638   node->type = xnn_node_type_clamp;
639   node->activation.output_min = output_min;
640   node->activation.output_max = output_max;
641   node->num_inputs = 1;
642   node->inputs.raw[0] = input_id;
643   node->num_outputs = 1;
644   node->outputs.raw[0] = output_id;
645   node->flags = flags;
646 
647   return xnn_status_success;
648 }
649 
xnn_define_hardswish(xnn_subgraph_t subgraph,uint32_t input_id,uint32_t output_id,uint32_t flags)650 enum xnn_status xnn_define_hardswish(
651   xnn_subgraph_t subgraph,
652   uint32_t input_id,
653   uint32_t output_id,
654   uint32_t flags)
655 {
656   if (!xnn_params.initialized) {
657     xnn_log_error("failed to define HardSwish operator: XNNPACK is not initialized");
658     return xnn_status_uninitialized;
659   }
660 
661   if (input_id >= subgraph->num_values) {
662     xnn_log_error(
663       "failed to define HardSwish operator with input ID #%" PRIu32 ": invalid Value ID",
664       input_id);
665     return xnn_status_invalid_parameter;
666   }
667 
668   if (output_id >= subgraph->num_values) {
669     xnn_log_error(
670       "failed to define HardSwish operator with output ID #%" PRIu32 ": invalid Value ID",
671       output_id);
672     return xnn_status_invalid_parameter;
673   }
674 
675   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
676   if (node == NULL) {
677     return xnn_status_out_of_memory;
678   }
679 
680   node->type = xnn_node_type_hardswish;
681   node->num_inputs = 1;
682   node->inputs.raw[0] = input_id;
683   node->num_outputs = 1;
684   node->outputs.raw[0] = output_id;
685   node->flags = flags;
686 
687   return xnn_status_success;
688 }
689 
xnn_define_sigmoid(xnn_subgraph_t subgraph,uint32_t input_id,uint32_t output_id,uint32_t flags)690 enum xnn_status xnn_define_sigmoid(
691   xnn_subgraph_t subgraph,
692   uint32_t input_id,
693   uint32_t output_id,
694   uint32_t flags)
695 {
696   if (!xnn_params.initialized) {
697     xnn_log_error("failed to define Sigmoid operator: XNNPACK is not initialized");
698     return xnn_status_uninitialized;
699   }
700 
701   if (input_id >= subgraph->num_values) {
702     xnn_log_error(
703       "failed to define Sigmoid operator with input ID #%" PRIu32 ": invalid Value ID",
704       input_id);
705     return xnn_status_invalid_parameter;
706   }
707 
708   if (output_id >= subgraph->num_values) {
709     xnn_log_error(
710       "failed to define Sigmoid operator with output ID #%" PRIu32 ": invalid Value ID",
711       output_id);
712     return xnn_status_invalid_parameter;
713   }
714 
715   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
716   if (node == NULL) {
717     return xnn_status_out_of_memory;
718   }
719 
720   node->type = xnn_node_type_sigmoid;
721   node->num_inputs = 1;
722   node->inputs.raw[0] = input_id;
723   node->num_outputs = 1;
724   node->outputs.raw[0] = output_id;
725   node->flags = flags;
726 
727   return xnn_status_success;
728 }
729 
xnn_define_softmax(xnn_subgraph_t subgraph,uint32_t input_id,uint32_t output_id,uint32_t flags)730 enum xnn_status xnn_define_softmax(
731   xnn_subgraph_t subgraph,
732   uint32_t input_id,
733   uint32_t output_id,
734   uint32_t flags)
735 {
736   if (!xnn_params.initialized) {
737     xnn_log_error("failed to define SoftMax operator: XNNPACK is not initialized");
738     return xnn_status_uninitialized;
739   }
740 
741   if (input_id >= subgraph->num_values) {
742     xnn_log_error(
743       "failed to define SoftMax operator with input ID #%" PRIu32 ": invalid Value ID",
744       input_id);
745     return xnn_status_invalid_parameter;
746   }
747 
748   if (output_id >= subgraph->num_values) {
749     xnn_log_error(
750       "failed to define SoftMax operator with output ID #%" PRIu32 ": invalid Value ID",
751       output_id);
752     return xnn_status_invalid_parameter;
753   }
754 
755   struct xnn_node* node = xnn_subgraph_new_node(subgraph);
756   if (node == NULL) {
757     return xnn_status_out_of_memory;
758   }
759 
760   node->type = xnn_node_type_softmax;
761   node->num_inputs = 1;
762   node->inputs.raw[0] = input_id;
763   node->num_outputs = 1;
764   node->outputs.raw[0] = output_id;
765   node->flags = flags;
766 
767   return xnn_status_success;
768 }
769 
xnn_delete_subgraph(xnn_subgraph_t subgraph)770 enum xnn_status xnn_delete_subgraph(
771   xnn_subgraph_t subgraph)
772 {
773   if (subgraph != NULL) {
774     memset(subgraph->nodes, 0, sizeof(struct xnn_node) * subgraph->num_nodes);
775     xnn_release_memory(subgraph->nodes);
776 
777     memset(subgraph->values, 0, sizeof(struct xnn_value) * subgraph->num_values);
778     xnn_release_memory(subgraph->values);
779 
780     memset(subgraph, 0, sizeof(struct xnn_subgraph));
781     xnn_release_memory(subgraph);
782   }
783   return xnn_status_success;
784 }
785