class_docstr: A pass to merge an identity operator with a LUT based activation function with
  a preceding operator provided that operator can do a table lookup for the activation
  in the hardware
docstr: Recursively visit call nodes in the input graph and if an ethosu.identity
  operator with LUT is found and the preceding operator has a LUT attribute, create
  a new NPU operator.
  
  Parameters
  ----------
  call : tvm.relay.expr.Call
      The current call node being visited.
  
  Returns
  -------
  tvm.relay.expr.Call
      The input call node in the case the current call node does
      not refer to an Op. Else, a new call node with a new operator.
docstr_tok: ["Recursively","visit","call","nodes","in","the","input","graph","and","if","an","ethosu.identity","operator","with","LUT","is","found","and","the","preceding","operator","has","a","LUT","attribute",",","create","a","new","NPU","operator",".","Parameters","--","--","--","--","--","call",":","tvm.relay.expr.Call","The","current","call","node","being","visited",".","Returns","--","--","--","-","tvm.relay.expr.Call","The","input","call","node","in","the","case","the","current","call","node","does","not","refer","to","an","Op",".","Else",",","a","new","call","node","with","a","new","operator","."]
code: def visit_call(
      self, call: tvm.relay.expr.Call
  ) -> tvm.relay.expr.Call:
      """Recursively visit call nodes in the input graph and if an ethosu.identity
      operator with LUT is found and the preceding operator has a LUT attribute, create
      a new NPU operator.
  
      Parameters
      ----------
      call : tvm.relay.expr.Call
          The current call node being visited.
  
      Returns
      -------
      tvm.relay.expr.Call
          The input call node in the case the current call node does
          not refer to an Op. Else, a new call node with a new operator.
      """
      new_call = call
      lut_activations = ["TANH", "LUT", "SIGMOID"]
  
      if isinstance(call.op, tvm.ir.Op) and isinstance(
          call.args[0], tvm.relay.expr.Call
      ):
          producer_op = call.args[0]
          # Check if the producer can do a LUT operation
          if (
              producer_op.op.name in self.lut_ops.keys()
              and call.op.name == "contrib.ethosu.identity"
              and call.attrs.activation in lut_activations
          ):
              # Check the producer doesn't already have a LUT
              has_lut = producer_op.attrs.activation in lut_activations
              if not has_lut:
                  new_call = self.create_op_with_lut(call)
  
      new_call = super().visit_call(new_call)
  
      return new_call
  
imports: from collections import defaultdict
  from typing import List, Callable
  from ethosu.vela import api
  import tvm
  from tvm import relay
  from tvm.relay.backend.contrib.ethosu.tir.compiler import LowerToTIR
  from tvm.relay.backend.contrib.ethosu.tir.scheduler import copy_constants
  from tvm.contrib.ethosu.cascader import cascade, EthosuDeviceConfig, CascaderOptions, MemoryRegion, extract_memory_info
  from tvm.relay.backend.contrib.ethosu.legalize import LegalizeEthosU
  from tvm.relay.backend.contrib.ethosu import tir_to_cs_translator, util, vela_api
  from tvm.relay.expr_functor import ExprMutator, ExprVisitor, Call
  from tvm.relay import expr
  from tvm.relay.backend.contrib.ethosu.op import op_attrs
  from tvm.relay.backend.contrib.ethosu import op
  from .None import _ffi_api
label_desc: Use image node_id 3 for calling the OptimizeLUTs obj's underlying member method code with example usage: obj.visit_call(call) and returns: new_call