Skip to content

Conversation

@qti-yuduo
Copy link
Contributor

Motivation

ClipQuantFusion in clip_quantizelinear.cc calls graph_utils::RemoveNode() without first checking graph_utils::CanRemoveNode(). When a Clip node has min/max inputs from DequantizeLinear nodes (instead of initializers), it has multiple input edges. RemoveNode() throws exception:

 [ONNXRuntimeError] : 6 : RUNTIME_EXCEPTION : Exception during initialization: graph_utils.cc:650 bool onnxruntime::graph_utils::RemoveNode(onnxruntime::Graph&, onnxruntime::Node&) Should be unreachable if CanRemoveNodeAndMergeEdges is in sync with the logic here.

Fix:

Added CanRemoveNode() check to ClipQuantFusion::SatisfyCondition() to skip nodes that cannot be safely removed.

Test:

Added ClipQuantFusion_MultipleInputEdges test that creates a Clip node with min from a DQ node (2 input edges) and verifies the optimizer doesn't crash.

@qti-yuduo qti-yuduo changed the title [QNN EP] Fix ClipQuantFusion crash when Clip has multiple input edges Fix ClipQuantFusion crash when Clip has multiple input edges Jan 7, 2026
@yuslepukhin yuslepukhin requested a review from Copilot January 13, 2026 18:58

This comment was marked as resolved.

@tianleiwu
Copy link
Contributor

From AI

Summary

This PR fixes a runtime exception in the ClipQuantFusion optimizer. The crash occurred because the code attempted to remove a Clip node without verifying if it was safe to do so, specifically when the node had multiple input edges (e.g., dynamic min/max inputs from DequantizeLinear nodes).

Key Changes

  • Fix: Added a call to graph_utils::CanRemoveNode() within ClipQuantFusion::SatisfyCondition().
  • Test: Added a new test case ClipQuantFusion_MultipleInputEdges to reproduce the scenario and verify the fix.

Review Analysis

Correctness

  • Pattern: It is a standard and necessary practice in ONNX Runtime graph transformations to check CanRemoveNode() before calling RemoveNode(). The fix correctly implements this missing check.
  • Root Cause: The description clearly explains why the crash happened (multiple input edges causing RemoveNode to fail), and the fix directly addresses it.

Performance

  • Impact: Negligible. The added check is lightweight and prevents a crash, which is infinitely better than failing.

Conclusion

This is a straightforward and correct bug fix. The inclusion of a regression test gives high confidence in the solution. LGTM.

@yuslepukhin
Copy link
Member

/azp run Linux QNN CI Pipeline,Win_TRT_Minimal_CUDA_Test_CI,Windows ARM64 QNN CI Pipeline,Windows GPU Doc Gen CI Pipeline

@azure-pipelines
Copy link

Azure Pipelines successfully started running 4 pipeline(s).

Copy link
Contributor

@adrianlizarraga adrianlizarraga left a comment

Choose a reason for hiding this comment

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

looks good to me

This comment was marked as resolved.

@edgchen1 edgchen1 enabled auto-merge (squash) January 15, 2026 00:44
@edgchen1
Copy link
Contributor

hm, there appears to be an invisible unresolved comment that's blocking the merge

This comment was marked as off-topic.

This comment was marked as off-topic.

@microsoft microsoft deleted a comment from Copilot AI Jan 15, 2026
@microsoft microsoft deleted a comment from edgchen1 Jan 15, 2026
auto-merge was automatically disabled January 15, 2026 02:53

Pull request was closed

@hariharans29 hariharans29 reopened this Jan 15, 2026
@edgchen1
Copy link
Contributor

can't figure out how to merge this one. replacing with #27016.

@edgchen1 edgchen1 closed this Jan 15, 2026
yuslepukhin pushed a commit that referenced this pull request Jan 16, 2026
## Motivation

`ClipQuantFusion in clip_quantizelinear.cc` calls
`graph_utils::RemoveNode()` without first checking
`graph_utils::CanRemoveNode()`. When a Clip node has min/max inputs from
DequantizeLinear nodes (instead of initializers), it has multiple input
edges. `RemoveNode()` throws exception:

```
 [ONNXRuntimeError] : 6 : RUNTIME_EXCEPTION : Exception during initialization: graph_utils.cc:650 bool onnxruntime::graph_utils::RemoveNode(onnxruntime::Graph&, onnxruntime::Node&) Should be unreachable if CanRemoveNodeAndMergeEdges is in sync with the logic here.
```

## Fix:
Added `CanRemoveNode()` check to `ClipQuantFusion::SatisfyCondition()`
to skip nodes that cannot be safely removed.

## Test:
Added `ClipQuantFusion_MultipleInputEdges` test that creates a Clip node
with min from a DQ node (2 input edges) and verifies the optimizer
doesn't crash.


## Note:
This PR is a duplicate of #26923 which GitHub is preventing us from
merging. Credit goes to original author @qti-yuduo.

---------

Co-authored-by: Yuduo Wu <yuduow@qti.qualcomm.com>
alex-spacemit pushed a commit to spacemit-com/onnxruntime that referenced this pull request Jan 20, 2026
…ft#27016)

## Motivation

`ClipQuantFusion in clip_quantizelinear.cc` calls
`graph_utils::RemoveNode()` without first checking
`graph_utils::CanRemoveNode()`. When a Clip node has min/max inputs from
DequantizeLinear nodes (instead of initializers), it has multiple input
edges. `RemoveNode()` throws exception:

```
 [ONNXRuntimeError] : 6 : RUNTIME_EXCEPTION : Exception during initialization: graph_utils.cc:650 bool onnxruntime::graph_utils::RemoveNode(onnxruntime::Graph&, onnxruntime::Node&) Should be unreachable if CanRemoveNodeAndMergeEdges is in sync with the logic here.
```

## Fix:
Added `CanRemoveNode()` check to `ClipQuantFusion::SatisfyCondition()`
to skip nodes that cannot be safely removed.

## Test:
Added `ClipQuantFusion_MultipleInputEdges` test that creates a Clip node
with min from a DQ node (2 input edges) and verifies the optimizer
doesn't crash.


## Note:
This PR is a duplicate of microsoft#26923 which GitHub is preventing us from
merging. Credit goes to original author @qti-yuduo.

---------

Co-authored-by: Yuduo Wu <yuduow@qti.qualcomm.com>
tianleiwu pushed a commit that referenced this pull request Jan 21, 2026
## Motivation

`ClipQuantFusion in clip_quantizelinear.cc` calls
`graph_utils::RemoveNode()` without first checking
`graph_utils::CanRemoveNode()`. When a Clip node has min/max inputs from
DequantizeLinear nodes (instead of initializers), it has multiple input
edges. `RemoveNode()` throws exception:

```
 [ONNXRuntimeError] : 6 : RUNTIME_EXCEPTION : Exception during initialization: graph_utils.cc:650 bool onnxruntime::graph_utils::RemoveNode(onnxruntime::Graph&, onnxruntime::Node&) Should be unreachable if CanRemoveNodeAndMergeEdges is in sync with the logic here.
```

## Fix:
Added `CanRemoveNode()` check to `ClipQuantFusion::SatisfyCondition()`
to skip nodes that cannot be safely removed.

## Test:
Added `ClipQuantFusion_MultipleInputEdges` test that creates a Clip node
with min from a DQ node (2 input edges) and verifies the optimizer
doesn't crash.

## Note:
This PR is a duplicate of #26923 which GitHub is preventing us from
merging. Credit goes to original author @qti-yuduo.

---------

Co-authored-by: Yuduo Wu <yuduow@qti.qualcomm.com>
(cherry picked from commit cc2b01b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants