TfLiteStatus PrepareInt16SubOpPOT(TfLiteContext* context,
                                  const TfLiteTensor* input1,
                                  const TfLiteTensor* input2,
                                  TfLiteTensor* output, TfLiteSubParams* params,
                                  OpData* data) {
  // 16bit -> 16bit special quantized path, supporting only a rather
  // narrow case of quantization parameters: zero_points must all be 0
  // ("symmetric quantization") and scales must be power-of-two (which
  // we abbreviate as "POT" below). The intended use case for this path
  // is in LSTM cells, where, due to the constraints of implementing
  // some of the math in these LSTM cells in fixed-point arithmetic,
  // we need to have such symmetric, power-of-two quantization
  // (Fixed-point formats are inherently symmetric, power-of-two).
  TF_LITE_ENSURE_EQ(context, input1->params.zero_point, 0);
  TF_LITE_ENSURE_EQ(context, input2->params.zero_point, 0);
  TF_LITE_ENSURE_EQ(context, output->params.zero_point, 0);

  int input1_scale_log2_rounded;
  bool input1_scale_is_pot =
      CheckedLog2(input1->params.scale, &input1_scale_log2_rounded);
  TF_LITE_ENSURE(context, input1_scale_is_pot);

  int input2_scale_log2_rounded;
  bool input2_scale_is_pot =
      CheckedLog2(input2->params.scale, &input2_scale_log2_rounded);
  TF_LITE_ENSURE(context, input2_scale_is_pot);

  int output_scale_log2_rounded;
  bool output_scale_is_pot =
      CheckedLog2(output->params.scale, &output_scale_log2_rounded);
  TF_LITE_ENSURE(context, output_scale_is_pot);

  data->input1_shift = input1_scale_log2_rounded - output_scale_log2_rounded;
  data->input2_shift = input2_scale_log2_rounded - output_scale_log2_rounded;

  // Shifting of one input is supported. The graph quantization should ensure
  // that the other input matches the output.
  TF_LITE_ENSURE(context, data->input1_shift == 0 || data->input2_shift == 0);
  TF_LITE_ENSURE(context, data->input1_shift <= 0);
  TF_LITE_ENSURE(context, data->input2_shift <= 0);

  TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized(
      context, params->activation, output, &data->output_activation_min,
      &data->output_activation_max));
  return kTfLiteOk;
}
TfLiteStatus PrepareInt16SubOpPOT(TfLiteContext* context,
                                  const TfLiteTensor* input1,
                                  const TfLiteTensor* input2,
                                  TfLiteTensor* output, TfLiteSubParams* params,
                                  OpData* data) {
   
   
   
   
   
   
   
   
  TF_LITE_ENSURE_EQ(context, input1->params.zero_point, 0);
  TF_LITE_ENSURE_EQ(context, input2->params.zero_point, 0);
  TF_LITE_ENSURE_EQ(context, output->params.zero_point, 0);

  int input1_scale_log2_rounded;
  bool input1_scale_is_pot =
      CheckedLog2(input1->params.scale, &input1_scale_log2_rounded);
  TF_LITE_ENSURE(context, input1_scale_is_pot);

  int input2_scale_log2_rounded;
  bool input2_scale_is_pot =
      CheckedLog2(input2->params.scale, &input2_scale_log2_rounded);
  TF_LITE_ENSURE(context, input2_scale_is_pot);

  int output_scale_log2_rounded;
  bool output_scale_is_pot =
      CheckedLog2(output->params.scale, &output_scale_log2_rounded);
  TF_LITE_ENSURE(context, output_scale_is_pot);

  data->input1_shift = input1_scale_log2_rounded - output_scale_log2_rounded;
  data->input2_shift = input2_scale_log2_rounded - output_scale_log2_rounded;

   
   
  TF_LITE_ENSURE(context, data->input1_shift == 0 || data->input2_shift == 0);
  TF_LITE_ENSURE(context, data->input1_shift <= 0);
  TF_LITE_ENSURE(context, data->input2_shift <= 0);

  TF_LITE_ENSURE_STATUS(CalculateActivationRangeQuantized(
      context, params->activation, output, &data->output_activation_min,
      &data->output_activation_max));
  return kTfLiteOk;
}