diff --git a/crates/test_helpers/src/lib.rs b/crates/test_helpers/src/lib.rs index 63308a2ca33d..d032ded576d4 100644 --- a/crates/test_helpers/src/lib.rs +++ b/crates/test_helpers/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(stdsimd, powerpc_target_feature)] + pub mod array; #[cfg(target_arch = "wasm32")] @@ -198,7 +200,7 @@ pub fn test_unary_elementwise_flush_subnormals< Vector: Into<[Scalar; LANES]> + From<[Scalar; LANES]> + Copy, VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy, { - let flush = |x: Scalar| FlushSubnormals::flush(fs(FlushSubnormals::flush(x))); + let flush = |x: Scalar| subnormals::flush(fs(subnormals::flush_in(x))); test_1(&|x: [Scalar; LANES]| { proptest::prop_assume!(check(x)); let result_v: [ScalarResult; LANES] = fv(x.into()).into(); @@ -308,7 +310,7 @@ pub fn test_binary_elementwise_flush_subnormals< VectorResult: Into<[ScalarResult; LANES]> + From<[ScalarResult; LANES]> + Copy, { let flush = |x: Scalar1, y: Scalar2| { - FlushSubnormals::flush(fs(FlushSubnormals::flush(x), FlushSubnormals::flush(y))) + subnormals::flush(fs(subnormals::flush_in(x), subnormals::flush_in(y))) }; test_2(&|x: [Scalar1; LANES], y: [Scalar2; LANES]| { proptest::prop_assume!(check(x, y)); diff --git a/crates/test_helpers/src/subnormals.rs b/crates/test_helpers/src/subnormals.rs index d46e8524116c..585b80bb6c73 100644 --- a/crates/test_helpers/src/subnormals.rs +++ b/crates/test_helpers/src/subnormals.rs @@ -41,3 +41,38 @@ macro_rules! impl_else { impl_float! { f32, f64 } impl_else! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize } + +/// AltiVec should flush subnormal inputs to zero, but QEMU seems to only flush outputs. +/// https://gitlab.com/qemu-project/qemu/-/issues/1779 +#[cfg(all(target_arch = "powerpc", target_feature = "altivec"))] +fn in_buggy_qemu() -> bool { + use std::sync::OnceLock; + static BUGGY: OnceLock = OnceLock::new(); + + fn add(x: f32, y: f32) -> f32 { + use core::arch::powerpc::*; + let array: [f32; 4] = + unsafe { core::mem::transmute(vec_add(vec_splats(x), vec_splats(y))) }; + array[0] + } + + *BUGGY.get_or_init(|| add(-1.0857398e-38, 0.).is_sign_negative()) +} + +#[cfg(all(target_arch = "powerpc", target_feature = "altivec"))] +pub fn flush_in(x: T) -> T { + if in_buggy_qemu() { + x + } else { + x.flush() + } +} + +#[cfg(not(all(target_arch = "powerpc", target_feature = "altivec")))] +pub fn flush_in(x: T) -> T { + x.flush() +} + +pub fn flush(x: T) -> T { + x.flush() +}