1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx2")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
12 #[repr(C, align(32))]
13 pub struct i8x32 { avx: m256i }
14 } else {
15 #[derive(Default, Clone, Copy, PartialEq, Eq)]
22 #[repr(C, align(32))]
23 pub struct i8x32 { a : i8x16, b : i8x16 }
24 }
25}
26
27impl_simd_int! {
28 unsafe {
29 T = i8,
30 N = 32,
31 Simd = i8x32,
32 UintSimd = u8x32,
33 T_BITS = 8,
34 T_BITS_MUL_2 = 16,
35 BitmaskType = u32,
36 [
37 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
38 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
39 ],
40 optional_type_x86_inner { X86Inner = __m256i },
41 optional_type_arm_inner {},
42 optional_type_wasm_inner {},
43 }
44
45 #[inline]
46 fn simd_lt(self, rhs: Self) -> Self::Output {
47 rhs.simd_gt(self)
48 }
49
50 #[inline]
51 fn simd_gt(self, rhs: Self) -> Self::Output {
52 pick! {
53 if #[cfg(target_feature="avx2")] {
54 Self { avx : cmp_gt_mask_i8_m256i(self.avx,rhs.avx) }
55 } else {
56 Self {
57 a : self.a.simd_gt(rhs.a),
58 b : self.b.simd_gt(rhs.b),
59 }
60 }
61 }
62 }
63
64 #[inline]
65 fn simd_le(self, rhs: Self) -> Self::Output {
66 pick! {
67 if #[cfg(target_feature="avx2")] {
68 !self.simd_gt(rhs)
69 } else {
70 Self {
71 a : self.a.simd_le(rhs.a),
72 b : self.b.simd_le(rhs.b),
73 }
74 }
75 }
76 }
77
78 #[inline]
79 fn simd_ge(self, rhs: Self) -> Self::Output {
80 pick! {
81 if #[cfg(target_feature="avx2")] {
82 !self.simd_lt(rhs)
83 } else {
84 Self {
85 a : self.a.simd_ge(rhs.a),
86 b : self.b.simd_ge(rhs.b),
87 }
88 }
89 }
90 }
91
92 #[inline]
93 fn shr(self, rhs: u8x32) -> Self::Output {
94 let [self_a, self_b]: [i8x16; 2] = cast(self);
98 let [rhs_a, rhs_b]: [u8x16; 2] = cast(rhs);
99 cast([self_a >> rhs_a, self_b >> rhs_b])
100 }
101
102 #[inline]
103 fn shr(self, rhs: u32) -> Self::Output {
104 let [self_a, self_b]: [i8x16; 2] = cast(self);
108 cast([self_a >> rhs, self_b >> rhs])
109 }
110
111 #[inline]
112 pub fn max(self, rhs: Self) -> Self {
113 pick! {
114 if #[cfg(target_feature="avx2")] {
115 Self { avx: max_i8_m256i(self.avx,rhs.avx) }
116 } else {
117 Self {
118 a : self.a.max(rhs.a),
119 b : self.b.max(rhs.b),
120 }
121 }
122 }
123 }
124
125 #[inline]
126 pub fn min(self, rhs: Self) -> Self {
127 pick! {
128 if #[cfg(target_feature="avx2")] {
129 Self { avx: min_i8_m256i(self.avx,rhs.avx) }
130 } else {
131 Self {
132 a : self.a.min(rhs.a),
133 b : self.b.min(rhs.b),
134 }
135 }
136 }
137 }
138
139 #[inline]
140 pub fn reduce_max(self) -> i8 {
141 let array: [i8x16; 2] = cast(self);
142 array[0].max(array[1]).reduce_max()
143 }
144
145 #[inline]
146 pub fn reduce_min(self) -> i8 {
147 let array: [i8x16; 2] = cast(self);
148 array[0].min(array[1]).reduce_min()
149 }
150
151 #[inline]
152 pub fn unbounded_shr(self, rhs: u8x32) -> Self {
153 let [self_a, self_b] = cast::<i8x32, [i8x16; 2]>(self);
157 let [rhs_a, rhs_b] = cast::<u8x32, [u8x16; 2]>(rhs);
158 cast([self_a.unbounded_shr(rhs_a), self_b.unbounded_shr(rhs_b)])
159 }
160
161 #[inline]
162 pub fn unbounded_shr_scalar(self, rhs: u32) -> Self {
163 let [self_a, self_b] = cast::<i8x32, [i8x16; 2]>(self);
167 cast([self_a.unbounded_shr_scalar(rhs), self_b.unbounded_shr_scalar(rhs)])
168 }
169
170 #[inline]
171 pub fn saturating_add(self, rhs: Self) -> Self {
172 pick! {
173 if #[cfg(target_feature="avx2")] {
174 Self { avx: add_saturating_i8_m256i(self.avx, rhs.avx) }
175 } else {
176 Self {
177 a : self.a.saturating_add(rhs.a),
178 b : self.b.saturating_add(rhs.b),
179 }
180 }
181 }
182 }
183
184 #[inline]
185 pub fn saturating_sub(self, rhs: Self) -> Self {
186 pick! {
187 if #[cfg(target_feature="avx2")] {
188 Self { avx: sub_saturating_i8_m256i(self.avx, rhs.avx) }
189 } else {
190 Self {
191 a : self.a.saturating_sub(rhs.a),
192 b : self.b.saturating_sub(rhs.b),
193 }
194 }
195 }
196 }
197
198 #[inline]
199 pub fn overflowing_mul(self, rhs: Self) -> (Self, Self) {
200 let (low, high) = self.mul_keep_low_high(rhs);
201 let low = cast::<u8x32, i8x32>(low);
202
203 let overflow = high.simd_ne(low.is_negative());
204 (low, overflow)
205 }
206
207 optional_fn_widening_mul {
208 #[inline]
209 pub fn widening_mul(self, rhs: Self) -> i16x32 {
210 let [self_a, self_b] = cast::<i8x32, [i8x16; 2]>(self);
214 let [rhs_a, rhs_b] = cast::<i8x32, [i8x16; 2]>(rhs);
215
216 cast([self_a.widening_mul(rhs_a), self_b.widening_mul(rhs_b)])
217 }
218 }
219
220 #[inline]
221 pub fn mul_keep_low_high(self, rhs: Self) -> (u8x32, i8x32) {
222 let [self_a, self_b] = cast::<i8x32, [i8x16; 2]>(self);
226 let [rhs_a, rhs_b] = cast::<i8x32, [i8x16; 2]>(rhs);
227
228 let result_a = self_a.mul_keep_low_high(rhs_a);
229 let result_b = self_b.mul_keep_low_high(rhs_b);
230 (cast([result_a.0, result_b.0]), cast([result_a.1, result_b.1]))
231 }
232
233 #[inline]
234 pub fn mul_keep_high(self, rhs: Self) -> Self {
235 let [self_a, self_b] = cast::<i8x32, [i8x16; 2]>(self);
239 let [rhs_a, rhs_b] = cast::<i8x32, [i8x16; 2]>(rhs);
240
241 cast([self_a.mul_keep_high(rhs_a), self_b.mul_keep_high(rhs_b)])
242 }
243
244 #[inline]
245 pub fn abs(self) -> Self {
246 pick! {
247 if #[cfg(target_feature="avx2")] {
248 Self { avx: abs_i8_m256i(self.avx) }
249 } else {
250 Self {
251 a : self.a.abs(),
252 b : self.b.abs(),
253 }
254 }
255 }
256 }
257
258 #[inline]
259 pub fn is_positive(self) -> Self {
260 pick! {
261 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
262 Self {
264 a: self.a.is_positive(),
265 b: self.b.is_positive(),
266 }
267 } else {
268 self.simd_gt(Self::ZERO)
269 }
270 }
271 }
272
273 #[inline]
274 pub fn is_negative(self) -> Self {
275 pick! {
276 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
277 Self {
279 a: self.a.is_negative(),
280 b: self.b.is_negative(),
281 }
282 } else {
283 self.simd_lt(Self::ZERO)
284 }
285 }
286 }
287
288 optional_fn_deserialize {}
289}
290
291impl i8x32 {
294 #[inline]
303 pub fn swizzle_half(self, rhs: i8x32) -> i8x32 {
304 pick! {
305 if #[cfg(target_feature="avx2")] {
306 Self { avx: shuffle_av_i8z_half_m256i(self.avx, add_saturating_u8_m256i(rhs.avx, set_splat_i8_m256i(0x70))) }
307 } else {
308 Self {
309 a : self.a.shuffle_zeroing(rhs.a.cast_unsigned()),
310 b : self.b.shuffle_zeroing(rhs.b.cast_unsigned()),
311 }
312 }
313 }
314 }
315
316 #[inline]
326 pub fn swizzle_half_relaxed(self, rhs: i8x32) -> i8x32 {
327 pick! {
328 if #[cfg(target_feature="avx2")] {
329 Self { avx: shuffle_av_i8z_half_m256i(self.avx, rhs.avx) }
330 } else {
331 Self {
332 a : self.a.shuffle(rhs.a.cast_unsigned()),
333 b : self.b.shuffle(rhs.b.cast_unsigned()),
334 }
335 }
336 }
337 }
338
339 #[inline]
351 #[deprecated(since = "1.7.0", note = "replaced with `shuffle_zeroing`")]
352 pub fn swizzle(self, rhs: i8x32) -> i8x32 {
353 self.shuffle_zeroing(rhs.cast_unsigned())
354 }
355
356 #[inline]
365 #[deprecated(since = "1.7.0", note = "replaced with `shuffle`")]
366 pub fn swizzle_relaxed(self, rhs: i8x32) -> i8x32 {
367 self.shuffle(rhs.cast_unsigned())
368 }
369}