def _add_op(cls, op_cls, **kwargs):
        """
        Add an op of type `op_cls` (e.g., convolution) to current block.
        """
        kwargs = cls._maybe_set_name(kwargs, op_cls.__name__)
        logger.debug(
            "Adding op '{}' of type {}".format(kwargs["name"], op_cls.__name__)
        )

        # If before_op is explicitly passed, the builder will respect it,
        # otherwise it will refer to _BEFORE_OP_STACK.
        before_op = kwargs.get("before_op", None)
        if before_op is None and len(_BEFORE_OP_STACK) != 0:
            before_op = _BEFORE_OP_STACK[-1]

        # Shallow copy list inputs to ensure op inputs are immutable
        kwargs = {k: v if not isinstance(v, (list, tuple)) else v[:] for k, v in kwargs.items() if v is not None}
        kwargs.update(cls._create_vars(
            input_spec=op_cls.input_spec,
            op_name=kwargs["name"], before_op=before_op,
            candidate_kv=kwargs))
        kwargs["enclosing_block"] = curr_block()

        # Add scope information
        current_scopes = SCOPE_STACK.get_curr_scopes()
        kwargs["scopes"] = current_scopes
        new_op = op_cls(**kwargs)

        # We record if the op is created under graph pass
        if len(current_scopes) == 1 and ScopeSource.COREMLTOOLS_GRAPH_PASS in current_scopes:
            VALID_OPS_TO_COPY_SCOPE_INFO[-1].add(new_op)

        # Initialize optional input Vars if it wasn't in kwargs
        default_inputs = new_op.default_inputs()
        # Shallow copy list inputs to ensure op inputs are immutable
        missing_optional_vals = {k: v if not isinstance(v, (list, tuple)) else v[:] for k, v in default_inputs.items()
            if k not in kwargs and v is not None}
        missing_optional_vars = cls._create_vars(
            input_spec=op_cls.input_spec,
            op_name=kwargs["name"], before_op=before_op,
            candidate_kv=missing_optional_vals)
        new_op.set_inputs(type_inference=False,
            **missing_optional_vars)

        curr_block()._insert_op_before(new_op, before_op=before_op)
        new_op.build_nested_blocks()
        new_op.type_value_inference()
        if len(new_op.outputs) == 1:
            return new_op.outputs[0]
        return new_op.outputs

        Add an op of type `op_cls` (e.g., convolution) to current block.
        
coremltools/converters/mil/mil/builder.py