| 273 | |
| 274 | template <KernelType kernel_type> |
| 275 | void EvalQuantized(TfLiteContext* context, TfLiteNode* node, |
| 276 | TfLiteSubParams* params, const OpData* data, |
| 277 | const TfLiteTensor* input1, const TfLiteTensor* input2, |
| 278 | TfLiteTensor* output) { |
| 279 | tflite::ArithmeticParams op_params; |
| 280 | op_params.left_shift = data->left_shift; |
| 281 | op_params.input1_offset = data->input1_offset; |
| 282 | op_params.input1_multiplier = data->input1_multiplier; |
| 283 | op_params.input1_shift = data->input1_shift; |
| 284 | op_params.input2_offset = data->input2_offset; |
| 285 | op_params.input2_multiplier = data->input2_multiplier; |
| 286 | op_params.input2_shift = data->input2_shift; |
| 287 | op_params.output_offset = data->output_offset; |
| 288 | op_params.output_multiplier = data->output_multiplier; |
| 289 | op_params.output_shift = data->output_shift; |
| 290 | SetActivationParams(data->output_activation_min, data->output_activation_max, |
| 291 | &op_params); |
| 292 | |
| 293 | const bool need_broadcast = optimized_ops::ProcessBroadcastShapes( |
| 294 | GetTensorShape(input1), GetTensorShape(input2), &op_params); |
| 295 | |
| 296 | #define TF_LITE_SUB(type, opname, data_type) \ |
| 297 | type::opname(op_params, GetTensorShape(input1), \ |
| 298 | GetTensorData<data_type>(input1), GetTensorShape(input2), \ |
| 299 | GetTensorData<data_type>(input2), GetTensorShape(output), \ |
| 300 | GetTensorData<data_type>(output)) |
| 301 | // NOTE: We are using the add kernels. This is possible as the second values |
| 302 | // multiplier is negated before being passed down. |
| 303 | if (output->type == kTfLiteInt8) { |
| 304 | if (need_broadcast) { |
| 305 | TF_LITE_SUB(reference_integer_ops, BroadcastAdd4DSlow, int8_t); |
| 306 | } else { |
| 307 | TF_LITE_SUB(reference_integer_ops, Add, int8_t); |
| 308 | } |
| 309 | } else if (output->type == kTfLiteUInt8) { |
| 310 | if (kernel_type == kReference) { |
| 311 | if (need_broadcast) { |
| 312 | TF_LITE_SUB(reference_ops, BroadcastAdd4DSlow, uint8_t); |
| 313 | } else { |
| 314 | TF_LITE_SUB(reference_ops, Add, uint8_t); |
| 315 | } |
| 316 | } else { |
| 317 | if (op_params.broadcast_category == |
| 318 | BroadcastableOpCategory::kGenericBroadcast) { |
| 319 | TF_LITE_SUB(optimized_ops, BroadcastAdd4DSlow, uint8_t); |
| 320 | } else if (need_broadcast) { |
| 321 | TF_LITE_SUB(optimized_ops, BroadcastAddFivefold, uint8_t); |
| 322 | } else { |
| 323 | TF_LITE_SUB(optimized_ops, Add, uint8_t); |
| 324 | } |
| 325 | } |
| 326 | } else { |
| 327 | if (kernel_type == kReference) { |
| 328 | if (need_broadcast) { |
| 329 | TF_LITE_SUB(reference_ops, BroadcastSub4DSlow, int16_t); |
| 330 | } else { |
| 331 | TF_LITE_SUB(reference_ops, Sub16, int16_t); |
| 332 | } |
no test coverage detected