]> git.lizzy.rs Git - rust.git/blob - library/portable-simd/crates/core_simd/src/reduction.rs
Rollup merge of #91610 - aDotInTheVoid:patch-2, r=GuillaumeGomez
[rust.git] / library / portable-simd / crates / core_simd / src / reduction.rs
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, SimdElement, SupportedLaneCount};
6 use core::ops::{BitAnd, BitOr, BitXor};
7
8 macro_rules! impl_integer_reductions {
9     { $scalar:ty } => {
10         impl<const LANES: usize> Simd<$scalar, LANES>
11         where
12             LaneCount<LANES>: SupportedLaneCount,
13         {
14             /// Horizontal wrapping add.  Returns the sum of the lanes of the vector, with wrapping addition.
15             #[inline]
16             pub fn horizontal_sum(self) -> $scalar {
17                 unsafe { simd_reduce_add_ordered(self, 0) }
18             }
19
20             /// Horizontal wrapping multiply.  Returns the product of the lanes of the vector, with wrapping multiplication.
21             #[inline]
22             pub fn horizontal_product(self) -> $scalar {
23                 unsafe { simd_reduce_mul_ordered(self, 1) }
24             }
25
26             /// Horizontal maximum.  Returns the maximum lane in the vector.
27             #[inline]
28             pub fn horizontal_max(self) -> $scalar {
29                 unsafe { simd_reduce_max(self) }
30             }
31
32             /// Horizontal minimum.  Returns the minimum lane in the vector.
33             #[inline]
34             pub fn horizontal_min(self) -> $scalar {
35                 unsafe { simd_reduce_min(self) }
36             }
37         }
38     }
39 }
40
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 }
51
52 macro_rules! impl_float_reductions {
53     { $scalar:ty } => {
54         impl<const LANES: usize> Simd<$scalar, LANES>
55         where
56             LaneCount<LANES>: SupportedLaneCount,
57         {
58
59             /// Horizontal add.  Returns the sum of the lanes of the vector.
60             #[inline]
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()
65                 } else {
66                     unsafe { simd_reduce_add_ordered(self, 0.) }
67                 }
68             }
69
70             /// Horizontal multiply.  Returns the product of the lanes of the vector.
71             #[inline]
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()
76                 } else {
77                     unsafe { simd_reduce_mul_ordered(self, 1.) }
78                 }
79             }
80
81             /// Horizontal maximum.  Returns the maximum lane in the vector.
82             ///
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`.
85             #[inline]
86             pub fn horizontal_max(self) -> $scalar {
87                 unsafe { simd_reduce_max(self) }
88             }
89
90             /// Horizontal minimum.  Returns the minimum lane in the vector.
91             ///
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`.
94             #[inline]
95             pub fn horizontal_min(self) -> $scalar {
96                 unsafe { simd_reduce_min(self) }
97             }
98         }
99     }
100 }
101
102 impl_float_reductions! { f32 }
103 impl_float_reductions! { f64 }
104
105 impl<T, const LANES: usize> Simd<T, LANES>
106 where
107     Self: BitAnd<Self, Output = Self>,
108     T: SimdElement + BitAnd<T, Output = T>,
109     LaneCount<LANES>: SupportedLaneCount,
110 {
111     /// Horizontal bitwise "and".  Returns the cumulative bitwise "and" across the lanes of
112     /// the vector.
113     #[inline]
114     pub fn horizontal_and(self) -> T {
115         unsafe { simd_reduce_and(self) }
116     }
117 }
118
119 impl<T, const LANES: usize> Simd<T, LANES>
120 where
121     Self: BitOr<Self, Output = Self>,
122     T: SimdElement + BitOr<T, Output = T>,
123     LaneCount<LANES>: SupportedLaneCount,
124 {
125     /// Horizontal bitwise "or".  Returns the cumulative bitwise "or" across the lanes of
126     /// the vector.
127     #[inline]
128     pub fn horizontal_or(self) -> T {
129         unsafe { simd_reduce_or(self) }
130     }
131 }
132
133 impl<T, const LANES: usize> Simd<T, LANES>
134 where
135     Self: BitXor<Self, Output = Self>,
136     T: SimdElement + BitXor<T, Output = T>,
137     LaneCount<LANES>: SupportedLaneCount,
138 {
139     /// Horizontal bitwise "xor".  Returns the cumulative bitwise "xor" across the lanes of
140     /// the vector.
141     #[inline]
142     pub fn horizontal_xor(self) -> T {
143         unsafe { simd_reduce_xor(self) }
144     }
145 }