]> git.lizzy.rs Git - rust.git/blob - library/portable-simd/crates/core_simd/src/reduction.rs
Rollup merge of #88361 - WaffleLapkin:patch-2, r=jyn514
[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, 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 }