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 93a4a644b0 [Test] Run round ties-to-even test on every backend that 
implements it (#20252)
93a4a644b0 is described below

commit 93a4a644b02a9a37a3324dc3006a3d011240dc16
Author: LngelKyo <[email protected]>
AuthorDate: Wed Sep 2 02:02:10 2026 +0900

    [Test] Run round ties-to-even test on every backend that implements it 
(#20252)
    
    #19368 aligned `tir.round` to ties-to-even across LLVM, CUDA, NVPTX,
    ROCm, Hexagon, Metal, OpenCL, SPIR-V and WebGPU, and #20131 fixed the C
    host — but the shape of that bug can recur: `test_round_ties_to_even`
    (tests/python/tirx-base/test_tir_intrin.py) is pinned to
    `target="llvm"`, so the C host's ties behaviour is not exercised
    anywhere. The C host passed every test for four months for exactly this
    reason.
    
    **What this PR does**
    
    Parametrize `test_round_ties_to_even` over the two host targets the
    regression can recur on — `c` and `llvm` — following the
    `test_codegen_loop_step` convention. Device backends have their own
    lowering rules and belong in their own codegen tests. The midpoint
    vector is the one #19368 added, reused verbatim.
    
    **Verification.** On a local build: reverting the C rule to its
    pre-#20131 ties-away-from-zero form makes `test_round_ties_to_even[c]`
    fail with the expected midpoint mismatches (`0.5 → 1.0 vs 0.0`, `2.5 →
    3.0 vs 2.0`, `−0.5 → −1.0 vs −0.0`), while `[llvm]` still passes — i.e.
    the test now catches the class of bug that #20131 fixed. With the rule
    restored, both targets pass. Formatting checked with ruff format/ruff
    check — both the CI-pinned ruff 0.12.3 and 0.15.14 pass clean on the
    touched file.
    
    **Second commit** is docs-only: it pins the floating-point-environment
    assumption from the #20131 discussion into `src/target/intrin_rule.cc`.
    nearbyint is ties-to-even under the default `FE_TONEAREST`, and the same
    holds for the LLVM rule, which lowers to `llvm.nearbyint` —
    rounding-mode sensitive, like nearbyint itself (`llvm.roundeven` is the
    mode-independent one). Every other backend that registers `tirx.round` —
    cuda, nvptx, rocm, hexagon, metal, opencl, vulkan, webgpu — emits code
    for a separate device whose rounding mode is fixed at RNE, so
    `fesetround()` in the host process cannot reach it.
    
    **Third commit** is a one-line CI restore: #20131 left a 3-line wrapped
    call in `test_target_codegen_c_host.py` that ruff-format rejoins under
    `line-length = 100`, so `pre-commit run --all-files` fails on every open
    PR. This PR carries the rejoin so that merging it leaves main
    lint-green. Reproduce: `uvx [email protected] format --check
    tests/python/codegen/test_target_codegen_c_host.py`.
    
    ---------
    
    Co-authored-by: LngelKyo <[email protected]>
---
 src/target/intrin_rule.cc                 |  9 +++++++++
 tests/python/tirx-base/test_tir_intrin.py | 14 +++++++++++---
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/src/target/intrin_rule.cc b/src/target/intrin_rule.cc
index 9d3a26cdd1..22d2d97d42 100644
--- a/src/target/intrin_rule.cc
+++ b/src/target/intrin_rule.cc
@@ -38,6 +38,15 @@ using tirx::FLowerIntrinsic;
 // is ties-AWAY-from-zero, so lowering through FloatSuffix would disagree with
 // the folder and with every other backend. Rename to nearbyint before the
 // float suffix is applied, as the CUDA rule already does.
+//
+// Like nearbyint in general, this honours the current floating-point
+// environment: it is ties-to-even under the default FE_TONEAREST. The only
+// other backend a host fesetround() can reach is llvm, which lowers to
+// llvm.nearbyint (also mode-sensitive; llvm.roundeven is the
+// mode-independent one). Every other backend that registers tirx.round --
+// cuda, nvptx, rocm, hexagon, metal, opencl, vulkan, webgpu -- emits code
+// for a separate device whose rounding mode is fixed at RNE, so the
+// host's mode cannot reach it, whichever intrinsic the rule names.
 struct FloatSuffixTiesToEven {
   std::string operator()(const PrimType& ty, std::string name) const {
     if (name == "round") name = "nearbyint";
diff --git a/tests/python/tirx-base/test_tir_intrin.py 
b/tests/python/tirx-base/test_tir_intrin.py
index 6b31133b13..561e3d6761 100644
--- a/tests/python/tirx-base/test_tir_intrin.py
+++ b/tests/python/tirx-base/test_tir_intrin.py
@@ -60,15 +60,23 @@ def test_nearbyint():
     tvm.testing.assert_allclose(a_rounded.numpy(), np.rint(a.numpy()))
 
 
-def test_round_ties_to_even():
-    """Test that tir.round uses ties-to-even (banker's rounding) semantics."""
+# Covers the host targets the regression can recur on: the C host lowers
+# through src/target/intrin_rule.cc (the path #19368 left behind and #20131
+# fixed), llvm through llvm.nearbyint. Device backends have their own
+# lowering rules and belong in their own codegen tests.
[email protected]("target", ["c", "llvm"])
+def test_round_ties_to_even(target):
+    """Test that tirx.round uses ties-to-even (banker's rounding) semantics."""
+    if target != "c" and not tvm.testing.device_enabled(target):
+        pytest.skip(f"{target} not enabled")
+
     m = te.var("m")
     A = te.placeholder((m,), name="A")
     A_rounded = te.compute((m,), lambda *i: tvm.tirx.round(A(*i)), name="A")
 
     mod = te.create_prim_func([A, A_rounded])
     sch = tvm.s_tir.Schedule(mod)
-    func = tvm.compile(sch.mod, target="llvm")
+    func = tvm.compile(sch.mod, target=target)
 
     dev = tvm.cpu(0)
     # Midpoint values where ties-to-even and ties-away differ

Reply via email to