Skip to content

[Qualcomm] Partitioner falls back on ops without a node visitor - #21607

Open
psiddh wants to merge 4 commits into
pytorch:mainfrom
psiddh:qnn-fix-partitioner-robustness
Open

[Qualcomm] Partitioner falls back on ops without a node visitor#21607
psiddh wants to merge 4 commits into
pytorch:mainfrom
psiddh:qnn-fix-partitioner-robustness

Conversation

@psiddh

@psiddh psiddh commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

[Qualcomm] Partitioner falls back on ops without a node visitor (fix KeyError)

Summary

QnnOperatorSupport.is_node_supported indexed self.node_visitors[node.target.__name__]
directly, so any op that has no QNN node visitor raised KeyError and aborted the entire
partition
instead of falling back to CPU. XNNPACK's partitioner returns False for unknown
ops; QNN should do the same.

Symptom

Lowering Mamba2 to QNN crashes:

File ".../backends/qualcomm/partition/qnn_partitioner.py", line 113, in is_node_supported
    op_wrapper = self.node_visitors[node.target.__name__].define_node(...)
KeyError: 'aten.bitwise_not.default'

Mamba2's causal mask uses ~torch.tril(...), which traces to aten.bitwise_not.default — an op
QNN ships no visitor for. This is not SSM/conv specific: any graph containing an op without a
visitor hits it.

Fix

Guard the lookup and return False (→ CPU fallback) for unsupported ops:

supported = False
if node.target.__name__ not in self.node_visitors:
    logger.info(f"[{self.phase}] {node.target.__name__} | No node visitor, unsupported")
    return False
op_wrapper = self.node_visitors[node.target.__name__].define_node(...)

Testing

test_partitioner_falls_back_on_op_without_visitor (in test_passes.py): lowers a module whose
graph contains aten.bitwise_not.default and asserts to_executorch() succeeds. Fails on the
pre-fix code with the exact KeyError above; passes after.
Verified by file-swap.

Notes

  • Optional follow-up (not in this PR): add aten.bitwise_not.default to the op_logical_not
    visitor's target list so it delegates to QNN (on a bool tensor it's equivalent to logical_not),
    putting more of Mamba2 on the HTP instead of CPU.
  • Surfaced by the HuggingFace transformers ExecuTorch-exporter QNN work (PR #47747), which currently
    skips SSM with an inaccurate "CanonicalizeConv unsqueezes a conv bias" comment — the real cause is
    this partitioner KeyError.

cc @cbilgin

QnnOperatorSupport.is_node_supported indexed self.node_visitors[op] directly,
so any op lacking a QNN node visitor raised KeyError and aborted the whole
partition instead of falling back to CPU (as XNNPACK's partitioner does).

Guard the lookup and return False for unsupported ops. Surfaced by Mamba2,
whose causal mask uses ~torch.tril(...) -> aten.bitwise_not.default, an op QNN
has no visitor for. Adds a regression test that fails with KeyError before.

Co-authored-with: Claude <noreply@anthropic.com>
@pytorch-bot

pytorch-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown

🔗 Helpful Links

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

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

❗ 1 Active SEVs

There are 1 currently active SEVs. If your PR is affected, please view them below:

✅ You can merge normally! (1 Unrelated Failure)

As of commit 2b89f8c with merge base bb6b99a (image):

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

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 5, 2026
@psiddh psiddh added the module: qnn Issues related to Qualcomm's QNN delegate and code under backends/qualcomm/ label Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 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.

@psiddh
psiddh marked this pull request as ready for review August 5, 2026 23:49
Copilot AI lite review requested due to automatic review settings August 5, 2026 23:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a crash in the Qualcomm QNN partitioner where QnnOperatorSupport.is_node_supported could raise a KeyError when encountering an operator that has no registered QNN node visitor, aborting partitioning instead of falling back to CPU.

Changes:

  • Add a guard in QnnOperatorSupport.is_node_supported to return False (CPU fallback) when an op has no node visitor, avoiding KeyError.
  • Add a regression test covering an op without a visitor (aten.bitwise_not.default) to ensure lowering doesn’t crash.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
backends/qualcomm/partition/qnn_partitioner.py Adds missing-visitor guard to prevent KeyError and allow CPU fallback.
backends/qualcomm/tests/test_passes.py Adds a regression test intended to ensure unknown ops don’t abort QNN lowering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread backends/qualcomm/tests/test_passes.py Outdated
Co-authored-with: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 6, 2026 00:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@shewu-quic shewu-quic left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your help.
Could you please help to add aten.bitwise_not.default into to_be_implemented_operator?
https://github.com/pytorch/executorch/blob/main/backends/qualcomm/partition/common_defs.py

Per review: list bitwise_not as a known-unsupported op so it reports the
tracked 'can be supported, please report an issue' message. The partitioner
guard remains as the general safety net for any other visitor-less op.

Co-authored-with: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 6, 2026 07:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (3)

backends/qualcomm/partition/common_defs.py:28

  • Adding exir_ops.edge.aten.bitwise_not.default to to_be_implemented_operator makes the op take the "Skipped, this op can be supported" early-return path, which bypasses the new "missing node visitor" fallback and will also keep forcing CPU fallback even if a node visitor is later added. Since the purpose of this PR is to handle missing visitors generically, this entry is redundant and makes follow-up support harder.
    exir_ops.edge.aten.median.default,
    exir_ops.edge.aten.median.dim,
    exir_ops.edge.aten.round.decimals,
    exir_ops.edge.aten.le.Scalar,
    exir_ops.edge.aten.bitwise_not.default,

backends/qualcomm/tests/test_passes.py:511

  • This test currently depends on end-to-end lowering and a QNN SDK presence (so it may be skipped in many environments), and it doesn’t assert that bitwise_not is actually taking the “missing visitor” path (it could be filtered earlier via operator lists or pass transforms). You can make it a deterministic unit regression by (1) checking the edge graph contains exir_ops.edge.aten.bitwise_not.default, (2) asserting it is not in the registered node visitor dict, (3) asserting it is not pre-filtered by to_be_implemented_operator, and (4) calling QnnOperatorSupport.is_node_supported with a minimal mock to ensure it returns False without raising.
        # Guard against a vacuous test: the visitor-less op must actually be present.
        exported = torch.export.export(BitwiseNot().eval(), sample_input)
        self.assertTrue(
            any(
                node.op == "call_function" and "bitwise_not" in str(node.target)

backends/qualcomm/tests/test_passes.py:484

  • Using ~(x > 0) relies on PyTorch tracing details and can be rewritten/decomposed in ways that remove aten.bitwise_not from the exported/edge graph, making the regression test brittle. Calling torch.ops.aten.bitwise_not.default explicitly makes the test deterministic about the operator it is targeting.
            def forward(self, x):
                return (~(x > 0)).to(torch.float32) + x

unguarded lookup aborted the whole partition instead of falling back.
"""

class BitwiseNot(torch.nn.Module):

@qti-horodnic qti-horodnic Aug 6, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: If we add this op to the to_be_implemented_operator list, this test won't really exercise the path we're trying to validate right? I suggest changing to something like aten.frac.default since it has no visitor and the model is simple:

class FracModule(torch.nn.Module):
    def forward(self, x):
        return torch.frac(x) + x

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. module: qnn Issues related to Qualcomm's QNN delegate and code under backends/qualcomm/

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants