1 pub trait FlushSubnormals
: Sized
{
2 fn flush(self) -> Self {
7 impl<T
> FlushSubnormals
for *const T {}
8 impl<T
> FlushSubnormals
for *mut T {}
10 macro_rules
! impl_float
{
13 impl FlushSubnormals
for $ty
{
14 fn flush(self) -> Self {
15 let is_f32
= core
::mem
::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"),
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)
34 macro_rules
! impl_else
{
37 impl FlushSubnormals
for $ty {}
42 impl_float
! { f32, f64 }
43 impl_else
! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize }
45 /// AltiVec should flush subnormal inputs to zero, but QEMU seems to only flush outputs.
46 /// https://gitlab.com/qemu-project/qemu/-/issues/1779
48 any(target_arch
= "powerpc", target_arch
= "powerpc64"),
49 target_feature
= "altivec"
51 fn in_buggy_qemu() -> bool
{
52 use std
::sync
::OnceLock
;
53 static BUGGY
: OnceLock
<bool
> = OnceLock
::new();
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
::*;
62 unsafe { core::mem::transmute(vec_add(vec_splats(x), vec_splats(y))) }
;
66 *BUGGY
.get_or_init(|| add(-1.0857398e-38, 0.).is_sign_negative())
70 any(target_arch
= "powerpc", target_arch
= "powerpc64"),
71 target_feature
= "altivec"
73 pub fn flush_in
<T
: FlushSubnormals
>(x
: T
) -> T
{
82 any(target_arch
= "powerpc", target_arch
= "powerpc64"),
83 target_feature
= "altivec"
85 pub fn flush_in
<T
: FlushSubnormals
>(x
: T
) -> T
{
89 pub fn flush
<T
: FlushSubnormals
>(x
: T
) -> T
{