code: def _get_devices(fn: Callable, complement: bool = True) -> Tuple:
      valid_devices = ivy.valid_devices
      invalid_devices = ivy.invalid_devices
      all_devices = ivy.all_devices
  
      supported = set(ivy.valid_devices)
  
      is_backend_fn = "backend" in fn.__module__
      is_frontend_fn = "frontend" in fn.__module__
      is_einops_fn = "einops" in fn.__name__
      if not is_backend_fn and not is_frontend_fn and not is_einops_fn:
          if complement:
              supported = set(all_devices).difference(supported)
          return supported
  
      # Their values are formatted like either
      # 1. fn.supported_devices = ("cpu",)
      # Could also have the "all" value for the framework
      basic = [
          ("supported_devices", set.intersection, valid_devices),
          ("unsupported_devices", set.difference, invalid_devices),
      ]
      for key, merge_fn, base in basic:
          if hasattr(fn, key):
              v = getattr(fn, key)
              if "einops" in fn.__name__ and isinstance(v, dict):
                  v = v.get(ivy.current_backend_str(), base)
              ivy.utils.assertions.check_isinstance(v, tuple)
              supported = merge_fn(supported, set(v))
  
      if complement:
          supported = set(all_devices).difference(supported)
  
      return tuple(supported)
  
imports: import os
  import gc
  import abc
  import math
  import psutil
  import warnings
  import types
  from typing import Type, Optional, Tuple
  from typing import Union, Callable, Iterable, Any
  import ivy
  from ivy.func_wrapper import handle_out_argument, to_native_arrays_and_back, inputs_to_native_arrays, handle_nestable, handle_array_like_without_promotion, handle_backend_invalid
  from ivy.utils.exceptions import handle_exceptions
label_desc: Use image node_id 29 for calling a global function with example usage: _get_devices(fn, complement) and returns: tuple, supported