Skip to content

Commit f294074

Browse files
authored
Revert "Arm backend: Refactor compile spec handling (#14111)" (#14175)
This reverts commit 29cec35. This broke our internal Buck builds and I think revert/reapply will allow us to ingest changes faster overall. (Have plans to get some Buck coverage in GitHub CI that will prevent problems like this going forward soon.)
1 parent 47acc87 commit f294074

31 files changed

+637
-664
lines changed

backends/arm/arm_backend.py

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
# Copyright 2023-2025 Arm Limited and/or its affiliates.
2+
#
3+
# This source code is licensed under the BSD-style license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
# pyre-unsafe
7+
8+
#
9+
# Main implementation of AoT flow to partition and preprocess for Arm target
10+
# backends. Converts via TOSA as an intermediate form supported by AoT and
11+
# JIT compiler flows.
12+
#
13+
from enum import Enum
14+
from typing import List, Optional
15+
16+
from executorch.backends.arm.tosa import TosaSpecification
17+
18+
from executorch.exir.backend.compile_spec_schema import ( # type: ignore[import-not-found]
19+
CompileSpec,
20+
)
21+
22+
23+
class ArmCompileSpecBuilder:
24+
class DebugMode(Enum):
25+
JSON = 1
26+
TOSA = 2
27+
28+
def __init__(self):
29+
self.compile_spec: List[CompileSpec] = []
30+
self.compiler_flags = []
31+
self.output_format = None
32+
self.path_for_intermediates = None
33+
self.tosa_spec = None
34+
self.tosa_debug_mode = None
35+
36+
def vgf_compile_spec(
37+
self,
38+
tosa_spec: TosaSpecification = None, # type: ignore[assignment]
39+
compiler_flags: Optional[str] = "",
40+
) -> "ArmCompileSpecBuilder":
41+
"""
42+
Generate compile spec for VGF compatible targets
43+
44+
Args:
45+
compiler_flags: Extra compiler flags for converter_backend
46+
"""
47+
self.output_format = "vgf"
48+
self.compiler_flags = [
49+
compiler_flags,
50+
]
51+
52+
if tosa_spec is None:
53+
tosa_spec = TosaSpecification.create_from_string("TOSA-1.0+FP")
54+
55+
tosa_version = tosa_spec.version # type: ignore[attr-defined]
56+
tosa_profiles = tosa_spec.profiles # type: ignore[attr-defined]
57+
58+
if tosa_version.major != 1:
59+
raise ValueError(
60+
"Arm backend only supports converter-backend for TOSA version 1. "
61+
f"Invalid TOSA version: {tosa_version}"
62+
)
63+
64+
if "FP" not in tosa_profiles and "INT" not in tosa_profiles:
65+
raise ValueError(
66+
"Arm backend only supports converter-backend for FP or INT. "
67+
f"Invalid TOSA profile: {tosa_profiles}"
68+
)
69+
70+
if len(tosa_profiles) != 1:
71+
raise ValueError(
72+
"For now Arm backend only supports converter-backend for either FP or INT. "
73+
f"Invalid TOSA profile: {tosa_profiles}"
74+
)
75+
76+
self.tosa_spec = tosa_spec
77+
78+
return self
79+
80+
def ethosu_compile_spec(
81+
self,
82+
target: str,
83+
system_config: Optional[str] = None,
84+
memory_mode: Optional[str] = None,
85+
extra_flags: Optional[str] = None,
86+
config_ini: Optional[str] = "Arm/vela.ini",
87+
) -> "ArmCompileSpecBuilder":
88+
"""
89+
Generate compile spec for Ethos-U NPU
90+
91+
Args:
92+
target: Ethos-U accelerator configuration, e.g. ethos-u55-128
93+
system_config: System configuration to select from the Vel
94+
configuration file
95+
memory_mode: Memory mode to select from the Vela configuration file
96+
extra_flags: Extra flags for the Vela compiler
97+
config_ini: Vela configuration file(s) in Python ConfigParser .ini
98+
file format
99+
"""
100+
assert (
101+
self.output_format is None
102+
), f"Output format already set to f{self.output_format}"
103+
self.output_format = "vela"
104+
self.compiler_flags = [
105+
f"--accelerator-config={target}",
106+
f"--config={config_ini}",
107+
]
108+
109+
# default system config and memory mode
110+
if "ethos-u55" in target:
111+
if system_config is None:
112+
system_config = "Ethos_U55_High_End_Embedded"
113+
if memory_mode is None:
114+
memory_mode = "Shared_Sram"
115+
elif "ethos-u85" in target:
116+
if system_config is None:
117+
system_config = "Ethos_U85_SYS_DRAM_Mid"
118+
if memory_mode is None:
119+
memory_mode = "Sram_Only"
120+
else:
121+
raise RuntimeError(f"Unknown ethos target: {target}")
122+
123+
if system_config is not None:
124+
self.compiler_flags.append(f"--system-config={system_config}")
125+
if memory_mode is not None:
126+
self.compiler_flags.append(f"--memory-mode={memory_mode}")
127+
if extra_flags is not None:
128+
self.compiler_flags.append(extra_flags)
129+
130+
# We require raw output and regor, so add these flags if absent. This
131+
# overrides any other output setting.
132+
self.compiler_flags.append("--output-format=raw")
133+
self.compiler_flags.append("--debug-force-regor")
134+
135+
base_tosa_version = "TOSA-1.0+INT+int16"
136+
if "u55" in target:
137+
# Add the Ethos-U55 extension marker
138+
base_tosa_version += "+u55"
139+
self.tosa_spec = TosaSpecification.create_from_string(base_tosa_version)
140+
141+
return self
142+
143+
def tosa_compile_spec(
144+
self, tosa_spec: str | TosaSpecification
145+
) -> "ArmCompileSpecBuilder":
146+
"""
147+
Generate compile spec for TOSA flatbuffer output
148+
"""
149+
assert (
150+
self.output_format is None
151+
), f"Output format already set: {self.output_format}"
152+
self.output_format = "tosa"
153+
if isinstance(tosa_spec, TosaSpecification):
154+
self.tosa_spec = tosa_spec
155+
elif isinstance(tosa_spec, str):
156+
self.tosa_spec = TosaSpecification.create_from_string(tosa_spec)
157+
else:
158+
raise RuntimeError(f"Invalid type for {tosa_spec}!")
159+
return self
160+
161+
def dump_intermediate_artifacts_to(
162+
self, output_path: str
163+
) -> "ArmCompileSpecBuilder":
164+
"""
165+
Sets a path for dumping intermediate results during such as tosa and pte.
166+
"""
167+
self.path_for_intermediates = output_path
168+
return self
169+
170+
def dump_debug_info(self, debug_mode: DebugMode) -> "ArmCompileSpecBuilder":
171+
"""
172+
Dump debugging information into the intermediates path
173+
"""
174+
self.tosa_debug_mode = debug_mode.name
175+
return self
176+
177+
def build(self) -> List[CompileSpec]:
178+
"""
179+
Generate a list of compile spec objects from the builder
180+
"""
181+
assert self.tosa_spec
182+
183+
# Always supply a TOSA version
184+
self.compile_spec = [CompileSpec("tosa_spec", str(self.tosa_spec).encode())]
185+
186+
# Add compile flags, these are backend specific, refer to the backend
187+
# documentation.
188+
self.compile_spec += [
189+
CompileSpec("compile_flags", " ".join(self.compiler_flags).encode()),
190+
]
191+
192+
# encode output format
193+
self.compile_spec.append(
194+
CompileSpec("output_format", self.output_format.encode())
195+
)
196+
197+
if self.path_for_intermediates is not None:
198+
self.compile_spec.append(
199+
CompileSpec("debug_artifact_path", self.path_for_intermediates.encode())
200+
)
201+
202+
if self.tosa_debug_mode is not None:
203+
if not self.path_for_intermediates:
204+
raise ValueError(
205+
"dump_debug_info() must be used in conjunction with dump_intermediate_artifacts_to()"
206+
)
207+
208+
self.compile_spec.append(
209+
CompileSpec("dump_debug_info", self.tosa_debug_mode.encode())
210+
)
211+
212+
return self.compile_spec
213+
214+
215+
def is_tosa(compile_spec: List[CompileSpec]) -> bool:
216+
has_tosa_output = False
217+
has_tosa_spec = False
218+
for spec in compile_spec:
219+
if spec.key == "output_format":
220+
has_tosa_output = spec.value.decode() == "tosa"
221+
if spec.key == "tosa_spec":
222+
has_tosa_spec = True
223+
224+
return has_tosa_output and has_tosa_spec
225+
226+
227+
def is_ethosu(compile_spec: List[CompileSpec]) -> bool:
228+
for spec in compile_spec:
229+
if spec.key == "output_format":
230+
return spec.value.decode() == "vela"
231+
return False
232+
233+
234+
def is_vgf(compile_spec: List[CompileSpec]) -> bool:
235+
for spec in compile_spec:
236+
if spec.key == "output_format":
237+
return spec.value.decode() == "vgf"
238+
return False
239+
240+
241+
def get_intermediate_path(compile_spec: List[CompileSpec]) -> Optional[str]:
242+
for spec in compile_spec:
243+
if spec.key == "debug_artifact_path":
244+
return spec.value.decode()
245+
return None

0 commit comments

Comments
 (0)