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
11 #include <xnnpack.h>
12 #include <xnnpack/log.h>
13 #include <xnnpack/operator.h>
14 #include <xnnpack/params.h>
15 #include <xnnpack/subgraph.h>
16 #include <xnnpack/subgraph-validation.h>
17
create_abs_operator(const struct xnn_node * node,const struct xnn_value * values,size_t num_values,struct xnn_operator_data * opdata,const struct xnn_caches * caches)18 static enum xnn_status create_abs_operator(
19 const struct xnn_node* node,
20 const struct xnn_value* values,
21 size_t num_values,
22 struct xnn_operator_data* opdata,
23 const struct xnn_caches* caches)
24 {
25 assert(node->num_inputs == 1);
26 const uint32_t input_id = node->inputs[0];
27 assert(input_id != XNN_INVALID_VALUE_ID);
28 assert(input_id < num_values);
29
30 assert(node->num_outputs == 1);
31 const uint32_t output_id = node->outputs[0];
32 assert(output_id != XNN_INVALID_VALUE_ID);
33 assert(output_id < num_values);
34
35 const size_t num_input_dims = values[input_id].shape.num_dims;
36 const size_t channel_dim = num_input_dims == 0 ? 1 : values[input_id].shape.dim[num_input_dims - 1];
37
38 enum xnn_status status;
39 switch (node->compute_type) {
40 case xnn_compute_type_fp32:
41 status = xnn_create_abs_nc_f32(
42 channel_dim /* channels */, channel_dim /* input stride */, channel_dim /* output stride */,
43 node->flags,
44 &opdata->operator_objects[0]);
45 break;
46 #ifndef XNN_NO_F16_OPERATORS
47 case xnn_compute_type_fp16:
48 status = xnn_create_abs_nc_f16(
49 channel_dim /* channels */, channel_dim /* input stride */, channel_dim /* output stride */,
50 node->flags,
51 &opdata->operator_objects[0]);
52 break;
53 #endif // !defined(XNN_NO_F16_OPERATORS)
54 default:
55 XNN_UNREACHABLE;
56 }
57 if (status == xnn_status_success) {
58 opdata->batch_size = xnn_shape_multiply_non_channel_dims(&values[input_id].shape);
59 opdata->inputs[0] = input_id;
60 opdata->outputs[0] = output_id;
61 }
62 return status;
63 }
64
setup_abs_operator(const struct xnn_operator_data * opdata,const struct xnn_blob * blobs,size_t num_blobs,pthreadpool_t threadpool)65 static enum xnn_status setup_abs_operator(
66 const struct xnn_operator_data* opdata,
67 const struct xnn_blob* blobs,
68 size_t num_blobs,
69 pthreadpool_t threadpool)
70 {
71 const uint32_t input_id = opdata->inputs[0];
72 assert(input_id != XNN_INVALID_VALUE_ID);
73 assert(input_id < num_blobs);
74
75 const uint32_t output_id = opdata->outputs[0];
76 assert(output_id != XNN_INVALID_VALUE_ID);
77 assert(output_id < num_blobs);
78
79 const struct xnn_blob* input_blob = blobs + input_id;
80 const void* input_data = input_blob->data;
81 assert(input_data != NULL);
82
83 const struct xnn_blob* output_blob = blobs + output_id;
84 void* output_data = output_blob->data;
85 assert(output_data != NULL);
86
87 switch (opdata->operator_objects[0]->type) {
88 case xnn_operator_type_abs_nc_f32:
89 return xnn_setup_abs_nc_f32(
90 opdata->operator_objects[0],
91 opdata->batch_size,
92 input_data,
93 output_data,
94 threadpool);
95 #ifndef XNN_NO_F16_OPERATORS
96 case xnn_operator_type_abs_nc_f16:
97 return xnn_setup_abs_nc_f16(
98 opdata->operator_objects[0],
99 opdata->batch_size,
100 input_data,
101 output_data,
102 threadpool);
103 #endif // !defined(XNN_NO_F16_OPERATORS)
104 default:
105 XNN_UNREACHABLE;
106 }
107 }
108
xnn_define_abs(xnn_subgraph_t subgraph,uint32_t input_id,uint32_t output_id,uint32_t flags)109 enum xnn_status xnn_define_abs(
110 xnn_subgraph_t subgraph,
111 uint32_t input_id,
112 uint32_t output_id,
113 uint32_t flags)
114 {
115 enum xnn_status status;
116 if ((status = xnn_subgraph_check_xnnpack_initialized(xnn_node_type_abs)) != xnn_status_success) {
117 return status;
118 }
119
120 if ((status = xnn_subgraph_check_input_node_id(xnn_node_type_abs, input_id, subgraph->num_values)) != xnn_status_success) {
121 return status;
122 }
123
124 const struct xnn_value* input_value = &subgraph->values[input_id];
125 status = xnn_subgraph_check_input_type_dense(xnn_node_type_abs, input_id, input_value);
126 if (status != xnn_status_success) {
127 return status;
128 }
129
130 switch (input_value->datatype) {
131 case xnn_datatype_fp32:
132 break;
133 default:
134 xnn_log_error(
135 "failed to define %s operator with input ID #%" PRIu32 ": unsupported Value datatype %s (%d)",
136 xnn_node_type_to_string(xnn_node_type_abs), input_id,
137 xnn_datatype_to_string(input_value->datatype), input_value->datatype);
138 return xnn_status_invalid_parameter;
139 }
140
141 status = xnn_subgraph_check_output_node_id(xnn_node_type_abs, output_id, subgraph->num_values);
142 if (status != xnn_status_success) {
143 return status;
144 }
145
146 const struct xnn_value* output_value = &subgraph->values[output_id];
147 status = xnn_subgraph_check_output_type_dense(xnn_node_type_abs, output_id, output_value);
148 if (status != xnn_status_success) {
149 return status;
150 }
151
152 switch (output_value->datatype) {
153 case xnn_datatype_fp32:
154 break;
155 default:
156 xnn_log_error(
157 "failed to define %s operator with output ID #%" PRIu32 ": unsupported Value datatype %s (%d)",
158 xnn_node_type_to_string(xnn_node_type_abs), output_id,
159 xnn_datatype_to_string(output_value->datatype), output_value->datatype);
160 return xnn_status_invalid_parameter;
161 }
162
163 struct xnn_node* node = xnn_subgraph_new_node(subgraph);
164 if (node == NULL) {
165 return xnn_status_out_of_memory;
166 }
167
168 node->type = xnn_node_type_abs;
169 node->compute_type = xnn_compute_type_fp32;
170 node->num_inputs = 1;
171 node->inputs[0] = input_id;
172 node->num_outputs = 1;
173 node->outputs[0] = output_id;
174 node->flags = flags;
175
176 node->create = create_abs_operator;
177 node->setup = setup_abs_operator;
178
179 return xnn_status_success;
180 }
181