Skip to content

Add OpBackend, for backends that lower by rewriting operators - #22366

Draft
rascani wants to merge 1 commit into
mainfrom
rascani/opbackend-abc
Draft

Add OpBackend, for backends that lower by rewriting operators#22366
rascani wants to merge 1 commit into
mainfrom
rascani/opbackend-abc

Conversation

@rascani

@rascani rascani commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

A Partitioner may only tag nodes -- to_backend asserts the graph it returns
is identical -- so a backend whose kernels replace operators in place has no
interface of its own. Arm's ReplaceQuantNodesPass and the Cortex-M pass
manager each reach for a different hook; #21516 asks for a third.

OpBackend.lower(ep, method_name) -> ep is that interface, and
EdgeProgramManager.to_op_backend applies one to every method. to_executorch
is only reachable from a manager, so a manager method is the useful shape; it
carries the constant methods and the etrecord across the rebuild.

Unlike to_backend it also carries the rest of the compile config rather than
replacing it, so _skip_dim_order -- which the explicit-layout work needs --
survives. That holds for a recipe with no partitioner, which is the
op-library case this exists for; behind a delegate partitioner to_backend
has already replaced the config before an operator backend runs, and giving
composition its own answer is left to that work.

Each backend gets a private copy of the program: a deep copy of the graph, and
its own state dict, constants, graph signature and range constraints. The
passes backends are built from rewrite in place, and the helper the contract
points at for adding an input inserts into graph_signature.input_specs, so
without the copy the caller's program -- still held as an earlier stage's
artifact -- is rewritten too, and left half-rewritten if the backend raises.
The weights the graph refers to are shared, not duplicated.

Adding an input is the easy way to return a program its own graph signature no
longer describes, so the returned program is checked before it is handed on:
unchecked, that surfaces as a message-less assertion in a pre-emit pass or a
bare KeyError from the emitter, naming neither the backend nor the input.
ExportedProgram.validate() would be the obvious check and is the wrong one --
it re-enters the edge verifier, which rejects the operators an operator backend
exists to install.

Marked experimental: one implementer, one commit of history. The decorator on
an ABC warns once per implementing module, at the class statement.

Nothing calls this yet. The recipe support that does is the next commit.

Authored with Claude Code.

A `Partitioner` may only tag nodes -- `to_backend` asserts the graph it returns
is identical -- so a backend whose kernels replace operators in place has no
interface of its own. Arm's `ReplaceQuantNodesPass` and the Cortex-M pass
manager each reach for a different hook; #21516 asks for a third.

`OpBackend.lower(ep, method_name) -> ep` is that interface, and
`EdgeProgramManager.to_op_backend` applies one to every method. `to_executorch`
is only reachable from a manager, so a manager method is the useful shape; it
carries the constant methods and the etrecord across the rebuild.

Unlike `to_backend` it also carries the rest of the compile config rather than
replacing it, so `_skip_dim_order` -- which the explicit-layout work needs --
survives. That holds for a recipe with no partitioner, which is the
op-library case this exists for; behind a delegate partitioner `to_backend`
has already replaced the config before an operator backend runs, and giving
composition its own answer is left to that work.

Each backend gets a private copy of the program: a deep copy of the graph, and
its own state dict, constants, graph signature and range constraints. The
passes backends are built from rewrite in place, and the helper the contract
points at for adding an input inserts into `graph_signature.input_specs`, so
without the copy the caller's program -- still held as an earlier stage's
artifact -- is rewritten too, and left half-rewritten if the backend raises.
The weights the graph refers to are shared, not duplicated.

Adding an input is the easy way to return a program its own graph signature no
longer describes, so the returned program is checked before it is handed on:
unchecked, that surfaces as a message-less assertion in a pre-emit pass or a
bare `KeyError` from the emitter, naming neither the backend nor the input.
`ExportedProgram.validate()` would be the obvious check and is the wrong one --
it re-enters the edge verifier, which rejects the operators an operator backend
exists to install.

Marked experimental: one implementer, one commit of history. The decorator on
an ABC warns once per implementing module, at the `class` statement.

Nothing calls this yet. The recipe support that does is the next commit.

Authored with Claude Code.
@pytorch-bot

pytorch-bot Bot commented Aug 31, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/22366

Note: Links to docs will display an error until the docs builds have been completed.

❌ 2 New Failures, 4 Unrelated Failures

As of commit d6d7380 with merge base 6067c7a (image):

NEW FAILURES - The following jobs have failed:

FLAKY - The following job failed but was likely due to flakiness present on trunk:

BROKEN TRUNK - The following jobs failed but was present on the merge base:

👉 Rebase onto the `viable/strict` branch to avoid these failures

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Aug 31, 2026
@github-actions

Copy link
Copy Markdown

This PR needs a release notes: label

If your change should be included in the release notes (i.e. would users of this library care about this change?), please use a label starting with release notes:. This helps us keep track and include your important work in the next release notes.

To add a label, you can comment to pytorchbot, for example
@pytorchbot label "release notes: none"

For more information, see
https://github.com/pytorch/pytorch/wiki/PyTorch-AutoLabel-Bot#why-categorize-for-release-notes-and-how-does-it-work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant