about summary refs log tree commit diff
path: root/library
diff options
context:
space:
mode:
authorTrevor Gross <tmgross@umich.edu>2024-05-29 02:56:59 -0500
committerTrevor Gross <tmgross@umich.edu>2024-10-30 12:22:57 -0500
commit1dc50415cdf4ae22ef7001ae264be0fe4040c81a (patch)
tree9d9a751474db5b88eb7a1ebe984f4ed430d61a40 /library
parentad465ce6bd07feebda7294b432bdfba7a5dc29ff (diff)
downloadrust-1dc50415cdf4ae22ef7001ae264be0fe4040c81a.tar.gz
rust-1dc50415cdf4ae22ef7001ae264be0fe4040c81a.zip
Add an apfloat fallback for int to float tests
Diffstat (limited to 'library')
-rw-r--r--library/compiler-builtins/testcrate/tests/conv.rs129
1 files changed, 77 insertions, 52 deletions
diff --git a/library/compiler-builtins/testcrate/tests/conv.rs b/library/compiler-builtins/testcrate/tests/conv.rs
index 24f3a04a4ee..6096803871b 100644
--- a/library/compiler-builtins/testcrate/tests/conv.rs
+++ b/library/compiler-builtins/testcrate/tests/conv.rs
@@ -12,60 +12,82 @@ mod int_to_float {
     use super::*;
 
     macro_rules! i_to_f {
-        ($($from:ty, $into:ty, $fn:ident);*;) => {
+        ($f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => {
             $(
                 #[test]
                 fn $fn() {
                     use compiler_builtins::float::conv::$fn;
                     use compiler_builtins::int::Int;
 
-                    fuzz(N, |x: $from| {
-                        let f0 = x as $into;
-                        let f1: $into = $fn(x);
-                        // This makes sure that the conversion produced the best rounding possible, and does
-                        // this independent of `x as $into` rounding correctly.
-                        // This assumes that float to integer conversion is correct.
-                        let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from;
-                        let y = f1 as $from;
-                        let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from;
-                        let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x);
-                        let error = <$from as Int>::abs_diff(y, x);
-                        let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x);
-                        // The first two conditions check that none of the two closest float values are
-                        // strictly closer in representation to `x`. The second makes sure that rounding is
-                        // towards even significand if two float values are equally close to the integer.
-                        if error_minus < error
-                            || error_plus < error
-                            || ((error_minus == error || error_plus == error)
-                                && ((f0.to_bits() & 1) != 0))
-                        {
-                            if !cfg!(any(
-                                target_arch = "powerpc",
-                                target_arch = "powerpc64"
-                            )) {
-                                panic!(
-                                    "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})",
-                                    stringify!($fn),
-                                    x,
-                                    f1.to_bits(),
-                                    y_minus_ulp,
-                                    y,
-                                    y_plus_ulp,
-                                    error_minus,
-                                    error,
-                                    error_plus,
-                                );
+                    fuzz(N, |x: $i_ty| {
+                        let f0 = apfloat_fallback!(
+                            $f_ty, $apfloat_ty, $sys_available,
+                            |x| x as $f_ty;
+                            // When the builtin is not available, we need to use a different conversion
+                            // method (since apfloat doesn't support `as` casting).
+                            |x: $i_ty| {
+                                use compiler_builtins::int::MinInt;
+
+                                let apf = if <$i_ty>::SIGNED {
+                                    FloatTy::from_i128(x.try_into().unwrap()).value
+                                } else {
+                                    FloatTy::from_u128(x.try_into().unwrap()).value
+                                };
+
+                                <$f_ty>::from_bits(apf.to_bits())
+                            },
+                            x
+                        );
+                        let f1: $f_ty = $fn(x);
+
+                        #[cfg($sys_available)] {
+                            // This makes sure that the conversion produced the best rounding possible, and does
+                            // this independent of `x as $into` rounding correctly.
+                            // This assumes that float to integer conversion is correct.
+                            let y_minus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_sub(1)) as $i_ty;
+                            let y = f1 as $i_ty;
+                            let y_plus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_add(1)) as $i_ty;
+                            let error_minus = <$i_ty as Int>::abs_diff(y_minus_ulp, x);
+                            let error = <$i_ty as Int>::abs_diff(y, x);
+                            let error_plus = <$i_ty as Int>::abs_diff(y_plus_ulp, x);
+
+                            // The first two conditions check that none of the two closest float values are
+                            // strictly closer in representation to `x`. The second makes sure that rounding is
+                            // towards even significand if two float values are equally close to the integer.
+                            if error_minus < error
+                                || error_plus < error
+                                || ((error_minus == error || error_plus == error)
+                                    && ((f0.to_bits() & 1) != 0))
+                            {
+                                if !cfg!(any(
+                                    target_arch = "powerpc",
+                                    target_arch = "powerpc64"
+                                )) {
+                                    panic!(
+                                        "incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})",
+                                        stringify!($fn),
+                                        x,
+                                        f1.to_bits(),
+                                        y_minus_ulp,
+                                        y,
+                                        y_plus_ulp,
+                                        error_minus,
+                                        error,
+                                        error_plus,
+                                    );
+                                }
                             }
                         }
+
                         // Test against native conversion. We disable testing on all `x86` because of
                         // rounding bugs with `i686`. `powerpc` also has the same rounding bug.
-                        if f0 != f1 && !cfg!(any(
+                        if !Float::eq_repr(f0, f1) && !cfg!(any(
                             target_arch = "x86",
                             target_arch = "powerpc",
                             target_arch = "powerpc64"
                         )) {
                             panic!(
-                                "{}({}): std: {}, builtins: {}",
+                                "{}({}): std: {:?}, builtins: {:?}",
                                 stringify!($fn),
                                 x,
                                 f0,
@@ -78,19 +100,22 @@ mod int_to_float {
         };
     }
 
-    i_to_f! {
-        u32, f32, __floatunsisf;
-        u32, f64, __floatunsidf;
-        i32, f32, __floatsisf;
-        i32, f64, __floatsidf;
-        u64, f32, __floatundisf;
-        u64, f64, __floatundidf;
-        i64, f32, __floatdisf;
-        i64, f64, __floatdidf;
-        u128, f32, __floatuntisf;
-        u128, f64, __floatuntidf;
-        i128, f32, __floattisf;
-        i128, f64, __floattidf;
+    i_to_f! { f32, Single, all(),
+        u32, __floatunsisf;
+        i32, __floatsisf;
+        u64, __floatundisf;
+        i64, __floatdisf;
+        u128, __floatuntisf;
+        i128, __floattisf;
+    }
+
+    i_to_f! { f64, Double, all(),
+        u32, __floatunsidf;
+        i32, __floatsidf;
+        u64, __floatundidf;
+        i64, __floatdidf;
+        u128, __floatuntidf;
+        i128, __floattidf;
     }
 }