about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTrevor Gross <tmgross@umich.edu>2025-06-02 20:20:23 +0000
committerTrevor Gross <tmgross@umich.edu>2025-06-02 22:47:15 +0000
commit57786431746f495f4205e26ee1badd142a380fff (patch)
treea6296879c7316b146516a3a8f0a043727ac67c8a
parentba7cdb681468ef7617bfa5a2bde7e3fb3d79a2be (diff)
downloadrust-57786431746f495f4205e26ee1badd142a380fff.tar.gz
rust-57786431746f495f4205e26ee1badd142a380fff.zip
libm-test: Fix unintentional skips in `binop_common`
`binop_common` emits a `SKIP` that is intended to apply only to
`copysign`, but is instead applying to all binary operators. Correct the
general case but leave the currently-failing `maximum_num` tests as a
FIXME, to be resolved separately in [1].

Also simplify skip logic and NaN checking, and add a few more `copysign`
checks.

[1]: https://github.com/rust-lang/compiler-builtins/pull/939
-rw-r--r--library/compiler-builtins/libm-test/src/generate/edge_cases.rs1
-rw-r--r--library/compiler-builtins/libm-test/src/precision.rs15
-rw-r--r--library/compiler-builtins/libm-test/src/test_traits.rs20
-rw-r--r--library/compiler-builtins/libm/src/math/copysign.rs10
4 files changed, 34 insertions, 12 deletions
diff --git a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs
index 2fb0746388c..4e4a782a169 100644
--- a/library/compiler-builtins/libm-test/src/generate/edge_cases.rs
+++ b/library/compiler-builtins/libm-test/src/generate/edge_cases.rs
@@ -51,6 +51,7 @@ where
 
     // Check some special values that aren't included in the above ranges
     values.push(Op::FTy::NAN);
+    values.push(Op::FTy::NEG_NAN);
     values.extend(Op::FTy::consts().iter());
 
     // Check around the maximum subnormal value
diff --git a/library/compiler-builtins/libm-test/src/precision.rs b/library/compiler-builtins/libm-test/src/precision.rs
index f6cdd015a59..32825b15d47 100644
--- a/library/compiler-builtins/libm-test/src/precision.rs
+++ b/library/compiler-builtins/libm-test/src/precision.rs
@@ -444,13 +444,18 @@ fn binop_common<F1: Float, F2: Float>(
     expected: F2,
     ctx: &CheckCtx,
 ) -> CheckAction {
-    // MPFR only has one NaN bitpattern; allow the default `.is_nan()` checks to validate. Skip if
-    // the first input (magnitude source) is NaN and the output is also a NaN, or if the second
-    // input (sign source) is NaN.
-    if ctx.basis == CheckBasis::Mpfr
+    // MPFR only has one NaN bitpattern; skip tests in cases where the first argument would take
+    // the sign of a NaN second argument. The default NaN checks cover other cases.
+    if ctx.base_name == BaseName::Copysign && ctx.basis == CheckBasis::Mpfr && input.1.is_nan() {
+        return SKIP;
+    }
+
+    // FIXME(#939): this should not be skipped, there is a bug in our implementationi.
+    if ctx.base_name == BaseName::FmaximumNum
+        && ctx.basis == CheckBasis::Mpfr
         && ((input.0.is_nan() && actual.is_nan() && expected.is_nan()) || input.1.is_nan())
     {
-        return SKIP;
+        return XFAIL_NOCHECK;
     }
 
     /* FIXME(#439): our fmin and fmax do not compare signed zeros */
diff --git a/library/compiler-builtins/libm-test/src/test_traits.rs b/library/compiler-builtins/libm-test/src/test_traits.rs
index 2af6af60ba2..278274d917b 100644
--- a/library/compiler-builtins/libm-test/src/test_traits.rs
+++ b/library/compiler-builtins/libm-test/src/test_traits.rs
@@ -312,12 +312,9 @@ where
     let mut inner = || -> TestResult {
         let mut allowed_ulp = ctx.ulp;
 
-        // Forbid overrides if the items came from an explicit list, as long as we are checking
-        // against either MPFR or the result itself.
-        let require_biteq = ctx.gen_kind == GeneratorKind::List && ctx.basis != CheckBasis::Musl;
-
         match SpecialCase::check_float(input, actual, expected, ctx) {
-            _ if require_biteq => (),
+            // Forbid overrides if the items came from an explicit list
+            _ if ctx.gen_kind == GeneratorKind::List => (),
             CheckAction::AssertSuccess => (),
             CheckAction::AssertFailure(msg) => assert_failure_msg = Some(msg),
             CheckAction::Custom(res) => return res,
@@ -327,9 +324,20 @@ where
 
         // Check when both are NaNs
         if actual.is_nan() && expected.is_nan() {
-            if require_biteq && ctx.basis == CheckBasis::None {
+            // Don't assert NaN bitwise equality if:
+            //
+            // * Testing against MPFR (there is a single NaN representation)
+            // * Testing against Musl except for explicit tests (Musl does some NaN quieting)
+            //
+            // In these cases, just the check that actual and expected are both NaNs is
+            // sufficient.
+            let skip_nan_biteq = ctx.basis == CheckBasis::Mpfr
+                || (ctx.basis == CheckBasis::Musl && ctx.gen_kind != GeneratorKind::List);
+
+            if !skip_nan_biteq {
                 ensure!(actual.biteq(expected), "mismatched NaN bitpatterns");
             }
+
             // By default, NaNs have nothing special to check.
             return Ok(());
         } else if actual.is_nan() || expected.is_nan() {
diff --git a/library/compiler-builtins/libm/src/math/copysign.rs b/library/compiler-builtins/libm/src/math/copysign.rs
index d2a86e7fd54..d093d610727 100644
--- a/library/compiler-builtins/libm/src/math/copysign.rs
+++ b/library/compiler-builtins/libm/src/math/copysign.rs
@@ -59,9 +59,17 @@ mod tests {
 
         // Not required but we expect it
         assert_biteq!(f(F::NAN, F::NAN), F::NAN);
-        assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN);
+        assert_biteq!(f(F::NAN, F::ONE), F::NAN);
+        assert_biteq!(f(F::NAN, F::NEG_ONE), F::NEG_NAN);
         assert_biteq!(f(F::NAN, F::NEG_NAN), F::NEG_NAN);
+        assert_biteq!(f(F::NEG_NAN, F::NAN), F::NAN);
+        assert_biteq!(f(F::NEG_NAN, F::ONE), F::NAN);
+        assert_biteq!(f(F::NEG_NAN, F::NEG_ONE), F::NEG_NAN);
         assert_biteq!(f(F::NEG_NAN, F::NEG_NAN), F::NEG_NAN);
+        assert_biteq!(f(F::ONE, F::NAN), F::ONE);
+        assert_biteq!(f(F::ONE, F::NEG_NAN), F::NEG_ONE);
+        assert_biteq!(f(F::NEG_ONE, F::NAN), F::ONE);
+        assert_biteq!(f(F::NEG_ONE, F::NEG_NAN), F::NEG_ONE);
     }
 
     #[test]