def _adjust_main_inputs(func):
    """
    Adjust the inputs in main func.

    If the input's dtype is not in Core ML I/O supported types, we do following steps:
        1. Change the input's dtype to int32 or fp32 based on original dtype.
        2. If the original dtype is supported in Core ML Runtime, we insert a cast op to cast the
           input from the changed dtype to the original dtype.
    """
    _IO_SUPPORTED_TYPES = _get_io_supported_types(func.opset_version, func.input_types)
    _RUNTIME_SUPPORTED_TYPES = _get_runtime_supported_types(func.opset_version)

    for input_name, input_var in func.inputs.items():
        if (
            types.is_tensor(input_var.sym_type) or types.is_scalar(input_var.sym_type)
        ) and input_var.dtype not in _IO_SUPPORTED_TYPES:
            input_dtype_str = types.builtin_to_string(input_var.dtype)
            convert_to_dtype = types.int32 if types.is_int(input_var.dtype) else types.fp32
            convert_to_dtype_str = types.builtin_to_string(convert_to_dtype)
            should_insert_cast = input_var.dtype in _RUNTIME_SUPPORTED_TYPES
            _adjust_var_dtype_helper(input_var, convert_to_dtype)
            human_readable_supported_types = list(
                map(types.builtin_to_string, _IO_SUPPORTED_TYPES)
            )
            logger.warning(
                f"\nInput '{input_var.name}' is of dtype {input_dtype_str}. The Core ML I/O does "
                f"not support this dtype (supported dtypes are: {human_readable_supported_types}). Consider "
                f"setting `minimum_deployment_target` to a higher IOS version for more supported "
                f"dtypes. This input is changed to {convert_to_dtype_str}.\n"
            )

            if not should_insert_cast:
                human_readable_supported_types = list(
                    map(types.builtin_to_string, _RUNTIME_SUPPORTED_TYPES)
                )
                logger.warning(
                    f"The original input dtype {input_dtype_str} is not supported in "
                    f"Core ML Runtime (supported dtypes are: {human_readable_supported_types}). Consider "
                    f"setting `minimum_deployment_target` to a higher IOS version for more "
                    f"supported dtypes. We just changed the dtype and won't insert any cast op."
                )
                continue

            logger.warning(
                f"Trying to insert a cast op at the beginning of the program to convert "
                f"the input to the originally defined dtype ({input_dtype_str}).\n"
            )
            try:
                first_op = func.operations[0] if len(func.operations) > 0 else None
                casted_input_var = mb.cast(x=input_var, dtype=input_dtype_str, before_op=first_op)
                # Use force replace as the `input_var.dtype` could be not subtype of the
                # `convert_to_dtype`. For example, int16 cast to int32. As it's only for input
                # dtype cast, this replace should be safe.
                func.replace_uses_of_var_after_op(
                    anchor_op=casted_input_var.op,
                    old_var=input_var,
                    new_var=casted_input_var,
                    force_replace=True,
                    no_check_var_types=True,
                )
            except Exception as e:
                logger.warning(
                    f"Failed to insert the cast op.\n{e}\nThe dtype of the input "
                    f"'{input_var.name}' is changed to {convert_to_dtype_str} without "
                    f"inserting any cast op."
                )

    Adjust the inputs in main func.

    If the input's dtype is not in Core ML I/O supported types, we do following steps:
        1. Change the input's dtype to int32 or fp32 based on original dtype.
        2. If the original dtype is supported in Core ML Runtime, we insert a cast op to cast the
           input from the changed dtype to the original dtype.
    
coremltools/converters/mil/backend/mil/passes/adjust_io_to_supported_types.py