code: def create_joint(fn: Callable, *, aot_config: AOTConfig) -> Any:
      def inner_fn(primals: List[Any], tangents: List[Any]):
          outs, tangent_mask = fn(*primals)
          assert len(tangent_mask) == len(outs)
          outs_to_grad = [
              o
              for needs_tangent, o in zip(tangent_mask, outs)
              if needs_tangent
          ]
          assert len(outs_to_grad) == len(tangents)
  
          # Get the inputs that need gradients
          grad_primals = []
          inputs_needs_grads = []
          # Note that we're not using primals here,
          # being carefully not to pass any mutated inputs into autograd.grad()
          for p in primals:
              is_grad_tensor = isinstance(p, Tensor) and p.requires_grad
              inputs_needs_grads.append(is_grad_tensor)
              if is_grad_tensor:
                  grad_primals.append(p)
  
          # Get the outputs that need gradients
          needed_outs = []
          needed_tangents = []
          for out, tangent in zip(outs_to_grad, tangents):
              if isinstance(out, Tensor) and out.requires_grad:
                  # A bit sketchy, but fixes e.g. test_aot_autograd_exhaustive_matmul_cpu_float32
                  # The issue is that we are sensitive to decomps that don't accurately maintain
                  # their output's _base.shape compared to eager mode, and this helps mitigate a bit.
                  # The not definitely_false is also sketchy; if unbacked
                  # symints are involved, we're just going to assume that the
                  # decomps setup the base shape correctly
                  needed_outs.append(
                      out
                      if not definitely_false(
                          sym_eq(out.shape, tangent.shape)
                      )
                      else out.view(tangent.shape)
                  )
                  needed_tangents.append(tangent)
  
          setup_stacktrace_preservation_hooks(
              [out.grad_fn for out in needed_outs]
          )
  
          if config.functionalize_rng_ops:
              PhiloxStateTracker.mark_beginning_of_backward()
          backward_out: Tuple[Tensor, ...] = tuple()
          # Call the backwards pass
          if grad_primals:
              with fx_traceback.preserve_node_meta():
                  # for full graph export, we always export a joint graph where we assume no tangents are needed.
                  if aot_config.no_tangents:
                      assert (
                          len(needed_tangents) == 1
                          and needed_tangents[0].numel() == 1
                      )
                      backward_out = torch.autograd.grad(
                          needed_outs,
                          grad_primals,
                          allow_unused=True,
                      )
                  else:
                      backward_out = torch.autograd.grad(
                          needed_outs,
                          grad_primals,
                          grad_outputs=needed_tangents,
                          allow_unused=True,
                      )
          backward_out_iter = iter(backward_out)
          return outs, [
              next(backward_out_iter) if i else None
              for i in inputs_needs_grads
          ]
  
      def inner_fn_with_anomaly(*args):
          with fx_traceback.preserve_node_meta(), warnings.catch_warnings():
              warnings.filterwarnings(
                  "ignore", "Anomaly Detection has been enabled."
              )
              with torch.autograd.detect_anomaly(check_nan=False):
                  return inner_fn(*args)
  
      return inner_fn_with_anomaly
  
imports: import warnings
  from contextlib import nullcontext
  from functools import wraps
  from typing import Any, Callable, List, Tuple, Union
  from unittest.mock import patch
  import torch
  import torch.fx.traceback
  import torch.utils._pytree
  from torch import Tensor
  from torch._decomp.decompositions_for_rng import PhiloxStateTracker
  from torch._guards import detect_fake_mode
  from torch._prims_common import CUDARngStateHelper
  from torch._subclasses.functional_tensor import FunctionalTensorMode
  from torch.fx import Interpreter
  from torch.fx.experimental.symbolic_shapes import definitely_false, sym_eq
  from torch.nn.utils import stateless
  from ..None import config
  from .collect_metadata_analysis import run_functionalized_fw_and_collect_metadata
  from .functional_utils import from_fun, has_data_mutation, has_metadata_mutation, is_fun, sync_functional_tensor, to_fun
  from .logging_utils import setup_stacktrace_preservation_hooks
  from .schemas import AOTConfig, MutationType, OutputType, SubclassMeta, SubclassTracingInfo, ViewAndMutationMeta
  from .subclass_utils import create_subclass_meta, requires_subclass_dispatch, unwrap_tensor_subclasses, wrap_tensor_subclasses_maybe_joint
  from .utils import maybe_to_fresh_input
label_desc: Use image node_id 3 for calling a global function with example usage: create_joint(fn) and returns: inner_fn_with_anomaly, outs,  unknown, inner_fn