@@ -7,81 +7,45 @@ pub trait FlushSubnormals: Sized {
77impl < T > FlushSubnormals for * const T { }
88impl < T > FlushSubnormals for * mut T { }
99
10- macro_rules! impl_float {
11- { $( $ty: ty) ,* } => {
12- $(
13- impl FlushSubnormals for $ty {
14- fn flush( self ) -> Self {
15- let is_f32 = size_of:: <Self >( ) == 4 ;
16- let ppc_flush = is_f32 && cfg!( all(
17- any( target_arch = "powerpc" , all( target_arch = "powerpc64" , target_endian = "big" ) ) ,
18- target_feature = "altivec" ,
19- not( target_feature = "vsx" ) ,
20- ) ) ;
21- let arm_flush = is_f32 && cfg!( all( target_arch = "arm" , target_feature = "neon" ) ) ;
22- let flush = ppc_flush || arm_flush;
23- if flush && self . is_subnormal( ) {
24- <$ty>:: copysign( 0. , self )
25- } else {
26- self
27- }
28- }
10+ impl FlushSubnormals for i8 { }
11+ impl FlushSubnormals for i16 { }
12+ impl FlushSubnormals for i32 { }
13+ impl FlushSubnormals for i64 { }
14+ impl FlushSubnormals for isize { }
15+
16+ impl FlushSubnormals for u8 { }
17+ impl FlushSubnormals for u16 { }
18+ impl FlushSubnormals for u32 { }
19+ impl FlushSubnormals for u64 { }
20+ impl FlushSubnormals for usize { }
21+
22+ impl FlushSubnormals for f16 { }
23+ impl FlushSubnormals for f64 { }
24+
25+ impl FlushSubnormals for f32 {
26+ fn flush ( self ) -> Self {
27+ // Correct for non-IEEE behavior for f32 on arm and powerpc.
28+ let ppc_flush = cfg ! ( all(
29+ any(
30+ target_arch = "powerpc" ,
31+ all( target_arch = "powerpc64" , target_endian = "big" )
32+ ) ,
33+ target_feature = "altivec" ,
34+ not( target_feature = "vsx" ) ,
35+ ) ) ;
36+ let arm_flush = cfg ! ( all( target_arch = "arm" , target_feature = "neon" ) ) ;
37+ let flush = ppc_flush || arm_flush;
38+
39+ if flush && self . is_subnormal ( ) {
40+ f32:: copysign ( 0.0 , self )
41+ } else {
42+ self
2943 }
30- ) *
31- }
32- }
33-
34- macro_rules! impl_else {
35- { $( $ty: ty) ,* } => {
36- $(
37- impl FlushSubnormals for $ty { }
38- ) *
3944 }
4045}
4146
42- impl_float ! { f16, f32 , f64 }
43- impl_else ! { i8 , i16 , i32 , i64 , isize , u8 , u16 , u32 , u64 , usize }
44-
45- /// AltiVec should flush subnormal inputs to zero, but QEMU seems to only flush outputs.
47+ /// NOTE: altivec had a subnormal flushing bug in older QEMU versions.
4648/// https://gitlab.com/qemu-project/qemu/-/issues/1779
47- #[ cfg( all(
48- any( target_arch = "powerpc" , target_arch = "powerpc64" ) ,
49- target_feature = "altivec"
50- ) ) ]
51- fn in_buggy_qemu ( ) -> bool {
52- use std:: sync:: OnceLock ;
53- static BUGGY : OnceLock < bool > = OnceLock :: new ( ) ;
54-
55- fn add ( x : f32 , y : f32 ) -> f32 {
56- #[ cfg( target_arch = "powerpc" ) ]
57- use core:: arch:: powerpc:: * ;
58- #[ cfg( target_arch = "powerpc64" ) ]
59- use core:: arch:: powerpc64:: * ;
60-
61- let array: [ f32 ; 4 ] =
62- unsafe { core:: mem:: transmute ( vec_add ( vec_splats ( x) , vec_splats ( y) ) ) } ;
63- array[ 0 ]
64- }
65-
66- * BUGGY . get_or_init ( || add ( -1.0857398e-38 , 0. ) . is_sign_negative ( ) )
67- }
68-
69- #[ cfg( all(
70- any( target_arch = "powerpc" , target_arch = "powerpc64" ) ,
71- target_feature = "altivec"
72- ) ) ]
73- pub fn flush_in < T : FlushSubnormals > ( x : T ) -> T {
74- if in_buggy_qemu ( ) {
75- x
76- } else {
77- x. flush ( )
78- }
79- }
80-
81- #[ cfg( not( all(
82- any( target_arch = "powerpc" , target_arch = "powerpc64" ) ,
83- target_feature = "altivec"
84- ) ) ) ]
8549pub fn flush_in < T : FlushSubnormals > ( x : T ) -> T {
8650 x. flush ( )
8751}
0 commit comments