code: def _binop(relay_op, with_relu=False, fp32_piggy_back=False):
      def qnn_impl(
          lhs,
          rhs,
          input_scale_lhs,
          input_zero_point_lhs,
          input_scale_rhs,
          input_zero_point_rhs,
          output_scale,
          output_zero_point,
      ):
          qnn_out = relay_op(
              lhs,
              rhs,
              input_scale_lhs,
              input_zero_point_lhs,
              input_scale_rhs,
              input_zero_point_rhs,
              output_scale,
              output_zero_point,
          )
          if with_relu:
              clip_min = _get_scalar(output_zero_point)
              return _op.tensor.clip(qnn_out, clip_min, 255)
          return qnn_out
  
      # refer to aten/src/ATen/native/quantized/cpu/{qadd, qmul}.cpp
      # they piggy backs to fp32 math by dequantize -> fp32 math -> quantize
      def torch_impl(
          lhs,
          rhs,
          input_scale_lhs,
          input_zero_point_lhs,
          input_scale_rhs,
          input_zero_point_rhs,
          output_scale,
          output_zero_point,
      ):
          if (
              isinstance(lhs, _expr.Call)
              and lhs.op.name == "qnn.quantize"
          ):
              lhs = lhs.args[0]
          else:
              lhs = relay.qnn.op.dequantize(
                  lhs, input_scale_lhs, input_zero_point_lhs
              )
  
          if (
              isinstance(rhs, _expr.Call)
              and rhs.op.name == "qnn.quantize"
          ):
              rhs = rhs.args[0]
          else:
              rhs = relay.qnn.op.dequantize(
                  rhs, input_scale_rhs, input_zero_point_rhs
              )
          fp32_out = relay_op(lhs, rhs)
  
          if with_relu:
              fp32_out = _op.nn.relu(fp32_out)
  
          return relay.qnn.op.quantize(
              fp32_out,
              output_scale,
              output_zero_point,
              axis=-1,
              out_dtype="uint8",
          )
  
      def _impl(inputs, _):
          lhs = inputs[0]
          rhs = inputs[1]
          output_scale = _expr.const(inputs[2])
          output_zero_point = _expr.const(inputs[3])
          assert (
              len(inputs) == 8
          ), "Input quant params not found in op inputs"
          # Manually added by add_input_quant_params_to_op_inputs above
          input_scale_lhs = _expr.const(inputs[4])
          input_zero_point_lhs = _expr.const(inputs[5])
          input_scale_rhs = _expr.const(inputs[6])
          input_zero_point_rhs = _expr.const(inputs[7])
  
          if fp32_piggy_back:
              logger.info("Piggy backing to FP32 op (PyTorch way)")
              return torch_impl(
                  lhs,
                  rhs,
                  input_scale_lhs,
                  input_zero_point_lhs,
                  input_scale_rhs,
                  input_zero_point_rhs,
                  output_scale,
                  output_zero_point,
              )
  
          return qnn_impl(
              lhs,
              rhs,
              input_scale_lhs,
              input_zero_point_lhs,
              input_scale_rhs,
              input_zero_point_rhs,
              output_scale,
              output_zero_point,
          )
  
      return _impl
  
imports: import numpy
  import tvm
  from tvm import relay
  from tvm.relay import expr
  from tvm.relay import op
  from tvm.relay.frontend.common import infer_shape
  from .common import logger
  from .pytorch_utils import is_version_greater_than
label_desc: Use image node_id 26 for calling a global function with example usage: _binop(relay_op, with_relu, fp32_piggy_back) and returns: _impl, qnn_out, relay, qnn_impl, _op, torch_impl