def op_convert_before_hook(
        self,
        op: Callable,
        args: Tuple[Any, ...],
        kwargs: Dict[str, Any],
        root_module: torch.nn.Module,
    ) -> Tuple[Callable, Tuple[Any, ...], Dict[str, Any]]:
        """
        This function is called before an op call in a converted model.
        For each arg in `args`, quantizes it if necessary.
        Returns potentially modified `op`, potentially modified `args`,
        potentially modified `kwargs`.
        """
        # TODO generalize this for more things
        # currently:
        # * can quantize args (via arg_quant_infos)
        # * can add scale and zp (via additional kwargs)
        arg_quant_infos, any_arg_quant_or_dequant_needed = self.get_op_convert_info(op)
        # Insert mul before nn.Linear for SmoothQuant
        act_key = str(self.idx)
        if act_key in self.idx_to_smooth_quant_scaling_factor:
            act_scaling_factors = self.idx_to_smooth_quant_scaling_factor[act_key]
            # if users modifies qconf.json and cancals quantization of the linear,
            # then any_arg_quant_or_dequant_needed[0] is False. Don't insert mul in this case.
            if act_scaling_factors is not None and any_arg_quant_or_dequant_needed[0]:
                w_key = str(self.idx) + "_0"
                act_scaling_factors = (
                    act_scaling_factors[w_key]
                    if len(act_scaling_factors) > 1
                    else next(iter(act_scaling_factors.values()))
                )
                # update arg_quant_infos
                if isinstance(arg_quant_infos[0][0], dict):
                    scale = (
                        arg_quant_infos[0][0][w_key]
                        if len(arg_quant_infos[0][0]) > 1
                        else next(iter(arg_quant_infos[0][0].values()))
                    )
                    zp = (
                        arg_quant_infos[0][1][w_key]
                        if len(arg_quant_infos[0][1]) > 1
                        else next(iter(arg_quant_infos[0][1].values()))
                    )
                else:
                    # For backward compatibility
                    assert isinstance(arg_quant_infos[0][0], torch.Tensor)
                    scale = arg_quant_infos[0][0]
                    zp = arg_quant_infos[0][1]
                arg_quant_infos = [(scale, zp, arg_quant_infos[0][2])]
                args = list(args)
                new_act = torch.mul(args[0], act_scaling_factors)
                args[0] = new_act
        args = iterate_and_apply_convert(
            args, arg_quant_infos, any_arg_quant_or_dequant_needed, op
        )
        return op, args, kwargs

        This function is called before an op call in a converted model.
        For each arg in `args`, quantizes it if necessary.
        Returns potentially modified `op`, potentially modified `args`,
        potentially modified `kwargs`.
        
intel_extension_for_pytorch/quantization/_quantization_state.py