Skip to main content

arm

Develop, debug, or explain the Arm backend in backends/arm/ and its community-facing examples in examples/arm/. Covers partitioning, TOSA lowering, VGF, Ethos-U, quantization, graph passes, memory layout, and node visitors. Not for development of other backends.

Source facts

Repository
pytorch/executorch
Last source activity
October 28, 2026 at 07:53
Detected SKILL.md language
English
Stars
5,154
Forks
1,239

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
arm
description
Develop, debug, or explain the Arm backend in backends/arm/ and its community-facing examples in examples/arm/. Covers partitioning, TOSA lowering, VGF, Ethos-U, quantization, graph passes, memory layout, and node visitors. Not for development of other backends.
# Arm Backend Development Use this guide to choose the implementation layer and validation path, then read the relevant code for current interfaces. Scope work to `backends/arm/` and its supporting examples and tests. ## Arm Targets and Code Map The Arm backend lowers to TOSA IR. Target-specific compilation then produces VGF using Model Converter or Ethos-U NPU code using Vela. TOSA versions, profiles, and extensions affect supported operations and lowering choices; consult `TosaSpecification` in `backends/arm/tosa/specification.py`. Specification documents are available at <https://www.mlplatform.org/tosa/>. | Location | Responsibility | |----------|----------------| | `backends/arm/quantizer/` | Quantization annotation and configuration | | `backends/arm/common/arm_compile_spec.py` | Shared Arm compile configuration | | `backends/arm/tosa/` | TOSA backend, partitioner, and compile spec | | `backends/arm/tosa/partitioner.py` | Shared capability-based partitioning, delegation tags, and partition-boundary handling | | `backends/arm/operator_support/` | Operator eligibility and target-specific restrictions; `tosa_supported_operators.py` composes support checks | | `backends/arm/tosa/specification.py` | TOSA versions, profiles, extensions, and target support | | `backends/arm/vgf/` | VGF backend, partitioner, and compile spec | | `backends/arm/vgf/partitioner.py` | VGF specialization of the shared TOSA partitioner | | `backends/arm/ethosu/` | Ethos-U backend, partitioner, and compile spec | | `backends/arm/ethosu/partitioner.py` | Ethos-U specialization of the shared TOSA partitioner | | `backends/arm/_passes/arm_pass_manager.py` | Pass ordering and pipeline configuration | | `backends/arm/_passes/` | Decompositions, layout handling, dialect conversion, and optimizations | | `backends/arm/operators/` | Node visitors and TOSA serialization | | `backends/arm/test/tester/test_pipeline.py` | Reusable lowering, execution, and pass-test pipelines | | `backends/arm/test/` | Operator, pass, model, and integration tests | | `examples/arm/` | Community-facing getting-started and evaluation examples; dependency setup | ## Partitioning Partitioning selects supported regions of the Edge graph for delegation before backend lowering. `TOSAPartitioner` uses capability-based partitioning to group eligible nodes and assign `delegation_tag` metadata. Its `DelegationSpec` selects the backend and compile specs used to lower each region. `VgfPartitioner` and `EthosUPartitioner` reuse this machinery with target-specific configuration. Nodes left outside delegates remain in the ExecuTorch graph and need suitable runtime kernels; partial delegation is not itself a lowering failure. Operator eligibility is more than the presence of a node visitor. Support checks in `backends/arm/operator_support/` account for the selected TOSA specification, target restrictions, dtypes, shapes, quantization, and operator arguments. `tosa_support_factory` combines positive support checks with rejection checks; `additional_checks` adds restrictions, not new lowering implementations. When changing or debugging partitioning: - Use `WhyNoPartitionReporter` rejection reasons and inspect delegation tags to understand why nodes were excluded before broadening support checks. - Change operator eligibility in the support checks; change region grouping or boundary handling in the partitioner. Keep graph rewrites in the appropriate transformation passes rather than hiding missing lowering support in checks. - Preserve Q/DQ boundaries and constant or mutable-buffer ownership when changing region boundaries. Acceptance must agree with what the selected backend can actually lower and execute. - Test both accepted and rejected cases, partition boundaries, and fallback behavior. Start with `backends/arm/test/misc/test_tosa_operator_support.py` for support checks and `backends/arm/test/misc/test_custom_partition.py` for partitioning examples; use operator pipelines to verify delegated execution. ## Arm Lowering Pipeline The pass manager is authoritative for ordering and target-specific differences. The responsibilities below are not a fixed execution sequence; passes can be interleaved or repeated: - Q/DQ folding attaches quantization parameters to nodes and removes folded Q/DQ operators; - Decompositions rewrite ATen operators toward TOSA forms. - Memory-layout lowering first wraps channels-last nodes with input and output permutes: channels-first to channels-last before the node, and the inverse after it. This preserves the surrounding graph's channels-first semantics. Later propagation moves permutes through compatible operators, bringing inverse pairs together so they cancel instead of transposing at every node. Necessary conversions remain at layout boundaries; not all permutes disappear. - Dialect conversion maps lowered Edge/ATen operators to TOSA equivalents; optimizations deduplicate nodes, remove no-ops, and fuse operators. - Node visitors serialize the lowered graph with `tosa_serializer`, before target-specific compilation. ## Implementation Decisions - Extend nearby implementations, interfaces, and helper methods before adding parallel mechanisms. Fix the earliest responsible layer rather than recovering from an error later in lowering. - Before modifying quantizer annotations or configuration, read `examples/arm/quantizer_tutorial.ipynb` for the quantization workflow and extension examples. Keep the tutorial aligned with quantizer API changes. - Missing quantization parameters generally belong in the quantizer, not in downstream code that reconstructs them. Decompositions whose resulting operators need separate quantization parameters belong before annotation. - Handle memory-layout issues in the existing layout and permute-propagation passes. Lowering retraces with fake tensors, not real tensor data; preserve dtype metadata and both static and symbolic shapes through rewrites. - Keep decompositions and complex graph rewrites out of node visitors; perform them in earlier passes so visitors remain serialization-focused. - Respect pass dependencies and ordering instead of repeating work already guaranteed by an earlier pass. - Preserve existing behavior; notify the user of intentional compatibility changes. If a refactor would materially simplify the implementation, suggest it before expanding the patch. ## Static and Dynamic Shapes When changing shape-dependent operators, symbolic arithmetic, inferred reshape dimensions, or dynamic padding, read `backends/arm/SYMINT_ET_LOWERING.md` first. Static dimensions are integer constants; dynamic dimensions are represented by `SymInt` expressions and FX producers such as `aten.sym_size.int`. TOSA consumes one-dimensional shape operands, not scalar symbolic values: dynamic dimensions lower to `DIM`, constants to `CONST_SHAPE`, and mixed shape lists to `CONCAT_SHAPE` when materialized. Symbolic representation alone does not imply dynamic-shape support for every target or operator. Check the selected TOSA specification, extensions, and partitioner restrictions before accepting a dynamic-shape case. Keep responsibilities separate: `ResolveViewCopyInferredDimPass` resolves `-1` and materializes inferred symbolic dimensions into FX producers before `SymbolicToTosaShapesPass` lowers them to TOSA shape operands. `SymbolMaterializationHelpers` builds and reuses TOSA shape nodes; it does not lower arbitrary raw `SymInt` values. Preserve shape metadata and test both static and dynamic cases. Exercise the same dynamically exported program with multiple valid input sizes, including sizes different from the export example, to detect accidental specialization. Keep sizes within the exported constraints. ## Community-Facing Examples Examples in `examples/arm/` are a front door for the community to get started with and evaluate ExecuTorch, not just internal test fixtures. For Arm TOSA, VGF, and Ethos-U examples: - Make the documented path easy and intuitive to follow without internal knowledge. State prerequisites, target requirements, commands, expected artifacts, and how to recognize successful execution. - Keep the main export-to-execution flow readable and focused. Put optional tuning and advanced configurations after the working baseline, rather than obscuring it with internal abstractions or test-only machinery. - Keep scripts, notebooks, README commands, and backend APIs consistent when changing interfaces. Start with `examples/arm/README.md` and the affected example's own README. - Maintain automated coverage of the documented path so examples do not go stale. Use lightweight smoke/export tests where possible and target execution tests where dependencies are available; check meaningful outputs, not just successful imports. Reuse existing example tests such as `backends/arm/test/misc/test_silero_vad_example.py` where applicable. - Keep hardware/toolchain-dependent coverage explicit and report untested steps. Mocked helper tests do not establish that the full example works. `examples/arm/setup.sh` installs dependencies such as compilers, Fixed Virtual Platforms (FVPs), and drivers; `examples/arm/arm-scratch/setup_path.sh` sets up tool paths. Use the configured project environment and setup instructions. ## Choosing Tests Use pipelines from `backends/arm/test/tester/test_pipeline.py` and follow nearby tests rather than assembling a separate lowering flow: | Change or target | Test entry point and dependencies | |------------------|-----------------------------------| | Individual graph pass | `backends/arm/test/passes/` with `PassPipeline`; e.g. `test_remove_clone_pass.py` | | TOSA operator correctness | `backends/arm/test/ops/test_add.py` shows `TosaPipelineFP` and `TosaPipelineINT`; numerical execution uses the TOSA reference model, not an FVP | | Ethos-U execution | `EthosU55PipelineINT` / `EthosU65PipelineINT` use Corstone-300; `EthosU85PipelineINT` uses Corstone-320; requires Vela, target runner, and the matching FVP | | VGF execution | `VgfPipeline` compiles with Model Converter and compares outputs through the Vulkan runtime; requires the matching runner and usable Vulkan environment | `run_on_tosa_ref_model=False`, `run_on_fvp=False`, and `run_on_vulkan_runtime=False` omit their respective execution checks. Do not describe those runs as numerical validation on that reference model or target. Preserve existing dependency markers and expected-failure conventions. For example, after activating the project environment and Arm tool paths: ```bash pytest -c backends/arm/test/pytest.ini backends/arm/test/ops/test_add.py -k tosa pytest -c backends/arm/test/pytest.ini backends/arm/test/passes/test_remove_clone_pass.py ``` Start with the test relevant to the change, then broaden to affected targets, specifications, and shape modes as needed. ## Regression Checks Consider numerical accuracy, final-model performance, and AoT lowering time for every behavior change. Nontrivial decomposition changes need accuracy and performance evaluation. For graph-wide quadratic algorithms, evaluate whether a more efficient approach is practical. Suggest measurements and alternatives when a regression is plausible; do not claim unmeasured results. Before finalizing non-prototyping implementation changes, run the configured pre-push hook (`.git/hooks/pre-push`, or the hook under `core.hooksPath` in a worktree) through the project environment and address failures caused by the change. If execution requires approval or is blocked, report that rather than claiming it passed. For documentation-only changes, use focused documentation or skill validation and whitespace checks instead; explanations without file changes need no hook.
View on GitHub