code: def firfilter(b, x, axis=-1, zi=None):
      """
      Filter data along one-dimension with an FIR filter.
  
      Filter a data sequence, `x`, using a digital filter. This works for many
      fundamental data types (including Object type). Please note, cuSignal
      doesn't support IIR filters presently, and this implementation is optimized
      for large filtering operations (and inherently depends on fftconvolve)
  
      Parameters
      ----------
      b : array_like
          The numerator coefficient vector in a 1-D sequence.
      x : array_like
          An N-dimensional input array.
      axis : int, optional
          The axis of the input data array along which to apply the
          linear filter. The filter is applied to each subarray along
          this axis.  Default is -1.
      zi : array_like, optional
          Initial conditions for the filter delays.  It is a vector
          (or array of vectors for an N-dimensional input) of length
          ``max(len(a), len(b)) - 1``.  If `zi` is None or is not given then
          initial rest is assumed.  See `lfiltic` for more information.
  
      Returns
      -------
      y : array
          The output of the digital filter.
      zf : array, optional
          If `zi` is None, this is not returned, otherwise, `zf` holds the
          final filter delay values.
      """
      b = cp.asarray(b)
      if b.ndim != 1:
          raise ValueError(
              "object of too small depth for desired array"
          )
  
      if x.ndim == 0:
          raise ValueError("x must be at least 1-D")
  
      inputs = [b, x]
      if zi is not None:
          # _linear_filter does not broadcast zi, but does do expansion of
          # singleton dims.
          zi = cp.asarray(zi)
          if zi.ndim != x.ndim:
              raise ValueError(
                  "object of too small depth for desired array"
              )
          expected_shape = list(x.shape)
          expected_shape[axis] = b.shape[0] - 1
          expected_shape = tuple(expected_shape)
          # check the trivial case where zi is the right shape first
          if zi.shape != expected_shape:
              strides = zi.ndim * [None]
              if axis < 0:
                  axis += zi.ndim
              for k in range(zi.ndim):
                  if k == axis and zi.shape[k] == expected_shape[k]:
                      strides[k] = zi.strides[k]
                  elif k != axis and zi.shape[k] == expected_shape[k]:
                      strides[k] = zi.strides[k]
                  elif k != axis and zi.shape[k] == 1:
                      strides[k] = 0
                  else:
                      raise ValueError(
                          "Unexpected shape for zi: expected "
                          "%s, found %s." % (expected_shape, zi.shape)
                      )
              zi = cp.lib.stride_tricks.as_strided(
                  zi, expected_shape, strides
              )
          inputs.append(zi)
      dtype = cp.result_type(*inputs)
  
      if dtype.char not in "fdgFDGO":
          raise NotImplementedError(
              "input type '%s' not supported" % dtype
          )
  
      b = cp.array(b, dtype=dtype)
      x = cp.array(x, dtype=dtype, copy=False)
  
      out_full = cp.apply_along_axis(
          lambda y: cp.convolve(b, y), axis, x
      )
  
      ind = out_full.ndim * [slice(None)]
      if zi is not None:
          ind[axis] = slice(zi.shape[axis])
          out_full[tuple(ind)] += zi
  
      ind[axis] = slice(out_full.shape[axis] - len(b) + 1)
      out = out_full[tuple(ind)]
  
      if zi is None:
          return out
      else:
          ind[axis] = slice(out_full.shape[axis] - len(b) + 1, None)
          zf = out_full[tuple(ind)]
          return out, zf
  
imports: import cupy
  import numpy
  from cupyx.scipy import linalg
  from ..convolution.correlate import correlate
  from ..filter_design.filter_design_utils import _validate_sos
  from ..utils.arraytools import _axis_reverse, _axis_slice, _const_ext, _even_ext, _odd_ext
  from ..utils.helper_tools import _get_max_smem, _get_max_tpb
  from ._channelizer_cuda import _channelizer
  from ._sosfilt_cuda import _sosfilt
label_desc: Use image node_id 2 for calling a global function with example usage: firfilter(b, x, axis, zi) and returns: out, out,  zf