Aharrypotter opened a new pull request, #19897:
URL: https://github.com/apache/tvm/pull/19897
## Summary
This PR fixes Relax ONNX frontend handling for integer `Div` when the divisor
is dynamic and may contain zero.
Issue #19541 reports a `SIGFPE` crash when an ONNX `Div` model has integer
inputs and the divisor is supplied as a graph input containing zero. PR
#19566
already added an import-time error for constant integer divisors containing
zero, but dynamic divisors still imported to a bare `relax.divide`. After
legalization, LLVM could still see integer `sdiv` / `udiv` with a zero
divisor.
ONNX integer division by zero is undefined. This PR keeps exact integer
division for every non-zero divisor lane, and returns zero for lanes where
the
runtime divisor is zero. The result is deterministic and avoids exposing
integer division by zero to LLVM.
## Design
### Guarded Dynamic Integer Div
For integer operands with a non-constant RHS, `Div._impl_v7` now emits a
guarded Relax subgraph:
```python
rhs_nonzero = relax.op.not_equal(rhs, relax.op.zeros_like(rhs))
safe_rhs = relax.op.where(rhs_nonzero, rhs, relax.op.ones_like(rhs))
quotient = relax.op.divide(lhs, safe_rhs)
result = relax.op.where(rhs_nonzero, quotient, relax.op.zeros_like(quotient))
```
The divisor passed to `relax.divide` is therefore never zero. The final
`where` restores the deterministic zero result for the originally-zero
divisor
lanes.
The importer normalizes the intermediate expressions whose inferred type is
needed by later `where` / `zeros_like` construction.
### Constant and Non-Integer Paths
The existing non-integer behavior is unchanged: non-integer `Div` still uses
the normal binary frontend implementation.
For integer `Div` with a constant RHS:
- constants containing zero still raise `ValueError` at import time
- constants without zero still use the normal binary frontend implementation
This keeps the PR #19566 behavior for constants while only adding runtime
guarding where import-time zero detection is impossible.
### No Float Fallback
The implementation intentionally avoids casting integer tensors through float
types. The guarded Relax graph preserves integer division semantics on all
non-zero lanes and avoids precision loss or float-to-int `inf` behavior.
### Frontend-Local Runtime Guard
This is intentionally a frontend-local runtime guard rather than a global
Relax, TIR, or LLVM integer-division policy. The check is not an import-time
Python decision for dynamic inputs; it is expressed as Relax IR and executes
with the model at runtime.
Handling this in a generic Relax/TIR pass would affect all producers of
integer
division and would need a project-wide policy for undefined integer
division-by-zero behavior: whether to trap, raise a controlled runtime error,
or return a deterministic value. This PR only addresses the ONNX frontend bug
reported in #19541 and keeps the deterministic zero result local to imported
ONNX integer `Div`.
## Updated Converter Behavior
| Case | Previous behavior | New behavior |
|---|---|---|
| integer `Div` with dynamic integer RHS | imports to bare `relax.divide`;
LLVM can see integer division by zero at runtime | imports to a guarded Relax
subgraph; non-zero divisor lanes keep exact integer division, zero-divisor
lanes return zero |
| integer `Div` with constant integer RHS containing zero | import-time
`ValueError` from PR #19566 | unchanged |
| integer `Div` with constant integer RHS without zero | normal binary
lowering | unchanged |
| non-integer `Div` | normal binary lowering | unchanged |
## Safety Checks
- Constant integer divisors containing zero raise
`ValueError("ONNX Div with integer inputs encountered divisor value 0.")`.
- Dynamic integer divisors are replaced with `ones_like(rhs)` only for the
division operand when the divisor lane is zero.
- Zero-divisor lanes are overwritten with `zeros_like(quotient)` after the
division.
- The guarded graph is asserted with structural Relax IR tests, so the
frontend
cannot silently regress to a bare `relax.divide` or wire the guard operands
incorrectly.
## Out of Scope / Non-Goals
- This PR does not define global Relax, TIR, or LLVM integer division-by-zero
semantics.
- This PR does not use a float-cast fallback for integer division.
- This PR does not change ONNX `Div` floating-point behavior.
- This PR does not change other frontends or other ONNX operators.
## Tests
The tests primarily lock the imported Relax graph shape, with one minimal VM
runtime smoke test for the original execution-time crash path.
| Test | Coverage |
|---|---|
| `test_div_integer_constant_zero_divisor_raises_valueerror` | keeps PR
#19566 constant-zero import-time error |
| `test_div_integer_dynamic_zero_divisor_runtime` | runs one dynamic INT32
ONNX `Div` model through `DecomposeOpsForInference`, `LegalizeOps`, LLVM
compile, and VM execution; asserts dtype, shape, exact non-zero divisor
results, and deterministic zero results for zero-divisor lanes |
| `test_div_integer_dynamic_zero_divisor_ir_guard` | uses
`tvm.ir.assert_structural_equal` to lock the exact guarded Relax subgraph
before legalization |
| `test_div_integer_dynamic_zero_divisor_broadcast_ir_guard` | uses
`tvm.ir.assert_structural_equal` to lock the guarded Relax subgraph when RHS
broadcasting is required |
Local validation:
```bash
python -m pytest \
tests/python/relax/test_frontend_onnx.py::test_div_integer_dynamic_zero_divisor_runtime
\
-xvs
python -m pytest tests/python/relax/test_frontend_onnx.py -k "div" -xvs
python -m ruff check \
python/tvm/relax/frontend/onnx/onnx_frontend.py \
tests/python/relax/test_frontend_onnx.py
```
Result:
```text
test_div_integer_dynamic_zero_divisor_runtime: passed
test_frontend_onnx.py -k "div": 7 passed
ruff check: All checks passed
```
## References
- Closes [#19541](https://github.com/apache/tvm/issues/19541): ONNX integer
`Div` with a dynamic zero divisor can crash at runtime.
- Follows up PR #19566: previous constant-zero divisor import-time error.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]