about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCaleb Zulawski <caleb.zulawski@gmail.com>2023-07-22 17:56:21 -0400
committerCaleb Zulawski <caleb.zulawski@gmail.com>2023-07-22 17:56:21 -0400
commitd07ce3cef9223c918ae2381fd46ff53ce0cf38b4 (patch)
treef73c88242ec982a4d230be9051152027c4eaecfc
parente73d02929abe6c24b1223a007333d7799e50bb57 (diff)
downloadrust-d07ce3cef9223c918ae2381fd46ff53ce0cf38b4.tar.gz
rust-d07ce3cef9223c918ae2381fd46ff53ce0cf38b4.zip
Account for possible qemu bug
-rw-r--r--crates/test_helpers/src/lib.rs6
-rw-r--r--crates/test_helpers/src/subnormals.rs35
2 files changed, 39 insertions, 2 deletions
diff --git a/crates/test_helpers/src/lib.rs b/crates/test_helpers/src/lib.rs
index 63308a2ca33..d032ded576d 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 d46e8524116..585b80bb6c7 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<bool> = 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<T: FlushSubnormals>(x: T) -> T {
+    if in_buggy_qemu() {
+        x
+    } else {
+        x.flush()
+    }
+}
+
+#[cfg(not(all(target_arch = "powerpc", target_feature = "altivec")))]
+pub fn flush_in<T: FlushSubnormals>(x: T) -> T {
+    x.flush()
+}
+
+pub fn flush<T: FlushSubnormals>(x: T) -> T {
+    x.flush()
+}