code: def _exec_fftn(
      a,
      direction,
      value_type,
      norm,
      axes,
      overwrite_x,
      plan=None,
      out=None,
      out_size=None,
  ):
      from cupy.cuda import cufft
  
      fft_type = _convert_fft_type(a.dtype, value_type)
  
      if a.flags.c_contiguous:
          order = "C"
      elif a.flags.f_contiguous:
          order = "F"
      else:
          raise ValueError("a must be contiguous")
  
      if value_type == "C2R" and not overwrite_x:
          # The input array may be modified in CUDA 10.1 and above.
          # See #3763 for the discussion.
          a = a.copy()
      elif cupy.cuda.runtime.is_hip and value_type != "C2C":
          # hipFFT's R2C would overwrite input
          # hipFFT's C2R PlanNd is actually not in use so it's fine here
          a = a.copy()
  
      # plan search precedence:
      # 1. plan passed in as an argument
      # 2. plan as context manager
      # 3. cached plan
      # 4. create a new one
      curr_plan = cufft.get_current_plan()
      if curr_plan is not None:
          plan = curr_plan
          # don't check repeated usage; it's done in _default_fft_func()
      if plan is None:
          # search from cache, and generate a plan if not found
          plan = _get_cufft_plan_nd(
              a.shape,
              fft_type,
              axes=axes,
              order=order,
              out_size=out_size,
          )
      else:
          if not isinstance(plan, cufft.PlanNd):
              raise ValueError(
                  "expected plan to have type cufft.PlanNd"
              )
          if order != plan.order:
              raise ValueError(
                  "array orders mismatch (plan: {}, input: {})".format(
                      plan.order, order
                  )
              )
          if a.flags.c_contiguous:
              expected_shape = [a.shape[ax] for ax in axes]
              if value_type == "C2R":
                  expected_shape[-1] = out_size
          else:
              # plan.shape will be reversed for Fortran-ordered inputs
              expected_shape = [a.shape[ax] for ax in axes[::-1]]
              # TODO(leofang): modify the shape for C2R
          expected_shape = tuple(expected_shape)
          if expected_shape != plan.shape:
              raise ValueError(
                  "The cuFFT plan and a.shape do not match: "
                  "plan.shape = {}, expected_shape={}, a.shape = {}".format(
                      plan.shape, expected_shape, a.shape
                  )
              )
          if fft_type != plan.fft_type:
              raise ValueError("cuFFT plan dtype mismatch.")
          if value_type != "C2C":
              if axes[-1] != plan.last_axis:
                  raise ValueError("The last axis for R2C/C2R mismatch")
              if out_size != plan.last_size:
                  raise ValueError(
                      "The size along the last R2C/C2R axis " "mismatch"
                  )
  
      # TODO(leofang): support in-place transform for R2C/C2R
      if overwrite_x and value_type == "C2C":
          out = a
      elif out is None:
          out = plan.get_output_array(a, order=order)
      else:
          plan.check_output_array(a, out)
  
      if out.size != 0:
          plan.fft(a, out, direction)
  
      # normalize by the product of the shape along the transformed axes
      arr = a if fft_type in (cufft.CUFFT_R2C, cufft.CUFFT_D2Z) else out
      sz = _prod([arr.shape[ax] for ax in axes])
      if norm == "backward" and direction == cufft.CUFFT_INVERSE:
          out /= sz
      elif norm == "ortho":
          out /= math.sqrt(sz)
      elif norm == "forward" and direction == cufft.CUFFT_FORWARD:
          out /= sz
  
      return out
  
imports: import functools
  import math
  import numpy
  import cupy
  from cupy.fft import config
  from cupy.fft._cache import get_plan_cache
label_desc: Use image node_id 12 for calling a global function with example usage: _exec_fftn(a, direction, value_type, norm, axes, overwrite_x, plan, out, out_size) and returns: out