code: def _SwitchGrad(op, *grad):
      """Gradients for a Switch op is calculated using a Merge op.
  
      If the switch is a loop switch, it will be visited twice. We create
      the merge on the first visit, and update the other input of the merge
      on the second visit. A next_iteration is also added on second visit.
      """
      graph = ops.get_default_graph()
      # pylint: disable=protected-access
      op_ctxt = op._get_control_flow_context()
      grad_ctxt = graph._get_control_flow_context()
      # pylint: enable=protected-access
      if isinstance(op_ctxt, WhileContext):
          merge_grad = grad_ctxt.grad_state.switch_map.get(op)
          if merge_grad is not None:
              # This is the second time this Switch is visited. It comes from
              # the non-exit branch of the Switch, so update the second input
              # to the Merge.
              # TODO(yuanbyu): Perform shape inference with this new input.
              if grad[1] is not None:
                  # pylint: disable=protected-access
                  control_flow_ops._AddNextAndBackEdge(
                      merge_grad, grad[1], enforce_shape_invariant=False
                  )
                  # pylint: enable=protected-access
              return None, None
          elif grad[0] is not None:
              # This is the first time this Switch is visited. It comes from
              # the Exit branch, which is grad[0]. grad[1] is empty at this point.
              # Use grad[0] for both inputs to merge for now, but update the second
              # input of merge when we see this Switch the second time.
              merge_grad = merge([grad[0], grad[0]], name="b_switch")[0]
              grad_ctxt.grad_state.switch_map[op] = merge_grad
              return merge_grad, None
          else:
              # This is the first time this Switch is visited. It comes from the
              # Identity branch. Such a Switch has `None` gradient for the Exit branch,
              # meaning the output is not differentiable.
              return None, None
      elif isinstance(op_ctxt, CondContext):
          zero_grad = grad[1 - op_ctxt.branch]
          # At this point, we have created zero_grad guarded by the right switch.
          # Unfortunately, we may still get None here for not trainable data types.
          if zero_grad is None:
              # For resource variables we get None always on the other branch, so bypass
              # this.
              if op.inputs[0].dtype == dtypes.resource:
                  return (
                      merge(
                          [grad[op_ctxt.branch]] * 2,
                          name="cond_resource_grad",
                      )[0],
                      None,
                  )
              return None, None
          return merge(grad, name="cond_grad")[0], None
      else:
          false_grad = switch(grad[0], op.inputs[1])[0]
          true_grad = switch(grad[1], op.inputs[1])[1]
          return merge([false_grad, true_grad])[0], None
  
file_path: tensorflow-upstream/tensorflow/python/ops/control_flow_grad.py
imports: from tensorflow.python.framework import dtypes
  from tensorflow.python.framework import indexed_slices
  from tensorflow.python.framework import ops
  from tensorflow.python.framework import sparse_tensor
  from tensorflow.python.framework import tensor
  from tensorflow.python.ops import control_flow_ops
  from tensorflow.python.ops import control_flow_util
  from tensorflow.python.ops import math_ops
  from tensorflow.python.ops.control_flow_ops import *
label_desc: Use image node_id 1 for calling a global function with example usage: _SwitchGrad(op) and returns: None,  None, merge,  None, merge,  None, merge_grad,  None, None,  None, None,  None, merge,  None