def test_cast_ops_fuse_across_block_smoke_3(self):
        """
        Input graph:
        main[CoreML7](%x: (1,int32)(Tensor)) {
          block0() {
            %cast_0: (1,fp32)(Tensor) = cast(x=%x, dtype="fp32", name="cast_0")
            %cond_0: (1,uint8)(Tensor) = cond(pred=True, name="cond_0")
              cond_0_true() {
                %cast_1: (1,int32)(Tensor) = cast(x=%cast_0, dtype="int32", name="cast_1")
                %cast_2: (1,uint8)(Tensor) = cast(x=%cast_1, dtype="uint8", name="cast_2")
                %cast_3: (1,fp32)(Tensor) = cast(x=%cast_2, dtype="fp32", name="cast_3")
                %cast_4: (1,uint8)(Tensor) = cast(x=%cast_3, dtype="uint8", name="cast_4")
              } -> (%cast_4)
              cond_0_false() {
                %cast_5: (1,int8)(Tensor) = cast(x=%cast_0, dtype="int8", name="cast_5")
                %cast_6: (1,bool)(Tensor) = cast(x=%cast_5, dtype="bool", name="cast_6")
                %cast_7: (1,uint8)(Tensor) = cast(x=%cast_6, dtype="uint8", name="cast_7")
              } -> (%cast_7)
          } -> (%cond_0)
        }

        Output graph:
        main[CoreML7](%x: (1,int32)(Tensor)) {
          block0() {
            %cond_0: (1,uint8)(Tensor) = cond(pred=True, name="cond_0")
              cond_0_true() {
                %x_to_uint8: (1,uint8)(Tensor) = cast(x=%x, dtype="uint8", name="x_to_uint8")
              } -> (%x_to_uint8)
              cond_0_false() {
                %x_to_bool: (1,bool)(Tensor) = cast(x=%x, dtype="bool", name="x_to_bool")
                %cast_7: (1,uint8)(Tensor) = cast(x=%x_to_bool, dtype="uint8", name="cast_7")
              } -> (%cast_7)
          } -> (%cond_0)
        }

        This is a more complex example:
        First, in the true branch, 4 ``cast`` ops are optimized into a single ``cast(dtype="uint8")``. In the false branch, 3 ``cast`` ops are optimized to ``cast(dtype="bool")->cast(dtype="uint8")``
        Second, the first ``cast`` op in each inner block is fused with the outer ``cast_0`` op, resulting in the above output graph.
        """

        @mb.program(
            input_specs=[mb.TensorSpec(shape=(1,), dtype=types.int32)],
            opset_version=ct.target.iOS17,
        )
        def prog(x):
            x = mb.cast(x=x, dtype="fp32")

            def _true_fn():
                x1 = mb.cast(x=x, dtype="int32")
                x1 = mb.cast(x=x1, dtype="uint8")
                x1 = mb.cast(x=x1, dtype="fp32")
                return mb.cast(x=x1, dtype="uint8")

            def _false_fn():
                x2 = mb.cast(x=x, dtype="int8")
                x2 = mb.cast(x=x2, dtype="bool")
                return mb.cast(x=x2, dtype="uint8")

            return mb.cond(pred=True, _true_fn=_true_fn, _false_fn=_false_fn)

        _, _, block = apply_pass_and_basic_check(prog, "common::cast_optimization")
        _, _, block = apply_pass_and_basic_check(prog, "common::dead_code_elimination")

        assert get_op_types_in_program(prog) == ["cond"]

        cond_op = block.find_ops(op_type="cond")[0]
        true_block, false_block = cond_op.blocks
        assert get_op_types_in_block(true_block) == ["cast"]
        assert get_op_types_in_block(false_block) == ["cast"] * 2

        expected_true_branch_types = ["uint8"]
        expected_false_branch_types = ["bool", "uint8"]

        assert expected_true_branch_types == [
            v.dtype.val for v in true_block.find_ops(op_type="cast")
        ]
        assert expected_false_branch_types == [
            v.dtype.val for v in false_block.find_ops(op_type="cast")
        ]

        Input graph:
        main[CoreML7](%x: (1,int32)(Tensor)) {
          block0() {
            %cast_0: (1,fp32)(Tensor) = cast(x=%x, dtype="fp32", name="cast_0")
            %cond_0: (1,uint8)(Tensor) = cond(pred=True, name="cond_0")
              cond_0_true() {
                %cast_1: (1,int32)(Tensor) = cast(x=%cast_0, dtype="int32", name="cast_1")
                %cast_2: (1,uint8)(Tensor) = cast(x=%cast_1, dtype="uint8", name="cast_2")
                %cast_3: (1,fp32)(Tensor) = cast(x=%cast_2, dtype="fp32", name="cast_3")
                %cast_4: (1,uint8)(Tensor) = cast(x=%cast_3, dtype="uint8", name="cast_4")
              } -> (%cast_4)
              cond_0_false() {
                %cast_5: (1,int8)(Tensor) = cast(x=%cast_0, dtype="int8", name="cast_5")
                %cast_6: (1,bool)(Tensor) = cast(x=%cast_5, dtype="bool", name="cast_6")
                %cast_7: (1,uint8)(Tensor) = cast(x=%cast_6, dtype="uint8", name="cast_7")
              } -> (%cast_7)
          } -> (%cond_0)
        }

        Output graph:
        main[CoreML7](%x: (1,int32)(Tensor)) {
          block0() {
            %cond_0: (1,uint8)(Tensor) = cond(pred=True, name="cond_0")
              cond_0_true() {
                %x_to_uint8: (1,uint8)(Tensor) = cast(x=%x, dtype="uint8", name="x_to_uint8")
              } -> (%x_to_uint8)
              cond_0_false() {
                %x_to_bool: (1,bool)(Tensor) = cast(x=%x, dtype="bool", name="x_to_bool")
                %cast_7: (1,uint8)(Tensor) = cast(x=%x_to_bool, dtype="uint8", name="cast_7")
              } -> (%cast_7)
          } -> (%cond_0)
        }

        This is a more complex example:
        First, in the true branch, 4 ``cast`` ops are optimized into a single ``cast(dtype="uint8")``. In the false branch, 3 ``cast`` ops are optimized to ``cast(dtype="bool")->cast(dtype="uint8")``
        Second, the first ``cast`` op in each inner block is fused with the outer ``cast_0`` op, resulting in the above output graph.
        
coremltools/converters/mil/mil/passes/tests/test_passes.py