1 use crate::simd::intrinsics::{ 2 simd_reduce_add_ordered, simd_reduce_and, simd_reduce_max, simd_reduce_min, 3 simd_reduce_mul_ordered, simd_reduce_or, simd_reduce_xor, 4 }; 5 use crate::simd::{LaneCount, Simd, SupportedLaneCount}; 6 7 macro_rules! impl_integer_reductions { 8 { $scalar:ty } => { 9 impl<const LANES: usize> Simd<$scalar, LANES> 10 where 11 LaneCount<LANES>: SupportedLaneCount, 12 { 13 /// Horizontal wrapping add. Returns the sum of the lanes of the vector, with wrapping addition. 14 #[inline] 15 pub fn horizontal_sum(self) -> $scalar { 16 unsafe { simd_reduce_add_ordered(self, 0) } 17 } 18 19 /// Horizontal wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication. 20 #[inline] 21 pub fn horizontal_product(self) -> $scalar { 22 unsafe { simd_reduce_mul_ordered(self, 1) } 23 } 24 25 /// Horizontal bitwise "and". Returns the cumulative bitwise "and" across the lanes of 26 /// the vector. 27 #[inline] 28 pub fn horizontal_and(self) -> $scalar { 29 unsafe { simd_reduce_and(self) } 30 } 31 32 /// Horizontal bitwise "or". Returns the cumulative bitwise "or" across the lanes of 33 /// the vector. 34 #[inline] 35 pub fn horizontal_or(self) -> $scalar { 36 unsafe { simd_reduce_or(self) } 37 } 38 39 /// Horizontal bitwise "xor". Returns the cumulative bitwise "xor" across the lanes of 40 /// the vector. 41 #[inline] 42 pub fn horizontal_xor(self) -> $scalar { 43 unsafe { simd_reduce_xor(self) } 44 } 45 46 /// Horizontal maximum. Returns the maximum lane in the vector. 47 #[inline] 48 pub fn horizontal_max(self) -> $scalar { 49 unsafe { simd_reduce_max(self) } 50 } 51 52 /// Horizontal minimum. Returns the minimum lane in the vector. 53 #[inline] 54 pub fn horizontal_min(self) -> $scalar { 55 unsafe { simd_reduce_min(self) } 56 } 57 } 58 } 59 } 60 61 impl_integer_reductions! { i8 } 62 impl_integer_reductions! { i16 } 63 impl_integer_reductions! { i32 } 64 impl_integer_reductions! { i64 } 65 impl_integer_reductions! { isize } 66 impl_integer_reductions! { u8 } 67 impl_integer_reductions! { u16 } 68 impl_integer_reductions! { u32 } 69 impl_integer_reductions! { u64 } 70 impl_integer_reductions! { usize } 71 72 macro_rules! impl_float_reductions { 73 { $scalar:ty } => { 74 impl<const LANES: usize> Simd<$scalar, LANES> 75 where 76 LaneCount<LANES>: SupportedLaneCount, 77 { 78 79 /// Horizontal add. Returns the sum of the lanes of the vector. 80 #[inline] 81 pub fn horizontal_sum(self) -> $scalar { 82 // LLVM sum is inaccurate on i586 83 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { 84 self.as_array().iter().sum() 85 } else { 86 unsafe { simd_reduce_add_ordered(self, 0.) } 87 } 88 } 89 90 /// Horizontal multiply. Returns the product of the lanes of the vector. 91 #[inline] 92 pub fn horizontal_product(self) -> $scalar { 93 // LLVM product is inaccurate on i586 94 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) { 95 self.as_array().iter().product() 96 } else { 97 unsafe { simd_reduce_mul_ordered(self, 1.) } 98 } 99 } 100 101 /// Horizontal maximum. Returns the maximum lane in the vector. 102 /// 103 /// Returns values based on equality, so a vector containing both `0.` and `-0.` may 104 /// return either. This function will not return `NaN` unless all lanes are `NaN`. 105 #[inline] 106 pub fn horizontal_max(self) -> $scalar { 107 unsafe { simd_reduce_max(self) } 108 } 109 110 /// Horizontal minimum. Returns the minimum lane in the vector. 111 /// 112 /// Returns values based on equality, so a vector containing both `0.` and `-0.` may 113 /// return either. This function will not return `NaN` unless all lanes are `NaN`. 114 #[inline] 115 pub fn horizontal_min(self) -> $scalar { 116 unsafe { simd_reduce_min(self) } 117 } 118 } 119 } 120 } 121 122 impl_float_reductions! { f32 } 123 impl_float_reductions! { f64 } 124