code: def helper_change_dtypes_to_uint8_int8(
      attrs, inputs, types, relay_op
  ):
      """Legalizes QNN conv2d/dense op for Intel HW. VNNI supports u8 x i8 fast conv/MM. If the dtypes
      are already good, we dont transform. Else, we shift the tensor values and zero points to change
      the dtype.
  
      Converting from int8 to uint8 can be done in following manner.
  
      Original equation
        scale * (QA - zp_a)
        scale * (QA + 128 - 128 - zp_a)
        scale * ( (QA + 128) - (zp_a + 128))
  
      Replacing QA + 128 with QA' and (zp_a + 128) with zp_a'
      We get our new quantized uint8 tensor - scale * (QA' - zp_a')
  
      Similarly we can convert from uint8 to int8.
  
      Parameters
      ----------
      attrs : tvm.ir.Attrs
          Attributes of current convolution
      inputs : list of tvm.relay.Expr
          The args of the Relay expr to be legalized
      types : list of types
          List of input and output types
  
      Returns
      -------
      result : tvm.relay.Expr
          The legalized expr
      """
      # Collect the dtypes.
      data_dtype = types[0].dtype
      kernel_dtype = types[1].dtype
  
      # Collect the input exprs.
      (
          data,
          kernel,
          input_zero_point,
          kernel_zero_point,
          input_scale,
          kernel_scale,
      ) = inputs
  
      # VNNI supports u8 x i8 fast conv/MM. Don't do anything if it is already satisfied.
      if data_dtype == "uint8" and kernel_dtype == "int8":
          return None
  
      # Shift input if necessary.
      if data_dtype == "int8":
          # Compute (QA + 128) and (zp_a + 128)
          data, input_zero_point = _shift(
              data, input_zero_point, "uint8"
          )
  
      # Shift kernel if necessary.
      if kernel_dtype == "uint8":
          # Compute (QA - 128) and (zp_a - 128)
          kernel, kernel_zero_point = _shift(
              kernel, kernel_zero_point, "int8"
          )
  
      # Call qnn.conv2d with modified inputs and zero points.
      new_attrs = {k: attrs[k] for k in attrs.keys()}
      return relay_op(
          data,
          kernel,
          input_zero_point,
          kernel_zero_point,
          input_scale,
          kernel_scale,
          **new_attrs,
      )
  
imports: import numpy
  from scipy import special
  import tvm
  from tvm import relay
  from tvm._ffi.base import TVMError
  from tvm.relay.qnn.op.canonicalizations import create_integer_lookup_op
  from ....target.x86 import target_has_features
  from ....topi.utils import is_target
  from ..None import op
label_desc: Use image node_id 12 for calling a global function with example usage: helper_change_dtypes_to_uint8_int8(attrs, inputs, types, relay_op) and returns: relay_op, None