| 73 | } |
| 74 | |
| 75 | TfLiteStatus Prepare8BitSubOp(TfLiteContext* context, |
| 76 | const TfLiteTensor* input_1, |
| 77 | const TfLiteTensor* input_2, TfLiteTensor* output, |
| 78 | TfLiteSubParams* params, OpData* op_params, |
| 79 | int op_sign) { |
| 80 | TF_LITE_ENSURE(context, |
| 81 | output->type == kTfLiteUInt8 || output->type == kTfLiteInt8); |
| 82 | const auto& input1_quantization_params = input_1->params; |
| 83 | const auto& input2_quantization_params = input_2->params; |
| 84 | const auto& output_quantization_params = output->params; |
| 85 | int32_t integer_type_min = 0; |
| 86 | int32_t integer_type_max = 0; |
| 87 | if (output->type == kTfLiteUInt8) { |
| 88 | integer_type_min = std::numeric_limits<uint8_t>::min(); |
| 89 | integer_type_max = std::numeric_limits<uint8_t>::max(); |
| 90 | } else { |
| 91 | // output->type == kTfLiteInt8 |
| 92 | integer_type_min = std::numeric_limits<int8_t>::min(); |
| 93 | integer_type_max = std::numeric_limits<int8_t>::max(); |
| 94 | } |
| 95 | |
| 96 | TF_LITE_ENSURE(context, |
| 97 | input1_quantization_params.zero_point >= integer_type_min); |
| 98 | TF_LITE_ENSURE(context, |
| 99 | input1_quantization_params.zero_point <= integer_type_max); |
| 100 | TF_LITE_ENSURE(context, |
| 101 | input2_quantization_params.zero_point >= integer_type_min); |
| 102 | TF_LITE_ENSURE(context, |
| 103 | input2_quantization_params.zero_point <= integer_type_max); |
| 104 | TF_LITE_ENSURE(context, |
| 105 | output_quantization_params.zero_point >= integer_type_min); |
| 106 | TF_LITE_ENSURE(context, |
| 107 | output_quantization_params.zero_point <= integer_type_max); |
| 108 | |
| 109 | op_params->input1_offset = -input1_quantization_params.zero_point; |
| 110 | op_params->input2_offset = -input2_quantization_params.zero_point; |
| 111 | op_params->output_offset = output_quantization_params.zero_point; |
| 112 | op_params->left_shift = 20; |
| 113 | const double twice_max_input_scale = |
| 114 | 2 * std::max(input1_quantization_params.scale, |
| 115 | input2_quantization_params.scale); |
| 116 | const double real_input1_multiplier = |
| 117 | input1_quantization_params.scale / twice_max_input_scale; |
| 118 | const double real_input2_multiplier = |
| 119 | input2_quantization_params.scale / twice_max_input_scale; |
| 120 | const double real_output_multiplier = |
| 121 | twice_max_input_scale / |
| 122 | ((1 << op_params->left_shift) * output_quantization_params.scale); |
| 123 | |
| 124 | tflite::QuantizeMultiplierSmallerThanOneExp(real_input1_multiplier, |
| 125 | &op_params->input1_multiplier, |
| 126 | &op_params->input1_shift); |
| 127 | tflite::QuantizeMultiplierSmallerThanOneExp(real_input2_multiplier, |
| 128 | &op_params->input2_multiplier, |
| 129 | &op_params->input2_shift); |
| 130 | op_params->input2_multiplier *= op_sign; |
| 131 | tflite::QuantizeMultiplierSmallerThanOneExp(real_output_multiplier, |
| 132 | &op_params->output_multiplier, |
no test coverage detected