This is an automated email from the ASF dual-hosted git repository.
tlopex pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new ce9cfc06d6 [Test] Pin CUDA round ties-to-even on exact midpoints
(#20274)
ce9cfc06d6 is described below
commit ce9cfc06d6d9ad03ea6da7bd22c2f94942110ec0
Author: LngelKyo <[email protected]>
AuthorDate: Tue Sep 8 12:50:40 2026 +0900
[Test] Pin CUDA round ties-to-even on exact midpoints (#20274)
`test_vectorized_intrin1` exercises `tvm.tirx.round` on the CUDA path
with `np.random.uniform(0, 1)` inputs and `atol=1e-3`, which cannot
distinguish ties-to-even from ties-away-from-zero: exact midpoints (0.5,
1.5, 2.5, ...) never occur in random data. The CUDA rule lowers
`tirx.round` to `nearbyint` / `nearbyintf`
(src/backend/cuda/codegen/intrin_rule_cuda.cc:42-46, with the comment
"Use nearbyint (ties-to-even) for round to match constant-folding
semantics"), so the intended tie rule is already encoded — but nothing
pinned it on this backend.
Scope follows the review on #20252, verbatim:
> Please limit this test to the regression-relevant host targets (llvm
and c) instead of enumerating every backend. Most of these device
targets are skipped in CI, so this list adds maintenance cost without
guaranteeing coverage. Backend-specific lowering should be tested in the
corresponding codegen tests when needed.
A midpoint test in the CUDA codegen file is that instruction's second
half.
**What this test does**
- Midpoint vector from #19368 / #20131 (`0.5, 1.5, 2.5, 3.5, -0.5, -1.5,
-2.5, -3.5`), tiled ×16 to fill the 128 lanes `sched()` assumes (1 block
× 32 threads × float4).
- Zero-tolerance check against `np.round` (`rtol=0, atol=0`).
`assert_allclose` treats -0.0 and +0.0 as equal, so a separate
`np.signbit` assertion pins that `round(-0.5)` must produce -0.0.
- Both compile paths (nvcc, nvrtc) are covered by the autouse fixture.
- Scope: float32 only. fp16/bf16 `hrint` is not covered here, consistent
with `test_vectorized_intrin1` skipping round on fp16.
**Verification** (my run): RTX A6000, driver 610.43.02, CUDA 13.0.88,
LLVM 15.0.7, TVM at eaf710e72 on 5e49b3430.
- `test_round_ties_to_even[nvcc]` / `[nvrtc]`: both PASSED.
- Negative control: reverting the CUDA rule to `round`/`roundf` makes
both params FAIL, with 64 of 128 lanes off by one (0.5→1, 2.5→3,
-0.5→-1, -2.5→-3). Restoring the rule turns both green again.
- `uvx [email protected] check` and `format --check` clean.
cc @tlopex @yongwww @swjng — follows up on #20252 (CI will likely need
approval as before).
---
tests/python/codegen/test_target_codegen_cuda.py | 28 ++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/tests/python/codegen/test_target_codegen_cuda.py
b/tests/python/codegen/test_target_codegen_cuda.py
index c921393108..d0459f3e95 100644
--- a/tests/python/codegen/test_target_codegen_cuda.py
+++ b/tests/python/codegen/test_target_codegen_cuda.py
@@ -782,6 +782,34 @@ def test_vectorized_intrin1():
run_test(*func, "float16")
[email protected]
[email protected](not env.has_cuda(), reason="need cuda")
+def test_round_ties_to_even():
+ # The CUDA rule lowers tirx.round to nearbyint/nearbyintf (ties-to-even,
+ # matching constant-folding semantics), so exact midpoints must round to
+ # even. np.random-based tests never produce midpoints; this pins the tie
+ # rule on both the nvcc and nvrtc compile paths (via the autouse fixture).
+ # sched() assumes 128 lanes, so the midpoints are tiled to fill it.
+ midpoints = np.array([0.5, 1.5, 2.5, 3.5, -0.5, -1.5, -2.5, -3.5],
dtype="float32")
+ ties_to_even = np.array([0.0, 2.0, 2.0, 4.0, -0.0, -2.0, -2.0, -4.0],
dtype="float32")
+ test_values = np.tile(midpoints, 16) # 128 lanes, matches sched()
+ expected = np.tile(ties_to_even, 16)
+
+ f = sched(tvm.tirx.round, "float32")
+ dev = tvm.cuda(0)
+ a = tvm.runtime.tensor(test_values, dev)
+ b = tvm.runtime.tensor(np.zeros(len(test_values), dtype="float32"), dev)
+
+ def run_and_check():
+ f(a, b)
+ tvm.testing.assert_allclose(b.numpy(), expected, rtol=0, atol=0)
+ # every midpoint lane hit an exact tie: pin the sign too (round(-0.5)
+ # must produce -0.0, not +0.0)
+ assert np.signbit(b.numpy()[4::8]).all(), "negative midpoints must
round to -0.0"
+
+ tvm.testing.run_with_gpu_lock(run_and_check)
+
+
@pytest.mark.gpu
@pytest.mark.skipif(not env.has_cuda(), reason="need cuda")
def test_vectorized_intrin2(dtype="float32"):