@@ -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