]> git.proxmox.com Git - rustc.git/blob - library/portable-simd/crates/test_helpers/src/subnormals.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / library / portable-simd / crates / test_helpers / src / subnormals.rs
1 pub trait FlushSubnormals: Sized {
2 fn flush(self) -> Self {
3 self
4 }
5 }
6
7 impl<T> FlushSubnormals for *const T {}
8 impl<T> FlushSubnormals for *mut T {}
9
10 macro_rules! impl_float {
11 { $($ty:ty),* } => {
12 $(
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"),
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 }
29 }
30 )*
31 }
32 }
33
34 macro_rules! impl_else {
35 { $($ty:ty),* } => {
36 $(
37 impl FlushSubnormals for $ty {}
38 )*
39 }
40 }
41
42 impl_float! { 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.
46 /// 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 )))]
85 pub fn flush_in<T: FlushSubnormals>(x: T) -> T {
86 x.flush()
87 }
88
89 pub fn flush<T: FlushSubnormals>(x: T) -> T {
90 x.flush()
91 }