code: def wrap_propagate_mutations_and_return(
      f: NativeFunction,
      functional_op: NativeFunction,
      inner_return_var: str,
  ) -> str:
      mutable_arg_names = f.func.arguments.mutable_arg_names()
      (
          aliased_outer_rets,
          non_aliased_outer_rets,
      ) = get_mutable_redispatch_return_names(f, inner_return_var)
      _, non_aliased_inner_rets = get_mutable_redispatch_return_names(
          functional_op, inner_return_var
      )
      # The outer function may have a mix of aliased and non-aliased outputs,
      # But the inner functional op that we're transforming to should only have non-aliased outputs
      assert len(mutable_arg_names) + len(
          non_aliased_outer_rets
      ) == len(non_aliased_inner_rets)
  
      # First, take all of the newly created outputs from the inner call and wrap them into functional tensors
      updates = []
      non_aliased_wrapped_ret_names = []
      for i, inner_ret in enumerate(
          non_aliased_inner_rets[: len(non_aliased_outer_rets)]
      ):
          ret_name = f"output_{i}"
          updates.append(
              f"""\
    auto output_{i} = at::functionalization::impl::to_functional_tensor({inner_ret});"""
          )
          non_aliased_wrapped_ret_names.append(ret_name)
  
      # Next, take all of the mutated outputs from the inner call corresponding to mutated inputs,
      # and propagate the mutations
      for outer_arg, inner_ret in zip(
          mutable_arg_names,
          non_aliased_inner_rets[len(non_aliased_outer_rets) :],
      ):
          updates.append(
              f"""\
    at::functionalization::impl::propagate_xla_data({outer_arg}, {inner_ret});
    at::functionalization::impl::replace_({outer_arg}, {inner_ret});
    at::functionalization::impl::commit_update({outer_arg});
    at::functionalization::impl::sync({outer_arg});"""
          )
  
      # Finally, we return:
      # - Any mutable arguments that also returns
      # - Any immutable returns that were created wrapping the output from the inner call
      returns_str = return_str(
          f.func.returns,
          aliased_outer_rets + non_aliased_wrapped_ret_names,
      )
      updates_str = "\n".join(updates)
      return f"""\
  {updates_str}
      {returns_str}"""
  
imports: from dataclasses import dataclass
  from typing import Callable, List, Optional, Tuple, Union
  from torchgen.api import cpp, dispatcher
  from torchgen.api.translate import translate
  from torchgen.api.types import BaseCType, Binding, CType, DispatcherSignature, FunctionalizationLambda, iTensorListRefT, NativeSignature, tensorListT, tensorT, VectorCType, ViewInverseSignature
  from torchgen.context import method_with_native_function, native_function_manager, with_native_function, with_native_function_and
  from torchgen.model import Argument, BackendIndex, BaseTy, BaseType, FunctionSchema, ListType, NativeFunction, NativeFunctionsGroup, NativeFunctionsViewGroup, Return, SchemaKind, SelfArgument, TensorOptionsArguments
  from torchgen.native_function_generation import INPLACE_OPS_THAT_DONT_GET_GROUPED_PROPERLY, MUTABLE_OPS_THAT_CANNOT_GET_AN_OUT_VARIANT, OUT_OPS_THAT_DONT_GET_GROUPED_PROPERLY
  from torchgen.selective_build.selector import SelectiveBuilder
label_desc: Use image node_id 13 for calling a global function with example usage: wrap_propagate_mutations_and_return(f, functional_op, inner_return_var) and returns: updates_str, str, returns_str