Skip to content

Commit 9d3d5af

Browse files
committed
Add an apfloat fallback for int to float tests
1 parent c04eb9e commit 9d3d5af

File tree

1 file changed

+77
-52
lines changed

1 file changed

+77
-52
lines changed

testcrate/tests/conv.rs

+77-52
Original file line numberDiff line numberDiff line change
@@ -12,60 +12,82 @@ mod int_to_float {
1212
use super::*;
1313

1414
macro_rules! i_to_f {
15-
($($from:ty, $into:ty, $fn:ident);*;) => {
15+
($f_ty:ty, $apfloat_ty:ident, $sys_available:meta, $($i_ty:ty, $fn:ident);*;) => {
1616
$(
1717
#[test]
1818
fn $fn() {
1919
use compiler_builtins::float::conv::$fn;
2020
use compiler_builtins::int::Int;
2121

22-
fuzz(N, |x: $from| {
23-
let f0 = x as $into;
24-
let f1: $into = $fn(x);
25-
// This makes sure that the conversion produced the best rounding possible, and does
26-
// this independent of `x as $into` rounding correctly.
27-
// This assumes that float to integer conversion is correct.
28-
let y_minus_ulp = <$into>::from_bits(f1.to_bits().wrapping_sub(1)) as $from;
29-
let y = f1 as $from;
30-
let y_plus_ulp = <$into>::from_bits(f1.to_bits().wrapping_add(1)) as $from;
31-
let error_minus = <$from as Int>::abs_diff(y_minus_ulp, x);
32-
let error = <$from as Int>::abs_diff(y, x);
33-
let error_plus = <$from as Int>::abs_diff(y_plus_ulp, x);
34-
// The first two conditions check that none of the two closest float values are
35-
// strictly closer in representation to `x`. The second makes sure that rounding is
36-
// towards even significand if two float values are equally close to the integer.
37-
if error_minus < error
38-
|| error_plus < error
39-
|| ((error_minus == error || error_plus == error)
40-
&& ((f0.to_bits() & 1) != 0))
41-
{
42-
if !cfg!(any(
43-
target_arch = "powerpc",
44-
target_arch = "powerpc64"
45-
)) {
46-
panic!(
47-
"incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})",
48-
stringify!($fn),
49-
x,
50-
f1.to_bits(),
51-
y_minus_ulp,
52-
y,
53-
y_plus_ulp,
54-
error_minus,
55-
error,
56-
error_plus,
57-
);
22+
fuzz(N, |x: $i_ty| {
23+
let f0 = apfloat_fallback!(
24+
$f_ty, $apfloat_ty, $sys_available,
25+
|x| x as $f_ty;
26+
// When the builtin is not available, we need to use a different conversion
27+
// method (since apfloat doesn't support `as` casting).
28+
|x: $i_ty| {
29+
use compiler_builtins::int::MinInt;
30+
31+
let apf = if <$i_ty>::SIGNED {
32+
FloatTy::from_i128(x.try_into().unwrap()).value
33+
} else {
34+
FloatTy::from_u128(x.try_into().unwrap()).value
35+
};
36+
37+
<$f_ty>::from_bits(apf.to_bits())
38+
},
39+
x
40+
);
41+
let f1: $f_ty = $fn(x);
42+
43+
#[cfg($sys_available)] {
44+
// This makes sure that the conversion produced the best rounding possible, and does
45+
// this independent of `x as $into` rounding correctly.
46+
// This assumes that float to integer conversion is correct.
47+
let y_minus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_sub(1)) as $i_ty;
48+
let y = f1 as $i_ty;
49+
let y_plus_ulp = <$f_ty>::from_bits(f1.to_bits().wrapping_add(1)) as $i_ty;
50+
let error_minus = <$i_ty as Int>::abs_diff(y_minus_ulp, x);
51+
let error = <$i_ty as Int>::abs_diff(y, x);
52+
let error_plus = <$i_ty as Int>::abs_diff(y_plus_ulp, x);
53+
54+
// The first two conditions check that none of the two closest float values are
55+
// strictly closer in representation to `x`. The second makes sure that rounding is
56+
// towards even significand if two float values are equally close to the integer.
57+
if error_minus < error
58+
|| error_plus < error
59+
|| ((error_minus == error || error_plus == error)
60+
&& ((f0.to_bits() & 1) != 0))
61+
{
62+
if !cfg!(any(
63+
target_arch = "powerpc",
64+
target_arch = "powerpc64"
65+
)) {
66+
panic!(
67+
"incorrect rounding by {}({}): {}, ({}, {}, {}), errors ({}, {}, {})",
68+
stringify!($fn),
69+
x,
70+
f1.to_bits(),
71+
y_minus_ulp,
72+
y,
73+
y_plus_ulp,
74+
error_minus,
75+
error,
76+
error_plus,
77+
);
78+
}
5879
}
5980
}
81+
6082
// Test against native conversion. We disable testing on all `x86` because of
6183
// rounding bugs with `i686`. `powerpc` also has the same rounding bug.
62-
if f0 != f1 && !cfg!(any(
84+
if !Float::eq_repr(f0, f1) && !cfg!(any(
6385
target_arch = "x86",
6486
target_arch = "powerpc",
6587
target_arch = "powerpc64"
6688
)) {
6789
panic!(
68-
"{}({}): std: {}, builtins: {}",
90+
"{}({}): std: {:?}, builtins: {:?}",
6991
stringify!($fn),
7092
x,
7193
f0,
@@ -78,19 +100,22 @@ mod int_to_float {
78100
};
79101
}
80102

81-
i_to_f! {
82-
u32, f32, __floatunsisf;
83-
u32, f64, __floatunsidf;
84-
i32, f32, __floatsisf;
85-
i32, f64, __floatsidf;
86-
u64, f32, __floatundisf;
87-
u64, f64, __floatundidf;
88-
i64, f32, __floatdisf;
89-
i64, f64, __floatdidf;
90-
u128, f32, __floatuntisf;
91-
u128, f64, __floatuntidf;
92-
i128, f32, __floattisf;
93-
i128, f64, __floattidf;
103+
i_to_f! { f32, Single, all(),
104+
u32, __floatunsisf;
105+
i32, __floatsisf;
106+
u64, __floatundisf;
107+
i64, __floatdisf;
108+
u128, __floatuntisf;
109+
i128, __floattisf;
110+
}
111+
112+
i_to_f! { f64, Double, all(),
113+
u32, __floatunsidf;
114+
i32, __floatsidf;
115+
u64, __floatundidf;
116+
i64, __floatdidf;
117+
u128, __floatuntidf;
118+
i128, __floattidf;
94119
}
95120
}
96121

0 commit comments

Comments
 (0)