TfLiteStatus EvalQuantized(TfLiteContext* context, TfLiteNode* node,
                           TfLiteMulParams* params, const OpData* data,
                           const TfLiteTensor* input1,
                           const TfLiteTensor* input2, TfLiteTensor* output) {
  if (input1->type == input2->type && input1->type == output->type &&
      (input1->type == kTfLiteUInt8 || input1->type == kTfLiteInt8 ||
       input1->type == kTfLiteInt16)) {
    tflite::ArithmeticParams op_params;
    SetActivationParams(data->output_activation_min,
                        data->output_activation_max, &op_params);
    op_params.input1_offset = -input1->params.zero_point;
    op_params.input2_offset = -input2->params.zero_point;
    op_params.output_offset = output->params.zero_point;
    op_params.output_multiplier = data->output_multiplier;
    op_params.output_shift = data->output_shift;
    bool need_broadcast = optimized_ops::ProcessBroadcastShapes(
        GetTensorShape(input1), GetTensorShape(input2), &op_params);
#define TF_LITE_MUL(type, opname, dtype)                             \
  type::opname(op_params, GetTensorShape(input1),                    \
               GetTensorData<dtype>(input1), GetTensorShape(input2), \
               GetTensorData<dtype>(input2), GetTensorShape(output), \
               GetTensorData<dtype>(output))
    if (input1->type == kTfLiteInt8) {
      if (kernel_type == kReference) {
        if (need_broadcast) {
          TF_LITE_MUL(reference_integer_ops, BroadcastMul4DSlow, int8_t);
        } else {
          TF_LITE_MUL(reference_integer_ops, Mul, int8_t);
        }
      } else {
        if (need_broadcast) {
          TF_LITE_MUL(optimized_integer_ops, BroadcastMulDispatch, int8_t);
        } else {
          TF_LITE_MUL(optimized_integer_ops, Mul, int8_t);
        }
      }
    } else if (input1->type == kTfLiteInt16) {
      // We have this check, because in case of int16
      // input1_val*input2_val can overflow int32:
      // see MulElementwise -
      // tensorflow/lite/kernels/internal/reference/integer_ops/mul.h in case of
      // 16-bit this function is used in symmetric quantization, so offset
      // should be zero.
      TF_LITE_ENSURE_EQ(context, op_params.input1_offset, 0.0);
      TF_LITE_ENSURE_EQ(context, op_params.input2_offset, 0.0);
      TF_LITE_ENSURE_EQ(context, op_params.output_offset, 0.0);

      if (need_broadcast) {
        TF_LITE_MUL(reference_integer_ops, BroadcastMul4DSlow, int16_t);
      } else {
        TF_LITE_MUL(reference_integer_ops, Mul, int16_t);
      }
    } else {
      // type == kTfLiteUInt8
      if (kernel_type == kReference) {
        if (need_broadcast) {
          TF_LITE_MUL(reference_ops, BroadcastMul4DSlow, uint8_t);
        } else {
          TF_LITE_MUL(reference_ops, Mul, uint8_t);
        }
      } else {
        if (need_broadcast) {
          TF_LITE_MUL(optimized_ops, BroadcastMulDispatch, uint8_t);
        } else {
          TF_LITE_MUL(optimized_ops, Mul, uint8_t);
        }
      }
    }
#undef TF_LITE_MUL
  } else if (input1->type == kTfLiteInt16 && input2->type == kTfLiteInt16 &&
             (output->type == kTfLiteUInt8 || output->type == kTfLiteInt8)) {
#define TF_LITE_MUL(type, opname, output_dtype)                        \
  tflite::ArithmeticParams op_params;                                  \
  SetActivationParams(data->output_activation_min,                     \
                      data->output_activation_max, &op_params);        \
  op_params.output_offset = output->params.zero_point;                 \
  type::opname(op_params, GetTensorShape(input1),                      \
               GetTensorData<int16_t>(input1), GetTensorShape(input2), \
               GetTensorData<int16_t>(input2), GetTensorShape(output), \
               GetTensorData<output_dtype>(output))
    if (output->type == kTfLiteInt8) {
      TF_LITE_MUL(reference_integer_ops, Mul, int8_t);
    } else {
      if (kernel_type == kReference) {
        TF_LITE_MUL(reference_ops, Mul, uint8_t);
      } else {
        TF_LITE_MUL(optimized_ops, Mul, uint8_t);
      }
    }
#undef TF_LITE_MUL
  } else {
    context->ReportError(
        context, "Unsupported combination of input and output types in Mul.");
    return kTfLiteError;
  }
  return kTfLiteOk;
}