code: def _schedule_async_dma_conv2d():
      """Manually schedule a conv2d block, created from TE compute op via CreatePrimFunc,
      using 8x8x32 packed layout.
      """
  
      def schedule_fn(
          sch, conv2d_block: Optional[BlockRV] = None
      ) -> bool:
          if conv2d_block is None:
              if has_block(sch, "conv2d_NCHWc_int8"):
                  conv2d_block = sch.get_block("conv2d_NCHWc_int8")
              else:
                  return False
  
          assert (
              "conv2d_NCHWc_int8"
              in sch.get(conv2d_block).annotations["schedule_rule"]
          )
  
          # Apply scheduling
  
          post_blocks = sch.get_consumers(conv2d_block)
          if len(post_blocks) > 0:
              # Fuse all intermediate post ops into the last op.
              # This is equivalent to the traverse_inline function used in TE schedules.
              while True:
                  next_post_blocks = []
                  for post_block in post_blocks:
                      next_consumers = sch.get_consumers(post_block)
                      if len(next_consumers) > 0:
                          sch.compute_inline(post_block)
                      next_post_blocks += next_consumers
                  if len(next_post_blocks) == 0:
                      assert len(post_blocks) == 1
                      outer_block = post_blocks[0]
                      break
                  post_blocks = next_post_blocks
          else:
              outer_block = conv2d_block
  
          # Move the conv2d mma into the injective post mma compute block
          if outer_block != conv2d_block:
              loops = sch.get_loops(outer_block)
              # Compute at the second loop for pipelining.
              sch.compute_at(
                  conv2d_block, loops[1], preserve_unit_loops=True
              )
  
          # Add cache for input and output for copying data to vtcm.
          input_a_cache = sch.cache_read(conv2d_block, 0, "global.vtcm")
          sch.compute_at(input_a_cache, sch.get_loops(conv2d_block)[1])
          sch.fuse(*sch.get_loops(input_a_cache)[2:])
  
          input_b_cache = sch.cache_read(conv2d_block, 1, "global.vtcm")
          sch.compute_at(input_b_cache, sch.get_loops(conv2d_block)[1])
          sch.fuse(*sch.get_loops(input_b_cache)[2:])
  
          output_cache_write = sch.cache_write(
              conv2d_block, 0, "global.vtcm"
          )
          sch.fuse(*sch.get_loops(output_cache_write)[2:])
  
          conv2d_loops = sch.get_loops(block=conv2d_block)
          o_c, k_h, k_w, x_0, x_1, i_c = conv2d_loops[-6:]
          ic_o, ic_i = sch.split(
              loop=i_c, factors=[None, 4], preserve_unit_iters=True
          )
          oc_o, oc_i = sch.split(
              loop=o_c, factors=[None, 32], preserve_unit_iters=True
          )
          sch.reorder(oc_o, k_h, k_w, x_0, x_1, ic_o, oc_i, ic_i)
          new_loops = sch.get_loops(block=conv2d_block)
          sch.parallel(new_loops[4])
          sch.unroll(new_loops[5])
          # TODO(nverke): Add compute optimizations here.
          sch.blockize(target=oc_i)
  
          sch.tensorize(oc_i, VRMPY_u8i8i32_VTCM_INTRIN)
  
          pipeline_loop = conv2d_loops[1]
          sch.annotate(
              pipeline_loop, "software_pipeline_stage", [0, 0, 1, 2, 3]
          )
          sch.annotate(
              pipeline_loop, "software_pipeline_order", [0, 1, 2, 3, 4]
          )
          sch.annotate(
              pipeline_loop, "software_pipeline_async_stages", [0, 2]
          )
  
          return True
  
      return schedule_fn
  
imports: import os
  import tempfile
  from types import MappingProxyType
  from typing import Any, Mapping, Optional
  import numpy
  import pytest
  import tvm
  import tvm.testing
  from tvm import meta_schedule
  from tvm import relay
  from tvm._ffi import register_func
  from tvm.contrib.hexagon.meta_schedule import get_hexagon_local_builder, get_hexagon_rpc_runner
  from tvm.meta_schedule import postproc, schedule_rule
  from tvm.meta_schedule.utils import cpu_count
  from tvm.tir.schedule import BlockRV, Schedule
  from tvm.tir.schedule.analysis import has_block
  from tvm.tir.tensor_intrin.hexagon import VRMPY_u8i8i32_INTRIN, VRMPY_u8u8i32_INTRIN, VRMPY_u8i8i32_VTCM_INTRIN
  from ..infrastructure import get_hexagon_target
label_desc: Use image node_id 8 for calling a global function with example usage: _schedule_async_dma_conv2d() and returns: schedule_fn, True, False