@@ -12,60 +12,82 @@ mod int_to_float {
12
12
use super :: * ;
13
13
14
14
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) ;* ; ) => {
16
16
$(
17
17
#[ test]
18
18
fn $fn( ) {
19
19
use compiler_builtins:: float:: conv:: $fn;
20
20
use compiler_builtins:: int:: Int ;
21
21
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
+ }
58
79
}
59
80
}
81
+
60
82
// Test against native conversion. We disable testing on all `x86` because of
61
83
// 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(
63
85
target_arch = "x86" ,
64
86
target_arch = "powerpc" ,
65
87
target_arch = "powerpc64"
66
88
) ) {
67
89
panic!(
68
- "{}({}): std: {}, builtins: {}" ,
90
+ "{}({}): std: {:? }, builtins: {:? }" ,
69
91
stringify!( $fn) ,
70
92
x,
71
93
f0,
@@ -78,19 +100,22 @@ mod int_to_float {
78
100
} ;
79
101
}
80
102
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;
94
119
}
95
120
}
96
121
0 commit comments