Skip to content

fix(executorch): lift nested and partitioner-excluded mutable buffers - #4470

Closed
shoumikhin wants to merge 16 commits into
pytorch:mainfrom
shoumikhin:fix-nested-buffer-lifting
Closed

fix(executorch): lift nested and partitioner-excluded mutable buffers#4470
shoumikhin wants to merge 16 commits into
pytorch:mainfrom
shoumikhin:fix-nested-buffer-lifting

Conversation

@shoumikhin

@shoumikhinshoumikhin commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Depends on #4459. These fixes are on top of that branch, so the file diff here
includes its commits and CI will stay red until it lands. Only the last four commits
are mine (af29266c7ed4..HEAD), at +280/-20 across five files, three of which are
tests.

What this fixes

Two problems that stop a model from exporting when part of its graph runs on a different
backend, plus the nested-buffer follow-ups that only become visible once the graph gets
that far.

1. An op excluded from TensorRT was predicted to alias

_kv_write_will_alias decides whether a buffer write becomes engine-level aliasing by
looking at the op, and never saw the ops the caller excluded via torch_executed_ops. An
excluded write was still predicted to alias, its copy_ was dropped, and the cross-check
in compile() then failed:

RuntimeError: lift_mutated_buffers classified these buffer writes as KV-cache
(engine-aliased) and dropped their copy_, but the compiled engine did not alias them
(absent from aliased_io): [...]. Their write-back would be silently dropped.

An op that never reaches a converter cannot emit an IKVCacheUpdateLayer, so the
prediction now honors the exclusion list, matched with
ConverterRegistry.qualified_name_or_str the same way the partitioners match it. The
write is still lifted and still copied back, like any other write the engine does not
alias.

That guard is worth calling out: it turned a cache that would silently stop updating into
a clear error naming every affected buffer.

2. A copy-back output could be paired with the wrong buffer

lift_mutated_buffers appends each copy-back buffer's new value as a trailing output, in
copyback_buffers order, and the exporter reclassified them by taking the last N.

That breaks once torch.export recognises a mutation itself, because it then records its
own BUFFER_MUTATION and moves it ahead of the user outputs. Filtering the buffer list
first and slicing the same number of trailing outputs shifts the two lists against each
other:

buffers [a, b, c], b already declared
pending [a, c] -> takes the last two values, which are b's and c's
result a is declared as the mutation of b's value

With different shapes the runtime fails copying that value into the buffer; with matching
shapes it silently writes the wrong state. On a transformer whose cache write stays inside
the engine, an earlier form of this bug declared the model's logits as a cache update and
export failed with expand: attempting to expand a dimension of length 16 -> 4096.

The fix detaches the full trailing run first and pairs it positionally with the full
buffer list, then keeps only the buffers not already declared. When every buffer was
already declared, nothing used to be detached and the appended values stayed as user
outputs, changing the saved model's output arity.

3. Renamed nested buffers left the mutation targets dangling

register_buffer rejects dots, so a nested buffer is renamed to lifted_buf_*. The
recorded mutation targets kept the original dotted names, which no longer resolve:

SpecViolationError: Buffer output getitem_1 does not point to a buffer that exists.
mutated target : 'layers.0.self_attn.kv_cache.k_cache'
buffer available : 'lifted_buf_layers_0_self_attn_kv_cache_k_cache'

They are remapped through the same mapping.

What changed since the first version

The first version of this PR also skipped an excluded buffer entirely, leaving the
get_attr and copy_ in place, on the theory that another backend would claim the write.
That was wrong outside ExecuTorch. lift_mutated_buffers runs for every compile()
caller, and post_lowering's remove_num_users_is_0_nodes erases the orphaned copy_
because nothing reads it, so the buffer froze at its compile-time contents and the cache
silently stopped updating. Worse, that input used to fail loudly at the cross-check above,
so the skip turned a clear error into wrong numbers.

The delegate-boundary error that motivated the skip has a different cause. ExecuTorch only
rejects a mutation consumed after a delegate when the delegate also absorbed the
buffer
; returning a mutation value out of a delegate is a supported, tested path
(exir/backend/test/test_partitioner.py::test_not_delegate_mutable_buffers). Absorption is
already prevented, by tag_constant_data skipping mutated buffers and by
_keep_mutated_buffers_above_delegate covering the case it misses. So the copy-back route
handles this correctly and no skip is needed.

Also dropped gm.meta["_lifted_buffer_attr_names"], which had no reader.

Testing

tests/py/dynamo/lowering/test_buffer_lifting.py and
tests/py/dynamo/executorch/test_kv_cache_export.py, plus three new regression tests,
each of which fails on the behavior it replaces:

  • test_torch_executed_write_is_copyback_not_kv: an excluded write is lifted, recorded as
    copy-back rather than predicted-aliased, and leaves no dead nodes for post_lowering to
    erase.
  • test_declare_aliased_kv_mutations_pairs_copyback_by_position: with [a, b, c] and only
    b already declared, each buffer is paired with its own value.
  • test_declare_aliased_kv_mutations_skips_already_declared_copyback: an already-declared
    buffer is not declared twice, and its trailing value still leaves the user outputs.

Note the nested-buffer lookup itself (gm.get_buffer) landed separately in #4472 and is
inherited here through this branch's base, so it is no longer part of this PR's changes.

@github-actionsgithub-actionsBot added component: tests Issues re: Tests component: lowering Issues re: The lowering / preprocessing passes component: core Issues re: The core compiler component: api [Python] Issues re: Python API component: api [C++] Issues re: C++ API component: runtime component: dynamo Issues relating to the `torch.compile` or `torch._dynamo.export` paths labels Aug 8, 2026
@shoumikhin
shoumikhinforce-pushed the fix-nested-buffer-lifting branch from 197acc4 to 0c52ff5CompareAugust 12, 2026 02:30
@shoumikhin

Copy link
Copy Markdown
ContributorAuthor

Pushed an amendment to this PR.

What changed

A copy-back value is now paired with its buffer by name rather than by position.

The old code assumed those values were always the last outputs:

copyback_getitems=list(out_args[-num_copyback:])

That assumption does not always hold. torch.export usually leaves them at the end, but
when it recognises the mutation itself it declares them BUFFER_MUTATION and moves them
to the front, because the verifier requires mutations to come before user outputs.
Taking the tail unconditionally then grabs a real user output and relabels it as a buffer
mutation.

How it showed up

On a transformer whose cache write stays inside the engine, it declared the model's
logits as a cache update. Five mutation specs for four buffers, one of them pointing at a
tensor of a completely different shape:

layers_1 v_cache <- (1, 16, 202048) the logits
layers_0 k_cache <- declared twice

Export then failed at runtime lowering:

RuntimeError: expand: attempting to expand a dimension of length 16 -> 4096

16 is the sequence length and 4096 is the cache length, which is the shape mismatch you
would expect from copying a user output into a cache buffer.

The fix

Reclassify only the buffers the program does not already declare as mutated:

already_mutated= {
spec.targetforspecinorig_specsifspec.kind==OutputKind.BUFFER_MUTATIONandisinstance(spec.target, str)
}
pending_copyback= [bufforbufincopyback_buffersifbufnotinalready_mutated]

This makes the pass idempotent with respect to what torch.export already recorded. The
companion if num_copyback and module_call_graph guard became
if copyback_specs and module_call_graph, so the output spec is only rebuilt when this
pass actually moved outputs. Rebuilding it after reclassifying nothing would drop a leaf
count that already matched.

After the change the same model exports and produces four mutation specs for four
buffers, each cache appearing exactly once, with the logits left as a user output.

@shoumikhin

Copy link
Copy Markdown
ContributorAuthor

Rebased onto your updated #4459 (5e7b37d). Two add/add conflicts, both in the copy-back remap comment, resolved in favor of your wording since #4459 now carries that fix itself.

One collision worth your call. Your new commit raises RuntimeError when a copy-back buffer already carries a BUFFER_MUTATION spec, because positional reclassification would retarget the trailing outputs. My commit on top fixes that positional pairing: it detaches the full num_copyback run and pairs it against the full copyback_buffers list before filtering, so an already-declared buffer is skipped rather than shifting the run.

So we now have two contracts for the same situation. Your test_declare_aliased_kv_mutations_rejects_redeclared_copyback expects the raise; my test_declare_aliased_kv_mutations_skips_already_declared_copyback expects a graceful skip. They do not always both fire, since your guard reads _kv_exposed_mutation_targets while mine reads graph_signature.output_specs, but the intent differs.

My read is that the raise is still correct for the KV path your guard watches, and the graceful skip is correct for the torch.export-declared case, so both can stand if we scope the guard to the KV targets explicitly. Happy to do that, or to drop my overlapping test and let the raise be the single contract, whichever you prefer for #4459.

Adds end-to-end caller-owned KV-cache support to the ExecuTorch TensorRT
delegate: the KV buffers are owned by the caller above the delegate and threaded
in as mutable-buffer delegate args, instead of being self-allocated inside a
(stateless) TensorRT engine.
Runtime + serialization (delegate):
- serialize each engine's aliased (KV-cache / in-place) I/O into the delegate blob
(serialization.py, backend.py, TensorRTBlobHeader.{h,cpp});
- at runtime bind each aliased TRT output binding to its aliased input's
caller-provided pointer (in-place) and reflect the result into the delegate
output EValue -- a no-op when the memory planner already aliased the two
(TensorRTBackend.{h,cpp}).
Export/lowering (torch_tensorrt):
- expose each engine's aliased outputs as graph-level BUFFER_MUTATIONs so
ExecuTorch keeps the KV buffers as caller-owned mutable buffers: at transform
time for the legacy exporter (retrace=False), and via a post-export pass
(_declare_aliased_kv_mutations_on_ep) for torch.export (retrace=True), which
otherwise truncates the aliased outputs at the fx boundary;
- keep delegate-mutated buffers above the delegate in TensorRTPartitioner
(tag_constant_data would otherwise freeze them as constants).
The retrace=True pass runs for exported_program as well as executorch. The
truncation happens at the fx boundary for every output format, so declaring only
on the executorch path left an exported_program saved with the mutation absent
from its signature while the engine still updated the cache in place. It is
declared before _normalize_engine_constants_to_python, which rewrites the engine
constants the pass reads aliased_io from. retrace=False was already correct for
every format via create_trt_exp_program. aot_inductor stays undeclared and
warns: whether an aliased in-place mutation survives functionalization under
inductor is unverified.
Tests cover serialization round-trip, the exposure-flag dispatch across both
retrace modes, the buffer-mutation declaration, and the partitioner un-tagging.
…mutations
_declare_aliased_kv_mutations_on_ep rebuilds the ExportedProgram to attach the
new output specs, but reconstructed only root/graph/signature/state_dict/
range_constraints/module_call_graph/constants. example_inputs and verifiers are
not recoverable from the graph and reset to their defaults when omitted, so the
pass was not a drop-in replacement for the program it rewrites.
That was invisible while the pass ran only on the executorch path, since to_edge
does not read either. Declaring mutations for exported_program as well makes it
reachable: torch.export.save then persists a program whose example inputs are
silently gone. AOTI refuses such a program outright ("exported_program.
example_inputs is required to be set in order for AOTInductor compilation"), so
this also has to be fixed before that format can ever declare mutations.
Carry both through. The stub programs in test_kv_cache_export.py now model them,
and the capturing test asserts they reach the constructor.
Reported by cehongwang in review.
Whether an aliased KV output gets declared a BUFFER_MUTATION is decided in two
places: the exporter (the legacy one declares at transform time, via
create_trt_exp_program) and save()'s per-output-format branch. Nothing reconciles
them, so a program that arrives already declared is declared a second time. The
duplicate spec then fails the ExportedProgram verifier's output ordering check.
Seed already_exposed from the incoming signature's BUFFER_MUTATION targets rather
than an empty set, so the pass skips buffers that are already declared and returns
the program untouched when nothing new remains.
That covers every combination that reaches it, including exported_program with
use_legacy_exporter=True, which the preceding commit made reachable.
The added test drives the pass on an already-declared program with
ExportedProgram monkeypatched to raise, so a regression fails on "rebuilt the
program" rather than on some later verifier complaint. The no-op fixture grows an
output_specs field, which a real ExportGraphSignature always has.
Reported by shoumikhin in review.
Four comments describe a zero-copy path where the memory planner places the
delegate's output slot on the aliased input, so the reflect is skipped. That
never happens: the delegate input and its aliased output are live at the same
time, so the planner cannot co-locate them. Instrumenting the branch over a
30-layer export confirms it -- dst == bind_ptr was false for all 120 aliased
outputs across a prefill and a decode step.
Two of them go further and call the skipped case the common fast path, which
inverts what the code does: every aliased output reflects, and a model with
aliased outputs therefore always syncs before returning.
Say what actually happens in all four (TensorRTBackend.h, and the reflect list,
the reflect loop and the must_sync rationale in TensorRTBackend.cpp). The
dst != bind_ptr check itself stays -- it is unreachable today, but it is what
stops a self-copy if planning ever changes -- and its comment now says so
instead of advertising a fast path.
Also two comment fixes found in the same pass: "These two" in _exporter.py
referred forward to checks the reader had not reached yet, and a test comment
said "previously-dropped" where it meant the output torch.export truncates.
No behaviour change.
Reported by shoumikhin in review.
The aliased-output branch discarded the resize_tensor result and skipped the
resize altogether when the rank was out of range, while the sibling non-aliased
branch treats both as fatal.
et_alias_out.nbytes() is read on the next line and sizes both the reflect D2D
copy and, through the delegate output EValue, ExecuTorch's write-back copy_. A
dynamic aliased output that outgrows its planned size would therefore move the
stale planned byte count in both, silently truncating the cache update rather
than failing.
Mirror the sibling branch: reject an out-of-range rank and propagate a
resize_tensor error.
Reported by shoumikhin in review.
…th too
Whether an aliased KV output is declared a BUFFER_MUTATION depends on two
independent switches. save() picks the exporter (retrace, plus an optional
use_legacy_exporter override) and only the legacy exporter exposes the mutations,
at transform time; save()'s per-format branch declares them for everything else.
The retrace=False branch did neither, so retrace=False with
use_legacy_exporter=False produced a program that silently omits an update the
engine performs -- no declaration and no diagnostic.
Run the declaration pass on the exported_program and executorch branches there as
well. The preceding commit made the pass skip buffers that already carry a spec,
so this is correct for either exporter: the legacy one keeps declaring at
transform time and the pass returns its program untouched.
aot_inductor stays undeclared on both paths, as before.
The added test drives save() over both formats and both exporters and asserts the
pass runs exactly once; against the previous commit all four parametrizations
fail.
Reported by shoumikhin in review.
The runtime binds delegate output i to output_binding_names[i]. That holds
because the partition's outputs are getitem(engine_node, i) in index order, and
nothing verifies it: inputs are checked in _reorder_input_names_for_executorch,
outputs were not. arrange_graph_outputs moves buffer mutations ahead of user
outputs and is a no-op here only while the mutated buffers stay above the
delegate, so a regression there would swap the serialized names silently.
Validate the correspondence in preprocess. A single-output engine returned
unwrapped is accepted -- one binding has no order to get wrong -- and anything
else must be one getitem per binding, in index order.
_build_edge_program only ever emitted `output((engine_node,))`, including for its
three-output-binding case, which is not a shape that can occur: a three-tuple
cannot be consumed as one value. It now emits one getitem per output binding, so
the fixtures model what the backend actually receives.
Reported by shoumikhin in review.
…d_io
aliased_io changes what a blob means. A parser that predates it binds each
aliased output to its own allocation instead of the input it aliases, so it does
not fail -- it returns wrong results. The magic is the only field that parser
validates, so it is the only thing that can make the skew fail closed.
Emit TR02 when metadata.aliased_io is non-empty and keep TR01 otherwise, rather
than bumping unconditionally: a blob with no alias map means exactly what it
meant before, so it stays loadable by an older runtime. Both magics are accepted
on read, so new runtimes still load existing artifacts.
Verified against a real older build rather than a simulated one: a TR02 blob
loads and produces the expected KV-persistence result on a runtime built from
this branch, and a runtime built before the change rejects the same blob with
"failed to parse TensorRT blob".
Reported by shoumikhin in review.
…r verify
The caller-owned KV path had no CI coverage: kv_cache_decode_check ships in the
release tarball and is defined in the packaged CMake project, but nothing built
or ran it, so a regression in the aliased binding would only surface downstream.
Export a decode .pte alongside the static-shape one and pass it to the verify
script as an optional second argument. When present the script builds
kv_cache_decode_check from the unpacked tarball, runs it, and requires the
persistence assertion to pass; the same no-libtorch link check the example runner
gets is applied to it. Without the argument the script behaves as before.
Also assert the tarball ships kv_cache_decode_check.cpp, next to the existing
entries, so the packaging contract is checked rather than assumed.
Reported by shoumikhin in review.
…ering claim
Four `continue`s in _declare_aliased_kv_mutations_on_ep left an aliased output
undeclared without saying so, and the mismatch only surfaced later as a delegate
arity error at execute. Log at each, at the level the case warrants: warn when the
persisted alias map disagrees with the engine's bindings (unknown input name, or
an index past the delegate args) and when the aliased input is not a registered
buffer, since all three leave the engine with an output binding the delegate
cannot satisfy; debug when the buffer already carries a spec, which is the
expected idempotent skip. The non-aliased output path stays silent -- it is the
common case, not a fault.
_reorder_input_names_for_executorch's docstring also justified skipping the output
reordering by claiming a TensorRT partition has no mutation outputs. That has not
been true since aliased I/O landed. The order does survive lowering, but for a
different reason: _keep_mutated_buffers_above_delegate keeps mutated buffers out
of the delegate, so ExecuTorch records the mutation as a USER_OUTPUT and
arrange_graph_outputs computes the identity permutation. Say that, and note the
guarantee is conditional -- _validate_output_binding_order is what enforces it.
Reported by cehongwang in review.
…T delegate
A mutable buffer with no engine aliasing -- a convolution-state ring buffer, say
-- is mutated outside the engine, so the KV aliasing path does not cover it.
lift_mutated_buffers appends its new value as a trailing user output;
reclassifying that output as a BUFFER_MUTATION of its buffer makes ExecuTorch
copy it back after the delegate runs.
Thread the buffer FQNs from gm.meta['_copyback_mutation_buffers'] into
_declare_aliased_kv_mutations_on_ep on the retrace=True executorch path, and have
create_trt_exp_program do the equivalent at transform time on the legacy path.
The reclassification is positional: it takes the trailing len(copyback_buffers)
outputs. That cannot skip an already-declared buffer the way the KV path's
already_exposed set does, because after a first declaration the mutations sit at
the front and the trailing outputs are the user's -- a second pass would retarget
those, dropping a user output and leaving the buffer with two mutation specs.
Reject that combination instead of silently corrupting the signature.
…program
Copy-back was threaded only on the executorch branch, so saving as
exported_program produced a signature that omits an update the program performs.
Hoist _copyback_bufs to the retrace=True block and pass it on both format
branches.
retrace=False is left alone deliberately. Only the legacy exporter declares
copy-back there, at transform time, and the pass cannot pick it up afterwards:
its reclassification is positional, so running it on an already-declared program
would retarget the wrong outputs. That leaves retrace=False with
use_legacy_exporter=False unable to declare copy-back at all, which now warns
instead of silently dropping it, mirroring the aot_inductor warning above.
shoumikhinand others added 4 commits August 20, 2026 14:20
Four problems that together stop a model from exporting when its caches live in
submodules or when part of the graph runs on another backend. The later ones only
become visible once the earlier ones are fixed.
1. A get_attr target is fully qualified, so a buffer owned by a submodule arrives
as "layers.0.self_attn.kv_cache.k_cache". hasattr and getattr do not walk a
dotted path, so every nested buffer is reported missing and skipped, and the
copy-back path never runs. Use get_buffer, which resolves through submodules.
2. register_buffer rejects dots, so a nested buffer is renamed to lifted_buf_*,
but the recorded mutation targets keep the original dotted names. The verifier
then rejects the program:
SpecViolationError: Buffer output getitem_1 does not point to a buffer
that exists
Remap the recorded targets through the same mapping, and keep the mapping in
meta so a later consumer does not have to reconstruct the renaming rule.
3. The aliasing prediction never sees torch_executed_ops, so a write the caller
excluded from TensorRT is still predicted to alias and its copy_ is dropped.
compile() then fails its own cross-check, reporting that the write-back would
be silently dropped. An op that never reaches a converter cannot emit an
IKVCacheUpdateLayer, so honor the exclusion list, matched the way the
partitioner matches it so the two cannot disagree.
4. Even with the prediction corrected, lifting an excluded write turns the
mutation into a delegate output that feeds the other delegate. ExecuTorch
cannot express a buffer mutation consumed across a delegate boundary:
RuntimeError: Tried to erase Node getitem_145 but it still had 1 users
in the graph: {executorch_call_delegate_1: None}
If TensorRT is not converting the write, leave the buffer alone entirely so
the copy_ stands for whichever backend claims it.
Pair a copy-back with its buffer by name rather than by position. torch.export
usually leaves those values as the last outputs, but when it recognises the mutation
itself it declares them BUFFER_MUTATION and moves them to the front, because the
verifier requires mutations to precede user outputs. Taking the tail unconditionally
then reclassified a real user output as a buffer mutation. On a transformer whose
cache write is kept inside the engine, that declared the model's logits as a cache
update and the export failed with:
RuntimeError: expand: attempting to expand a dimension of length 16 -> 4096
Only the buffers the program does not already declare as mutated are reclassified
now, so the pass is idempotent with respect to what torch.export already recorded.
The conflict resolution when rebasing left a line-wrapped condition that black wants on one
line. Python Linting failed on it.
An op the caller lists in torch_executed_ops never reaches a TensorRT converter, so
it cannot emit an IKVCacheUpdateLayer and the engine will not alias the buffer. The
aliasing prediction did not know that, so it classified such a write as engine-aliased
and dropped its copy_, and compile() then failed its own cross-check reporting that the
write-back would be silently lost.
The prediction now honors the exclusion list, matched the way the partitioners match it
so the two agree about the op. The write is still lifted and still copied back, like any
other write the engine does not alias.
An earlier version of this change skipped such a buffer entirely, leaving the get_attr
and the copy_ in place on the theory that another backend would claim the write. That is
wrong outside ExecuTorch: lift_mutated_buffers runs for every compile() caller, and
post_lowering's remove_num_users_is_0_nodes erases the orphaned copy_ because nothing
reads it, so the buffer froze at its compile-time contents and the cache silently stopped
updating. The copy-back route already handles this case correctly, and the mutation value
becomes a real graph output, so the dead-node pass cannot remove it.
The delegate-boundary error that motivated the skip has a different cause. ExecuTorch only
rejects a mutation consumed after the delegate when the delegate also absorbed the buffer,
and tag_constant_data already keeps mutated buffers above the delegate, which
_keep_mutated_buffers_above_delegate reinforces for the case it misses. Returning a mutation
value out of a delegate is a supported, tested path.
Also drop gm.meta["_lifted_buffer_attr_names"], which had no reader.
Test: test_torch_executed_write_is_copyback_not_kv asserts the excluded write is lifted,
recorded as copy-back rather than predicted-aliased, and left with no dead nodes for
post_lowering to erase. It fails on the previous behavior.
…s to
lift_mutated_buffers appends each copy-back buffer's new value as a trailing output, in
copyback_buffers order. The exporter reclassified those outputs as BUFFER_MUTATION by
taking the last N and zipping them against the buffer list.
That pairing breaks once torch.export recognises a mutation itself, because it then
records its own BUFFER_MUTATION and moves it ahead of the user outputs. Filtering the
buffer list first and slicing the same number of trailing outputs shifts the two lists
against each other, so one buffer gets another buffer's value:
buffers [a, b, c], b already declared
pending [a, c] -> takes the last two values, which are b's and c's
result a is declared as the mutation of b's value
With different shapes the runtime fails copying that value into the buffer; with matching
shapes it silently writes the wrong state.
Detach the full trailing run first and pair it positionally with the full buffer list,
then keep only the buffers the program has not already declared. Those appended values are
internal plumbing either way, so the run always leaves the user outputs. Previously, when
every buffer was already declared, nothing was detached and the values stayed as user
outputs, changing the saved model's output arity and exposing internal buffer state to the
caller. The out_spec rebuild is keyed on the same count for that reason.
Tests: test_declare_aliased_kv_mutations_pairs_copyback_by_position covers the mixed case
and test_declare_aliased_kv_mutations_skips_already_declared_copyback covers the
all-declared case. Both fail on the previous behavior.
@shoumikhin
shoumikhinforce-pushed the fix-nested-buffer-lifting branch from 8029187 to 266a494CompareAugust 20, 2026 21:22
@shoumikhin

Copy link
Copy Markdown
ContributorAuthor

Closing this in favour of #4459, which is the same work with one owner.

This branch was #4459 plus four commits on top, so there is nothing here that #4459 cannot carry directly. I rebased it onto today's main first, so the conflict resolutions are done and #4459 can take them rather than redo them. The details and the four commits to adopt are written up in #4459 (comment).

The branches stay up so the commits remain fetchable:

One note for whoever rebases next: the commit fix(dynamo): correct legacy exporter (retrace=False) submodule inlining for hybrid graphs already landed on main as #4446, and the landed version is a superset of the branch version, so it should be dropped rather than replayed.

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

Labels

cla signedcomponent: api [C++]Issues re: C++ APIcomponent: api [Python]Issues re: Python APIcomponent: coreIssues re: The core compilercomponent: dynamoIssues relating to the `torch.compile` or `torch._dynamo.export` pathscomponent: loweringIssues re: The lowering / preprocessing passescomponent: runtimecomponent: testsIssues re: Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@shoumikhin@lanluo-nvidia@Conarnar