Skip to content

[Fix][Relax][ONNX] Preserve integer Div truncation during import#19975

Open
viiccwen wants to merge 2 commits into
apache:mainfrom
viiccwen:fix/onnx-integer-div-truncation
Open

[Fix][Relax][ONNX] Preserve integer Div truncation during import#19975
viiccwen wants to merge 2 commits into
apache:mainfrom
viiccwen:fix/onnx-integer-div-truncation

Conversation

@viiccwen

Copy link
Copy Markdown
Contributor

ONNX integer Div uses truncating division, rounding toward zero. The Relax ONNX frontend already special-cased integer Div to detect zero divisors, but its PrimExpr folding path could still use NumPy floating-point division when one of the inputs was a shape-derived PrimExpr.

That behavior can produce floating-point TIR values for integer shape/index computations. For example, a Shape -> Gather -> Div -> Slice subgraph can produce T.float64(128.666...) as a Slice bound, which Relax rejects because strided_slice expects integer PrimExpr bounds.

This patch handles scalar integer Div inputs that contain a PrimExpr using TIR truncdiv, preserving ONNX semantics while keeping shape computations in TIR instead of routing them through NumPy. Constant tensor Div continues to use the existing generic binary constant-folding path.

The regression tests cover:

  • integer constant folding with negative values to distinguish truncation from floor division
  • a shape-derived PrimExpr Div used as a Slice bound
  • integer zero-divisor error handling

Verification:

  • python -m pytest tests/python/relax/test_frontend_onnx.py::test_div_integer_constant_zero_divisor_raises_valueerror tests/python/relax/test_frontend_onnx.py::test_div_integer_constant_folding_truncates_toward_zero tests/python/relax/test_frontend_onnx.py::test_div_integer_primexpr_folding_truncates_toward_zero -q

Fixes #19974

viiccwen added 2 commits July 10, 2026 06:24
ONNX integer Div uses truncating division, rounding toward zero. The Relax ONNX frontend already special-cased integer Div to detect zero divisors, but its PrimExpr folding path could still use NumPy floating-point division and produce floating-point TIR values for integer shape computations.

This can make shape-derived expressions such as Shape -> Gather -> Div -> Slice fail during import, because strided_slice expects integer PrimExpr bounds.

Handle scalar integer Div inputs that contain a PrimExpr using TIR truncdiv, while keeping existing generic BinaryBase handling for tensor constants and runtime expressions.

Add regression tests for integer constant Div semantics and a shape-derived PrimExpr Div used as a Slice bound.

Signed-off-by: viiccwen <vicwen@apache.org>
Signed-off-by: viiccwen <vicwen@apache.org>

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request adds support for folding integer division operations involving symbolic PrimExpr inputs in the ONNX frontend, truncating toward zero. It introduces helper methods to identify zero divisors and extract scalar expressions, and adds corresponding unit tests. The review feedback points out that shape-derived values in Relax are often wrapped in relax.PrimValue rather than raw tvm.ir.PrimExprs. To avoid bypassing the symbolic division path and causing potential runtime errors, it is recommended to explicitly check for and unwrap relax.PrimValue in both _as_scalar_prim_expr and the has_prim_expr condition.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread python/tvm/relax/frontend/onnx/onnx_frontend.py
Comment thread python/tvm/relax/frontend/onnx/onnx_frontend.py
@viiccwen

Copy link
Copy Markdown
Contributor Author

In the current Relax Python API, relax.prim_value does not produce a separate relax.PrimValue wrapper. It returns a TIR PrimExpr directly for both PrimExpr inputs and Python scalar inputs, so tvm.ir.is_prim_expr(...) already covers these values. I verified this locally, and there does not appear to be a relax.PrimValue Python class to unwrap.

Thx Gemini.

image

@viiccwen

Copy link
Copy Markdown
Contributor Author

cc @guan404ming, @tlopex. 🙌

@yongwww yongwww closed this Jul 11, 2026
@yongwww yongwww reopened this Jul 11, 2026
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.

[Bug] Relax ONNX frontend folds integer Div through floating-point division for PrimExpr inputs

2 participants