Skip to content

Do not move a view's shape earlier than the nodes that compute it - #22403

Open
msluszniak wants to merge 1 commit into
pytorch:mainfrom
msluszniak:ms/fuse-view-copy-symbolic-shape-order
Open

Do not move a view's shape earlier than the nodes that compute it#22403
msluszniak wants to merge 1 commit into
pytorch:mainfrom
msluszniak:ms/fuse-view-copy-symbolic-shape-order

Conversation

@msluszniak

Copy link
Copy Markdown
Contributor

Summary

_merge_view_copy_chains gives the first view in a chain the shape of the last one:

final_shape = view_nodes_to_remove[-1].args[1]
node.args = (node.args[0], final_shape)

Under dynamic shapes a view's shape is not a list of ints, it is a list that can contain nodes computing symbolic sizes. Those nodes may be defined anywhere between the first and the last view, so assigning the later shape to the earlier node can make that node read a value that does not exist yet.

The result is a graph that fails fx's own lint(), which the pass then hits itself on the very next line via eliminate_dead_code():

RuntimeError: Argument 'mul' of Node 'aten_view_copy_default_21' was used
before it has been defined! Please check that Nodes in the graph are
topologically ordered

I hit this lowering a TTS model to Vulkan. The chain ends on a view_copy(x, [2*s, 512]) whose 2*s is produced exactly one node after the first view of the chain, so the rewrite moves the shape one position too far back. The submodule handed to the backend is correctly ordered; this pass is what breaks it.

Fix

Fuse the longest prefix of the chain whose shape is available where the first view sits, and leave the rest alone. Chains with static shapes, which is the common case, keep fusing exactly as before.

Test plan

New backends/transforms/test/test_fuse_view_copy.py:

  • a static view chain still collapses to a single view
  • a chain whose final shape is computed after the first view leaves the graph topologically ordered (asserted with graph.lint())

The second test fails on the current pass and passes with this change; the first passes either way, so the existing fusion is not narrowed for static shapes.

`_merge_view_copy_chains` gives the first view in a chain the shape of the
last one:

    final_shape = view_nodes_to_remove[-1].args[1]
    node.args = (node.args[0], final_shape)

Under dynamic shapes a view's shape is not a list of ints, it is a list that
can contain nodes computing symbolic sizes. Those nodes may be defined
anywhere between the first and the last view, so assigning the later shape to
the earlier node can make that node read a value that does not exist yet.

The result is a graph that fails fx's own `lint()`, which the pass then hits
itself on the very next line via `eliminate_dead_code()`:

  RuntimeError: Argument 'mul' of Node 'aten_view_copy_default_21' was used
  before it has been defined! Please check that Nodes in the graph are
  topologically ordered

seen while lowering a TTS model to Vulkan, where the chain ends on a
`view_copy(x, [2*s, 512])` whose `2*s` is produced one node after the first
view.

Fuse the longest prefix of the chain whose shape is available where the first
view sits, and leave the rest alone. Chains with static shapes, which is the
common case, are unaffected.
@pytorch-bot

pytorch-bot Bot commented Sep 1, 2026

Copy link
Copy Markdown

🔗 Helpful Links

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

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

⚠️ 14 Awaiting Approval

As of commit 68fe421 with merge base 5428092 (image):

AWAITING APPROVAL - The following workflows need approval before CI can run:

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 Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

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.

msluszniak added a commit to software-mansion-labs/executorch that referenced this pull request Sep 1, 2026
Backport of pytorch/executorch#22403 and #22406.

- FuseViewCopyTransform no longer moves a view's shape earlier than the nodes
  that compute it, which produced a topologically invalid graph under dynamic
  shapes.
- index.Tensor with the index on any dimension is dispatched to index_select
  instead of falling back to the CPU. TagMemoryMetaPass now assigns a
  representation to tensors that sit in a list alongside Nones.

Supertonic vector_estimator goes from 29 delegate calls to 2, ~11% faster
end to end on Adreno 840, outputs unchanged.
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.

2 participants