1*523fa7a6SAndroid Build Coastguard Worker# Copyright 2023-2024 Arm Limited and/or its affiliates. 2*523fa7a6SAndroid Build Coastguard Worker# 3*523fa7a6SAndroid Build Coastguard Worker# This source code is licensed under the BSD-style license found in the 4*523fa7a6SAndroid Build Coastguard Worker# LICENSE file in the root directory of this source tree. 5*523fa7a6SAndroid Build Coastguard Worker 6*523fa7a6SAndroid Build Coastguard Worker# pyre-unsafe 7*523fa7a6SAndroid Build Coastguard Worker 8*523fa7a6SAndroid Build Coastguard Worker# 9*523fa7a6SAndroid Build Coastguard Worker# Main implementation of AoT flow to partition and preprocess for Arm target 10*523fa7a6SAndroid Build Coastguard Worker# backends. Converts via TOSA as an intermediate form supported by AoT and 11*523fa7a6SAndroid Build Coastguard Worker# JIT compiler flows. 12*523fa7a6SAndroid Build Coastguard Worker# 13*523fa7a6SAndroid Build Coastguard Worker 14*523fa7a6SAndroid Build Coastguard Workerimport logging 15*523fa7a6SAndroid Build Coastguard Workerimport os 16*523fa7a6SAndroid Build Coastguard Workerfrom typing import final, List, Optional 17*523fa7a6SAndroid Build Coastguard Worker 18*523fa7a6SAndroid Build Coastguard Workerimport serializer.tosa_serializer as ts 19*523fa7a6SAndroid Build Coastguard Workerfrom executorch.backends.arm.arm_vela import vela_compile 20*523fa7a6SAndroid Build Coastguard Workerfrom executorch.backends.arm.operators.node_visitor import get_node_visitors 21*523fa7a6SAndroid Build Coastguard Worker 22*523fa7a6SAndroid Build Coastguard Workerfrom executorch.backends.arm.tosa_specification import TosaSpecification 23*523fa7a6SAndroid Build Coastguard Workerfrom executorch.backends.arm._passes.arm_pass_manager import ( 24*523fa7a6SAndroid Build Coastguard Worker ArmPassManager, 25*523fa7a6SAndroid Build Coastguard Worker) # usort: skip 26*523fa7a6SAndroid Build Coastguard Workerfrom executorch.backends.arm.process_node import ( 27*523fa7a6SAndroid Build Coastguard Worker process_call_function, 28*523fa7a6SAndroid Build Coastguard Worker process_output, 29*523fa7a6SAndroid Build Coastguard Worker process_placeholder, 30*523fa7a6SAndroid Build Coastguard Worker) 31*523fa7a6SAndroid Build Coastguard Workerfrom executorch.backends.arm.tosa_utils import dbg_fail, dbg_tosa_dump 32*523fa7a6SAndroid Build Coastguard Workerfrom executorch.exir.backend.backend_details import BackendDetails, PreprocessResult 33*523fa7a6SAndroid Build Coastguard Workerfrom executorch.exir.backend.compile_spec_schema import CompileSpec 34*523fa7a6SAndroid Build Coastguard Workerfrom torch.export.exported_program import ExportedProgram 35*523fa7a6SAndroid Build Coastguard Worker 36*523fa7a6SAndroid Build Coastguard Worker# TOSA backend debug functionality 37*523fa7a6SAndroid Build Coastguard Workerlogger = logging.getLogger(__name__) 38*523fa7a6SAndroid Build Coastguard Workerlogger.setLevel(logging.WARNING) 39*523fa7a6SAndroid Build Coastguard WorkerTOSA_DBG_VERBOSE = os.environ.get("TOSA_DBG_VERBOSE") == "1" 40*523fa7a6SAndroid Build Coastguard Workerif TOSA_DBG_VERBOSE: 41*523fa7a6SAndroid Build Coastguard Worker logging.basicConfig(level=logging.INFO) 42*523fa7a6SAndroid Build Coastguard Worker logger.setLevel(logging.INFO) 43*523fa7a6SAndroid Build Coastguard Worker 44*523fa7a6SAndroid Build Coastguard Worker 45*523fa7a6SAndroid Build Coastguard Workerclass ArmCompileSpecBuilder: 46*523fa7a6SAndroid Build Coastguard Worker def __init__(self): 47*523fa7a6SAndroid Build Coastguard Worker self.compile_spec: List[CompileSpec] = [] 48*523fa7a6SAndroid Build Coastguard Worker self.compiler_flags = [] 49*523fa7a6SAndroid Build Coastguard Worker self.output_format = None 50*523fa7a6SAndroid Build Coastguard Worker self.path_for_intermediates = None 51*523fa7a6SAndroid Build Coastguard Worker # TODO MLETORCH-265 Remove permute_nhwc flag 52*523fa7a6SAndroid Build Coastguard Worker self.permute_nhwc = False 53*523fa7a6SAndroid Build Coastguard Worker self.quantize_io = False 54*523fa7a6SAndroid Build Coastguard Worker self.tosa_version = None 55*523fa7a6SAndroid Build Coastguard Worker 56*523fa7a6SAndroid Build Coastguard Worker def ethosu_compile_spec( 57*523fa7a6SAndroid Build Coastguard Worker self, 58*523fa7a6SAndroid Build Coastguard Worker config: str, 59*523fa7a6SAndroid Build Coastguard Worker system_config: str, 60*523fa7a6SAndroid Build Coastguard Worker memory_mode: str, 61*523fa7a6SAndroid Build Coastguard Worker extra_flags: Optional[str] = None, 62*523fa7a6SAndroid Build Coastguard Worker config_ini: Optional[str] = "Arm/vela.ini", 63*523fa7a6SAndroid Build Coastguard Worker ) -> "ArmCompileSpecBuilder": 64*523fa7a6SAndroid Build Coastguard Worker """ 65*523fa7a6SAndroid Build Coastguard Worker Generate compile spec for Ethos-U NPU 66*523fa7a6SAndroid Build Coastguard Worker 67*523fa7a6SAndroid Build Coastguard Worker Args: 68*523fa7a6SAndroid Build Coastguard Worker config: Ethos-U accelerator configuration, e.g. ethos-u55-128 69*523fa7a6SAndroid Build Coastguard Worker system_config: System configuration to select from the Vel 70*523fa7a6SAndroid Build Coastguard Worker configuration file 71*523fa7a6SAndroid Build Coastguard Worker memory_mode: Memory mode to select from the Vela configuration file 72*523fa7a6SAndroid Build Coastguard Worker extra_flags: Extra flags for the Vela compiler 73*523fa7a6SAndroid Build Coastguard Worker config_ini: Vela configuration file(s) in Python ConfigParser .ini 74*523fa7a6SAndroid Build Coastguard Worker file format 75*523fa7a6SAndroid Build Coastguard Worker """ 76*523fa7a6SAndroid Build Coastguard Worker assert ( 77*523fa7a6SAndroid Build Coastguard Worker self.output_format is None 78*523fa7a6SAndroid Build Coastguard Worker ), f"Output format already set to f{self.output_format}" 79*523fa7a6SAndroid Build Coastguard Worker self.output_format = "vela" 80*523fa7a6SAndroid Build Coastguard Worker self.compiler_flags = [ 81*523fa7a6SAndroid Build Coastguard Worker f"--accelerator-config={config}", 82*523fa7a6SAndroid Build Coastguard Worker f"--config={config_ini}", 83*523fa7a6SAndroid Build Coastguard Worker ] 84*523fa7a6SAndroid Build Coastguard Worker if system_config is not None: 85*523fa7a6SAndroid Build Coastguard Worker self.compiler_flags.append(f"--system-config={system_config}") 86*523fa7a6SAndroid Build Coastguard Worker if memory_mode is not None: 87*523fa7a6SAndroid Build Coastguard Worker self.compiler_flags.append(f"--memory-mode={memory_mode}") 88*523fa7a6SAndroid Build Coastguard Worker if extra_flags is not None: 89*523fa7a6SAndroid Build Coastguard Worker self.compiler_flags.append(extra_flags) 90*523fa7a6SAndroid Build Coastguard Worker 91*523fa7a6SAndroid Build Coastguard Worker base_tosa_version = "TOSA-0.80.0+BI" 92*523fa7a6SAndroid Build Coastguard Worker if "U55" in config: 93*523fa7a6SAndroid Build Coastguard Worker # Add the Ethos-U55 extension marker 94*523fa7a6SAndroid Build Coastguard Worker base_tosa_version += "+u55" 95*523fa7a6SAndroid Build Coastguard Worker self.tosa_version = TosaSpecification.create_from_string(base_tosa_version) 96*523fa7a6SAndroid Build Coastguard Worker 97*523fa7a6SAndroid Build Coastguard Worker return self 98*523fa7a6SAndroid Build Coastguard Worker 99*523fa7a6SAndroid Build Coastguard Worker def tosa_compile_spec(self, tosa_version: str) -> "ArmCompileSpecBuilder": 100*523fa7a6SAndroid Build Coastguard Worker """ 101*523fa7a6SAndroid Build Coastguard Worker Generate compile spec for TOSA flatbuffer output 102*523fa7a6SAndroid Build Coastguard Worker """ 103*523fa7a6SAndroid Build Coastguard Worker assert ( 104*523fa7a6SAndroid Build Coastguard Worker self.output_format is None 105*523fa7a6SAndroid Build Coastguard Worker ), f"Output format already set: {self.output_format}" 106*523fa7a6SAndroid Build Coastguard Worker self.output_format = "tosa" 107*523fa7a6SAndroid Build Coastguard Worker self.tosa_version = TosaSpecification.create_from_string(tosa_version) 108*523fa7a6SAndroid Build Coastguard Worker return self 109*523fa7a6SAndroid Build Coastguard Worker 110*523fa7a6SAndroid Build Coastguard Worker def dump_intermediate_artifacts_to( 111*523fa7a6SAndroid Build Coastguard Worker self, output_path: str 112*523fa7a6SAndroid Build Coastguard Worker ) -> "ArmCompileSpecBuilder": 113*523fa7a6SAndroid Build Coastguard Worker """ 114*523fa7a6SAndroid Build Coastguard Worker Sets a path for dumping intermediate results during such as tosa and pte. 115*523fa7a6SAndroid Build Coastguard Worker """ 116*523fa7a6SAndroid Build Coastguard Worker self.path_for_intermediates = output_path 117*523fa7a6SAndroid Build Coastguard Worker return self 118*523fa7a6SAndroid Build Coastguard Worker 119*523fa7a6SAndroid Build Coastguard Worker def set_permute_memory_format( 120*523fa7a6SAndroid Build Coastguard Worker self, set_nhwc_permutation: bool = True 121*523fa7a6SAndroid Build Coastguard Worker ) -> "ArmCompileSpecBuilder": 122*523fa7a6SAndroid Build Coastguard Worker """ 123*523fa7a6SAndroid Build Coastguard Worker Permute to channel last in compiler and runtime. Compilation and 124*523fa7a6SAndroid Build Coastguard Worker runtime will convert rank 4 inputs to channel last for each sub-graph. 125*523fa7a6SAndroid Build Coastguard Worker """ 126*523fa7a6SAndroid Build Coastguard Worker self.permute_nhwc = set_nhwc_permutation 127*523fa7a6SAndroid Build Coastguard Worker return self 128*523fa7a6SAndroid Build Coastguard Worker 129*523fa7a6SAndroid Build Coastguard Worker def set_quantize_io(self, quantize_io: bool = False) -> "ArmCompileSpecBuilder": 130*523fa7a6SAndroid Build Coastguard Worker """ 131*523fa7a6SAndroid Build Coastguard Worker Quantization of inputs and dequantization of outputs for cases where 132*523fa7a6SAndroid Build Coastguard Worker whole graph is quantized and method signature is not of quantized type. 133*523fa7a6SAndroid Build Coastguard Worker """ 134*523fa7a6SAndroid Build Coastguard Worker self.quantize_io = quantize_io 135*523fa7a6SAndroid Build Coastguard Worker return self 136*523fa7a6SAndroid Build Coastguard Worker 137*523fa7a6SAndroid Build Coastguard Worker def build(self) -> List[CompileSpec]: 138*523fa7a6SAndroid Build Coastguard Worker """ 139*523fa7a6SAndroid Build Coastguard Worker Generate a list of compile spec objects from the builder 140*523fa7a6SAndroid Build Coastguard Worker """ 141*523fa7a6SAndroid Build Coastguard Worker assert self.tosa_version 142*523fa7a6SAndroid Build Coastguard Worker 143*523fa7a6SAndroid Build Coastguard Worker # Always supply a TOSA version 144*523fa7a6SAndroid Build Coastguard Worker self.compile_spec = [ 145*523fa7a6SAndroid Build Coastguard Worker CompileSpec("tosa_version", str(self.tosa_version).encode()) 146*523fa7a6SAndroid Build Coastguard Worker ] 147*523fa7a6SAndroid Build Coastguard Worker 148*523fa7a6SAndroid Build Coastguard Worker if self.output_format == "vela": 149*523fa7a6SAndroid Build Coastguard Worker self.compile_spec += [ 150*523fa7a6SAndroid Build Coastguard Worker CompileSpec("output_format", "vela".encode()), 151*523fa7a6SAndroid Build Coastguard Worker CompileSpec("compile_flags", " ".join(self.compiler_flags).encode()), 152*523fa7a6SAndroid Build Coastguard Worker ] 153*523fa7a6SAndroid Build Coastguard Worker elif self.output_format == "tosa": 154*523fa7a6SAndroid Build Coastguard Worker self.compile_spec.append(CompileSpec("output_format", "tosa".encode())) 155*523fa7a6SAndroid Build Coastguard Worker 156*523fa7a6SAndroid Build Coastguard Worker if self.path_for_intermediates is not None: 157*523fa7a6SAndroid Build Coastguard Worker self.compile_spec.append( 158*523fa7a6SAndroid Build Coastguard Worker CompileSpec("debug_artifact_path", self.path_for_intermediates.encode()) 159*523fa7a6SAndroid Build Coastguard Worker ) 160*523fa7a6SAndroid Build Coastguard Worker 161*523fa7a6SAndroid Build Coastguard Worker if self.permute_nhwc: 162*523fa7a6SAndroid Build Coastguard Worker self.compile_spec.append( 163*523fa7a6SAndroid Build Coastguard Worker CompileSpec("permute_memory_format", "nhwc".encode()) 164*523fa7a6SAndroid Build Coastguard Worker ) 165*523fa7a6SAndroid Build Coastguard Worker 166*523fa7a6SAndroid Build Coastguard Worker if self.quantize_io: 167*523fa7a6SAndroid Build Coastguard Worker self.compile_spec.append(CompileSpec("quantize_io", "True".encode())) 168*523fa7a6SAndroid Build Coastguard Worker 169*523fa7a6SAndroid Build Coastguard Worker return self.compile_spec 170*523fa7a6SAndroid Build Coastguard Worker 171*523fa7a6SAndroid Build Coastguard Worker 172*523fa7a6SAndroid Build Coastguard Workerdef is_permute_memory(compile_spec: List[CompileSpec]) -> bool: 173*523fa7a6SAndroid Build Coastguard Worker for spec in compile_spec: 174*523fa7a6SAndroid Build Coastguard Worker if spec.key == "permute_memory_format": 175*523fa7a6SAndroid Build Coastguard Worker return spec.value.decode() == "nhwc" 176*523fa7a6SAndroid Build Coastguard Worker return False 177*523fa7a6SAndroid Build Coastguard Worker 178*523fa7a6SAndroid Build Coastguard Worker 179*523fa7a6SAndroid Build Coastguard Workerdef is_tosa(compile_spec: List[CompileSpec]) -> bool: 180*523fa7a6SAndroid Build Coastguard Worker for spec in compile_spec: 181*523fa7a6SAndroid Build Coastguard Worker if spec.key == "output_format": 182*523fa7a6SAndroid Build Coastguard Worker return spec.value.decode() == "tosa" 183*523fa7a6SAndroid Build Coastguard Worker return False 184*523fa7a6SAndroid Build Coastguard Worker 185*523fa7a6SAndroid Build Coastguard Worker 186*523fa7a6SAndroid Build Coastguard Workerdef get_intermediate_path(compile_spec: List[CompileSpec]) -> Optional[str]: 187*523fa7a6SAndroid Build Coastguard Worker for spec in compile_spec: 188*523fa7a6SAndroid Build Coastguard Worker if spec.key == "debug_artifact_path": 189*523fa7a6SAndroid Build Coastguard Worker return spec.value.decode() 190*523fa7a6SAndroid Build Coastguard Worker return None 191*523fa7a6SAndroid Build Coastguard Worker 192*523fa7a6SAndroid Build Coastguard Worker 193*523fa7a6SAndroid Build Coastguard Workerdef _get_first_delegation_tag(graph_module) -> str | None: 194*523fa7a6SAndroid Build Coastguard Worker """Get the first delegation tag from the graph_module or return None.""" 195*523fa7a6SAndroid Build Coastguard Worker for node in graph_module.graph.nodes: 196*523fa7a6SAndroid Build Coastguard Worker tag = node.meta.get("delegation_tag") 197*523fa7a6SAndroid Build Coastguard Worker if tag: 198*523fa7a6SAndroid Build Coastguard Worker return tag 199*523fa7a6SAndroid Build Coastguard Worker 200*523fa7a6SAndroid Build Coastguard Worker logger.debug("No delegation tag found in partition.") 201*523fa7a6SAndroid Build Coastguard Worker return None 202*523fa7a6SAndroid Build Coastguard Worker 203*523fa7a6SAndroid Build Coastguard Worker 204*523fa7a6SAndroid Build Coastguard Worker@final 205*523fa7a6SAndroid Build Coastguard Workerclass ArmBackend(BackendDetails): 206*523fa7a6SAndroid Build Coastguard Worker @staticmethod 207*523fa7a6SAndroid Build Coastguard Worker def preprocess( # noqa: C901 208*523fa7a6SAndroid Build Coastguard Worker edge_program: ExportedProgram, 209*523fa7a6SAndroid Build Coastguard Worker compile_spec: List[CompileSpec], 210*523fa7a6SAndroid Build Coastguard Worker ) -> PreprocessResult: 211*523fa7a6SAndroid Build Coastguard Worker logger.info("ArmBackend::preprocess") 212*523fa7a6SAndroid Build Coastguard Worker 213*523fa7a6SAndroid Build Coastguard Worker # if a debug/test build capture output files from TOSA stage 214*523fa7a6SAndroid Build Coastguard Worker artifact_path = None 215*523fa7a6SAndroid Build Coastguard Worker output_format = "" 216*523fa7a6SAndroid Build Coastguard Worker compile_flags = [] 217*523fa7a6SAndroid Build Coastguard Worker for spec in compile_spec: 218*523fa7a6SAndroid Build Coastguard Worker if spec.key == "debug_artifact_path": 219*523fa7a6SAndroid Build Coastguard Worker artifact_path = spec.value.decode() 220*523fa7a6SAndroid Build Coastguard Worker if spec.key == "output_format": 221*523fa7a6SAndroid Build Coastguard Worker output_format = spec.value.decode() 222*523fa7a6SAndroid Build Coastguard Worker if spec.key == "compile_flags": 223*523fa7a6SAndroid Build Coastguard Worker compile_flags.append(spec.value.decode()) 224*523fa7a6SAndroid Build Coastguard Worker 225*523fa7a6SAndroid Build Coastguard Worker # Check that the output format is set in the compile spec 226*523fa7a6SAndroid Build Coastguard Worker if not output_format: 227*523fa7a6SAndroid Build Coastguard Worker raise RuntimeError("output format is required") 228*523fa7a6SAndroid Build Coastguard Worker 229*523fa7a6SAndroid Build Coastguard Worker tosa_spec = TosaSpecification.create_from_compilespecs(compile_spec) 230*523fa7a6SAndroid Build Coastguard Worker assert ( 231*523fa7a6SAndroid Build Coastguard Worker tosa_spec is not None 232*523fa7a6SAndroid Build Coastguard Worker ), "TOSA backend needs a TOSA version specified in the CompileSpec!" 233*523fa7a6SAndroid Build Coastguard Worker 234*523fa7a6SAndroid Build Coastguard Worker if output_format == "vela" and len(compile_flags) == 0: 235*523fa7a6SAndroid Build Coastguard Worker # Not testing for compile_flags correctness here, just that they are 236*523fa7a6SAndroid Build Coastguard Worker # present. The compiler will give errors if they are not valid. 237*523fa7a6SAndroid Build Coastguard Worker raise RuntimeError("compile flags are required for vela output format") 238*523fa7a6SAndroid Build Coastguard Worker 239*523fa7a6SAndroid Build Coastguard Worker logger.info(f"Converting ExportedProgram to TOSA: {tosa_spec}") 240*523fa7a6SAndroid Build Coastguard Worker 241*523fa7a6SAndroid Build Coastguard Worker # Converted output for this subgraph, serializer needs path early as it emits 242*523fa7a6SAndroid Build Coastguard Worker # const data directly. Path created and data written only in debug builds. 243*523fa7a6SAndroid Build Coastguard Worker tosa_graph = ts.TosaSerializer(artifact_path) 244*523fa7a6SAndroid Build Coastguard Worker graph_module = ArmPassManager().transform_to_backend_pipeline( 245*523fa7a6SAndroid Build Coastguard Worker exported_program=edge_program, compile_spec=compile_spec 246*523fa7a6SAndroid Build Coastguard Worker ) 247*523fa7a6SAndroid Build Coastguard Worker 248*523fa7a6SAndroid Build Coastguard Worker node_visitors = get_node_visitors(edge_program, tosa_spec) 249*523fa7a6SAndroid Build Coastguard Worker 250*523fa7a6SAndroid Build Coastguard Worker for node in graph_module.graph.nodes: 251*523fa7a6SAndroid Build Coastguard Worker if node.op == "call_function": 252*523fa7a6SAndroid Build Coastguard Worker process_call_function(node, tosa_graph, node_visitors, tosa_spec) 253*523fa7a6SAndroid Build Coastguard Worker elif node.op == "placeholder": 254*523fa7a6SAndroid Build Coastguard Worker process_placeholder(node, tosa_graph, edge_program, tosa_spec) 255*523fa7a6SAndroid Build Coastguard Worker elif node.op == "output": 256*523fa7a6SAndroid Build Coastguard Worker process_output(node, tosa_graph) 257*523fa7a6SAndroid Build Coastguard Worker else: 258*523fa7a6SAndroid Build Coastguard Worker # This will only happen if an unpartitioned graph is passed without 259*523fa7a6SAndroid Build Coastguard Worker # any checking of compatibility. 260*523fa7a6SAndroid Build Coastguard Worker dbg_fail(node, tosa_graph, artifact_path) 261*523fa7a6SAndroid Build Coastguard Worker 262*523fa7a6SAndroid Build Coastguard Worker # TODO: It would be awesome if this dump could somehow be done on top level and not here. 263*523fa7a6SAndroid Build Coastguard Worker # Problem is that the desc.json has to be created on the tosa_graph object, which we can't 264*523fa7a6SAndroid Build Coastguard Worker # access from top level. 265*523fa7a6SAndroid Build Coastguard Worker if artifact_path: 266*523fa7a6SAndroid Build Coastguard Worker tag = _get_first_delegation_tag(graph_module) 267*523fa7a6SAndroid Build Coastguard Worker dbg_tosa_dump( 268*523fa7a6SAndroid Build Coastguard Worker tosa_graph, 269*523fa7a6SAndroid Build Coastguard Worker artifact_path, 270*523fa7a6SAndroid Build Coastguard Worker suffix="{}".format(f"_{tag}" if tag else ""), 271*523fa7a6SAndroid Build Coastguard Worker ) 272*523fa7a6SAndroid Build Coastguard Worker 273*523fa7a6SAndroid Build Coastguard Worker # Serialize and return the program. While we have always produced TOSA 274*523fa7a6SAndroid Build Coastguard Worker # output as an intermediate, some flows compile to device binaries in 275*523fa7a6SAndroid Build Coastguard Worker # preprocess and some consume TOSA fb directly. 276*523fa7a6SAndroid Build Coastguard Worker if output_format == "vela": 277*523fa7a6SAndroid Build Coastguard Worker # Emit vela_bin_stream format 278*523fa7a6SAndroid Build Coastguard Worker binary = vela_compile(tosa_graph, compile_flags) 279*523fa7a6SAndroid Build Coastguard Worker elif output_format == "tosa": 280*523fa7a6SAndroid Build Coastguard Worker # Emit TOSA flatbuffer 281*523fa7a6SAndroid Build Coastguard Worker binary = bytes(tosa_graph.serialize()) 282*523fa7a6SAndroid Build Coastguard Worker else: 283*523fa7a6SAndroid Build Coastguard Worker raise RuntimeError(f"Unknown format {output_format}") 284*523fa7a6SAndroid Build Coastguard Worker 285*523fa7a6SAndroid Build Coastguard Worker # Continueing from above. Can I put tosa_graph into this function? 286*523fa7a6SAndroid Build Coastguard Worker # debug_handle_map = ... 287*523fa7a6SAndroid Build Coastguard Worker return PreprocessResult(processed_bytes=binary) 288