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,
5 use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
6 use core::ops::{BitAnd, BitOr, BitXor};
8 macro_rules! impl_integer_reductions {
10 impl<const LANES: usize> Simd<$scalar, LANES>
12 LaneCount<LANES>: SupportedLaneCount,
14 /// Horizontal wrapping add. Returns the sum of the lanes of the vector, with wrapping addition.
16 pub fn horizontal_sum(self) -> $scalar {
17 unsafe { simd_reduce_add_ordered(self, 0) }
20 /// Horizontal wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication.
22 pub fn horizontal_product(self) -> $scalar {
23 unsafe { simd_reduce_mul_ordered(self, 1) }
26 /// Horizontal maximum. Returns the maximum lane in the vector.
28 pub fn horizontal_max(self) -> $scalar {
29 unsafe { simd_reduce_max(self) }
32 /// Horizontal minimum. Returns the minimum lane in the vector.
34 pub fn horizontal_min(self) -> $scalar {
35 unsafe { simd_reduce_min(self) }
41 impl_integer_reductions! { i8 }
42 impl_integer_reductions! { i16 }
43 impl_integer_reductions! { i32 }
44 impl_integer_reductions! { i64 }
45 impl_integer_reductions! { isize }
46 impl_integer_reductions! { u8 }
47 impl_integer_reductions! { u16 }
48 impl_integer_reductions! { u32 }
49 impl_integer_reductions! { u64 }
50 impl_integer_reductions! { usize }
52 macro_rules! impl_float_reductions {
54 impl<const LANES: usize> Simd<$scalar, LANES>
56 LaneCount<LANES>: SupportedLaneCount,
59 /// Horizontal add. Returns the sum of the lanes of the vector.
61 pub fn horizontal_sum(self) -> $scalar {
62 // LLVM sum is inaccurate on i586
63 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
64 self.as_array().iter().sum()
66 unsafe { simd_reduce_add_ordered(self, 0.) }
70 /// Horizontal multiply. Returns the product of the lanes of the vector.
72 pub fn horizontal_product(self) -> $scalar {
73 // LLVM product is inaccurate on i586
74 if cfg!(all(target_arch = "x86", not(target_feature = "sse2"))) {
75 self.as_array().iter().product()
77 unsafe { simd_reduce_mul_ordered(self, 1.) }
81 /// Horizontal maximum. Returns the maximum lane in the vector.
83 /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
84 /// return either. This function will not return `NaN` unless all lanes are `NaN`.
86 pub fn horizontal_max(self) -> $scalar {
87 unsafe { simd_reduce_max(self) }
90 /// Horizontal minimum. Returns the minimum lane in the vector.
92 /// Returns values based on equality, so a vector containing both `0.` and `-0.` may
93 /// return either. This function will not return `NaN` unless all lanes are `NaN`.
95 pub fn horizontal_min(self) -> $scalar {
96 unsafe { simd_reduce_min(self) }
102 impl_float_reductions! { f32 }
103 impl_float_reductions! { f64 }
105 impl<T, const LANES: usize> Simd<T, LANES>
107 Self: BitAnd<Self, Output = Self>,
108 T: SimdElement + BitAnd<T, Output = T>,
109 LaneCount<LANES>: SupportedLaneCount,
111 /// Horizontal bitwise "and". Returns the cumulative bitwise "and" across the lanes of
114 pub fn horizontal_and(self) -> T {
115 unsafe { simd_reduce_and(self) }
119 impl<T, const LANES: usize> Simd<T, LANES>
121 Self: BitOr<Self, Output = Self>,
122 T: SimdElement + BitOr<T, Output = T>,
123 LaneCount<LANES>: SupportedLaneCount,
125 /// Horizontal bitwise "or". Returns the cumulative bitwise "or" across the lanes of
128 pub fn horizontal_or(self) -> T {
129 unsafe { simd_reduce_or(self) }
133 impl<T, const LANES: usize> Simd<T, LANES>
135 Self: BitXor<Self, Output = Self>,
136 T: SimdElement + BitXor<T, Output = T>,
137 LaneCount<LANES>: SupportedLaneCount,
139 /// Horizontal bitwise "xor". Returns the cumulative bitwise "xor" across the lanes of
142 pub fn horizontal_xor(self) -> T {
143 unsafe { simd_reduce_xor(self) }