]> git.lizzy.rs Git - rust.git/blob - library/portable-simd/crates/core_simd/src/ord.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / library / portable-simd / crates / core_simd / src / ord.rs
1 use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
2
3 /// Parallel `PartialOrd`.
4 pub trait SimdPartialOrd: SimdPartialEq {
5     /// Test if each lane is less than the corresponding lane in `other`.
6     #[must_use = "method returns a new mask and does not mutate the original value"]
7     fn simd_lt(self, other: Self) -> Self::Mask;
8
9     /// Test if each lane is less than or equal to the corresponding lane in `other`.
10     #[must_use = "method returns a new mask and does not mutate the original value"]
11     fn simd_le(self, other: Self) -> Self::Mask;
12
13     /// Test if each lane is greater than the corresponding lane in `other`.
14     #[must_use = "method returns a new mask and does not mutate the original value"]
15     fn simd_gt(self, other: Self) -> Self::Mask;
16
17     /// Test if each lane is greater than or equal to the corresponding lane in `other`.
18     #[must_use = "method returns a new mask and does not mutate the original value"]
19     fn simd_ge(self, other: Self) -> Self::Mask;
20 }
21
22 /// Parallel `Ord`.
23 pub trait SimdOrd: SimdPartialOrd {
24     /// Returns the lane-wise maximum with `other`.
25     #[must_use = "method returns a new vector and does not mutate the original value"]
26     fn simd_max(self, other: Self) -> Self;
27
28     /// Returns the lane-wise minimum with `other`.
29     #[must_use = "method returns a new vector and does not mutate the original value"]
30     fn simd_min(self, other: Self) -> Self;
31
32     /// Restrict each lane to a certain interval.
33     ///
34     /// For each lane, returns `max` if `self` is greater than `max`, and `min` if `self` is
35     /// less than `min`. Otherwise returns `self`.
36     ///
37     /// # Panics
38     ///
39     /// Panics if `min > max` on any lane.
40     #[must_use = "method returns a new vector and does not mutate the original value"]
41     fn simd_clamp(self, min: Self, max: Self) -> Self;
42 }
43
44 macro_rules! impl_integer {
45     { $($integer:ty),* } => {
46         $(
47         impl<const LANES: usize> SimdPartialOrd for Simd<$integer, LANES>
48         where
49             LaneCount<LANES>: SupportedLaneCount,
50         {
51             #[inline]
52             fn simd_lt(self, other: Self) -> Self::Mask {
53                 // Safety: `self` is a vector, and the result of the comparison
54                 // is always a valid mask.
55                 unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
56             }
57
58             #[inline]
59             fn simd_le(self, other: Self) -> Self::Mask {
60                 // Safety: `self` is a vector, and the result of the comparison
61                 // is always a valid mask.
62                 unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
63             }
64
65             #[inline]
66             fn simd_gt(self, other: Self) -> Self::Mask {
67                 // Safety: `self` is a vector, and the result of the comparison
68                 // is always a valid mask.
69                 unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
70             }
71
72             #[inline]
73             fn simd_ge(self, other: Self) -> Self::Mask {
74                 // Safety: `self` is a vector, and the result of the comparison
75                 // is always a valid mask.
76                 unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
77             }
78         }
79
80         impl<const LANES: usize> SimdOrd for Simd<$integer, LANES>
81         where
82             LaneCount<LANES>: SupportedLaneCount,
83         {
84             #[inline]
85             fn simd_max(self, other: Self) -> Self {
86                 self.simd_lt(other).select(other, self)
87             }
88
89             #[inline]
90             fn simd_min(self, other: Self) -> Self {
91                 self.simd_gt(other).select(other, self)
92             }
93
94             #[inline]
95             fn simd_clamp(self, min: Self, max: Self) -> Self {
96                 assert!(
97                     min.simd_le(max).all(),
98                     "each lane in `min` must be less than or equal to the corresponding lane in `max`",
99                 );
100                 self.simd_max(min).simd_min(max)
101             }
102         }
103         )*
104     }
105 }
106
107 impl_integer! { u8, u16, u32, u64, usize, i8, i16, i32, i64, isize }
108
109 macro_rules! impl_float {
110     { $($float:ty),* } => {
111         $(
112         impl<const LANES: usize> SimdPartialOrd for Simd<$float, LANES>
113         where
114             LaneCount<LANES>: SupportedLaneCount,
115         {
116             #[inline]
117             fn simd_lt(self, other: Self) -> Self::Mask {
118                 // Safety: `self` is a vector, and the result of the comparison
119                 // is always a valid mask.
120                 unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
121             }
122
123             #[inline]
124             fn simd_le(self, other: Self) -> Self::Mask {
125                 // Safety: `self` is a vector, and the result of the comparison
126                 // is always a valid mask.
127                 unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
128             }
129
130             #[inline]
131             fn simd_gt(self, other: Self) -> Self::Mask {
132                 // Safety: `self` is a vector, and the result of the comparison
133                 // is always a valid mask.
134                 unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
135             }
136
137             #[inline]
138             fn simd_ge(self, other: Self) -> Self::Mask {
139                 // Safety: `self` is a vector, and the result of the comparison
140                 // is always a valid mask.
141                 unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
142             }
143         }
144         )*
145     }
146 }
147
148 impl_float! { f32, f64 }
149
150 macro_rules! impl_mask {
151     { $($integer:ty),* } => {
152         $(
153         impl<const LANES: usize> SimdPartialOrd for Mask<$integer, LANES>
154         where
155             LaneCount<LANES>: SupportedLaneCount,
156         {
157             #[inline]
158             fn simd_lt(self, other: Self) -> Self::Mask {
159                 // Safety: `self` is a vector, and the result of the comparison
160                 // is always a valid mask.
161                 unsafe { Self::from_int_unchecked(intrinsics::simd_lt(self.to_int(), other.to_int())) }
162             }
163
164             #[inline]
165             fn simd_le(self, other: Self) -> Self::Mask {
166                 // Safety: `self` is a vector, and the result of the comparison
167                 // is always a valid mask.
168                 unsafe { Self::from_int_unchecked(intrinsics::simd_le(self.to_int(), other.to_int())) }
169             }
170
171             #[inline]
172             fn simd_gt(self, other: Self) -> Self::Mask {
173                 // Safety: `self` is a vector, and the result of the comparison
174                 // is always a valid mask.
175                 unsafe { Self::from_int_unchecked(intrinsics::simd_gt(self.to_int(), other.to_int())) }
176             }
177
178             #[inline]
179             fn simd_ge(self, other: Self) -> Self::Mask {
180                 // Safety: `self` is a vector, and the result of the comparison
181                 // is always a valid mask.
182                 unsafe { Self::from_int_unchecked(intrinsics::simd_ge(self.to_int(), other.to_int())) }
183             }
184         }
185
186         impl<const LANES: usize> SimdOrd for Mask<$integer, LANES>
187         where
188             LaneCount<LANES>: SupportedLaneCount,
189         {
190             #[inline]
191             fn simd_max(self, other: Self) -> Self {
192                 self.simd_gt(other).select_mask(other, self)
193             }
194
195             #[inline]
196             fn simd_min(self, other: Self) -> Self {
197                 self.simd_lt(other).select_mask(other, self)
198             }
199
200             #[inline]
201             fn simd_clamp(self, min: Self, max: Self) -> Self {
202                 assert!(
203                     min.simd_le(max).all(),
204                     "each lane in `min` must be less than or equal to the corresponding lane in `max`",
205                 );
206                 self.simd_max(min).simd_min(max)
207             }
208         }
209         )*
210     }
211 }
212
213 impl_mask! { i8, i16, i32, i64, isize }