//! Implements portable horizontal bitwise vector reductions. #![allow(unused)] macro_rules! impl_reduction_bitwise { ( [$elem_ty:ident; $elem_count:expr]: $id:ident | $ielem_ty:ident | $test_tt:tt | ($convert:expr) | ($true:expr, $false:expr) ) => { impl $id { /// Lane-wise bitwise `and` of the vector elements. /// /// Note: if the vector has one lane, the first element of the /// vector is returned. #[inline] pub fn and(self) -> $elem_ty { #[cfg(not(target_arch = "aarch64"))] { use crate::llvm::simd_reduce_and; let r: $ielem_ty = unsafe { simd_reduce_and(self.0) }; $convert(r) } #[cfg(target_arch = "aarch64")] { // FIXME: broken on aarch64 // https://github.com/rust-lang-nursery/packed_simd/issues/15 let mut x = self.extract(0) as $elem_ty; for i in 1..$id::lanes() { x &= self.extract(i) as $elem_ty; } x } } /// Lane-wise bitwise `or` of the vector elements. /// /// Note: if the vector has one lane, the first element of the /// vector is returned. #[inline] pub fn or(self) -> $elem_ty { #[cfg(not(target_arch = "aarch64"))] { use crate::llvm::simd_reduce_or; let r: $ielem_ty = unsafe { simd_reduce_or(self.0) }; $convert(r) } #[cfg(target_arch = "aarch64")] { // FIXME: broken on aarch64 // https://github.com/rust-lang-nursery/packed_simd/issues/15 let mut x = self.extract(0) as $elem_ty; for i in 1..$id::lanes() { x |= self.extract(i) as $elem_ty; } x } } /// Lane-wise bitwise `xor` of the vector elements. /// /// Note: if the vector has one lane, the first element of the /// vector is returned. #[inline] pub fn xor(self) -> $elem_ty { #[cfg(not(target_arch = "aarch64"))] { use crate::llvm::simd_reduce_xor; let r: $ielem_ty = unsafe { simd_reduce_xor(self.0) }; $convert(r) } #[cfg(target_arch = "aarch64")] { // FIXME: broken on aarch64 // https://github.com/rust-lang-nursery/packed_simd/issues/15 let mut x = self.extract(0) as $elem_ty; for i in 1..$id::lanes() { x ^= self.extract(i) as $elem_ty; } x } } } test_if!{ $test_tt: paste::item! { pub mod [<$id _reduction_bitwise>] { use super::*; #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn and() { let v = $id::splat($false); assert_eq!(v.and(), $false); let v = $id::splat($true); assert_eq!(v.and(), $true); let v = $id::splat($false); let v = v.replace(0, $true); if $id::lanes() > 1 { assert_eq!(v.and(), $false); } else { assert_eq!(v.and(), $true); } let v = $id::splat($true); let v = v.replace(0, $false); assert_eq!(v.and(), $false); } #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn or() { let v = $id::splat($false); assert_eq!(v.or(), $false); let v = $id::splat($true); assert_eq!(v.or(), $true); let v = $id::splat($false); let v = v.replace(0, $true); assert_eq!(v.or(), $true); let v = $id::splat($true); let v = v.replace(0, $false); if $id::lanes() > 1 { assert_eq!(v.or(), $true); } else { assert_eq!(v.or(), $false); } } #[cfg_attr(not(target_arch = "wasm32"), test)] #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] fn xor() { let v = $id::splat($false); assert_eq!(v.xor(), $false); let v = $id::splat($true); if $id::lanes() > 1 { assert_eq!(v.xor(), $false); } else { assert_eq!(v.xor(), $true); } let v = $id::splat($false); let v = v.replace(0, $true); assert_eq!(v.xor(), $true); let v = $id::splat($true); let v = v.replace(0, $false); if $id::lanes() > 1 { assert_eq!(v.xor(), $true); } else { assert_eq!(v.xor(), $false); } } } } } }; }