def test_float16_input_output(self, opset_version):
        """
        Input graph:

        main(%x: (1, 1, 1, 1, fp16)(Tensor)) {
            block0() {
                %relu_0: (1, 1, 1, 1, fp16)(Tensor) = relu(x=%x, name="relu_0")
            } -> (%relu_0)
        }

        Output graph (if opset_version < ios16):

        main(%x: (1, 1, 1, 1, fp32)(Tensor)) {
            block0() {
                %cast_0: (1, 1, 1, 1, fp16)(Tensor) = cast(x=%x, dtype="fp16", name="cast_0")
                %relu_0__pre__output__fp32__cast: (1, 1, 1, 1, fp16)(Tensor) = relu(x=%cast_0, name="relu_0")
                %relu_0: (1, 1, 1, 1, fp32)(Tensor) = cast(x=%relu_0__pre__output__fp32__cast, dtype="fp32", name="cast_1")
            } -> (%relu_0)
        }

        Output graph (if opset_version >= ios16): same as the input graph
        """
        @mb.program(input_specs=[mb.TensorSpec(shape=(1, 1, 1, 1), dtype=types.fp16)], opset_version=opset_version)
        def prog(x):
            return mb.relu(x=x)

        skip_type_check = opset_version in [None, ct.target.iOS13]
        prev_prog, prev_block, block = apply_pass_and_basic_check(
            prog,
            "mil_backend::adjust_io_to_supported_types",
            skip_output_type_check=skip_type_check,
            skip_input_type_check=skip_type_check,
        )

        prev_inputs = list(prev_block.inputs.items())
        inputs = list(block.inputs.items())
        prev_outputs = prev_block.outputs
        outputs = block.outputs
        assert prev_inputs[0][1].name == inputs[0][1].name
        assert outputs[0].name == prev_outputs[0].name
        if opset_version is None or opset_version < target.iOS16:
            assert get_op_types_in_program(prog) == ['cast', 'relu', 'cast']
            assert inputs[0][1].dtype == types.fp32
            assert outputs[0].dtype == types.fp32
        else:
            assert get_op_types_in_program(prog) == ['relu']
            assert inputs[0][1].dtype == types.fp16
            assert block.outputs[0].dtype == types.fp16

        Input graph:

        main(%x: (1, 1, 1, 1, fp16)(Tensor)) {
            block0() {
                %relu_0: (1, 1, 1, 1, fp16)(Tensor) = relu(x=%x, name="relu_0")
            } -> (%relu_0)
        }

        Output graph (if opset_version < ios16):

        main(%x: (1, 1, 1, 1, fp32)(Tensor)) {
            block0() {
                %cast_0: (1, 1, 1, 1, fp16)(Tensor) = cast(x=%x, dtype="fp16", name="cast_0")
                %relu_0__pre__output__fp32__cast: (1, 1, 1, 1, fp16)(Tensor) = relu(x=%cast_0, name="relu_0")
                %relu_0: (1, 1, 1, 1, fp32)(Tensor) = cast(x=%relu_0__pre__output__fp32__cast, dtype="fp32", name="cast_1")
            } -> (%relu_0)
        }

        Output graph (if opset_version >= ios16): same as the input graph
        
coremltools/converters/mil/backend/mil/passes/test_passes.py