1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx512bw")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
12 #[repr(C, align(64))]
13 pub struct i8x64 { avx512: m512i }
14 } else {
15 #[derive(Default, Clone, Copy, PartialEq, Eq)]
22 #[repr(C, align(64))]
23 pub struct i8x64 { a : i8x32, b : i8x32 }
24 }
25}
26
27impl_simd_int! {
28 unsafe {
29 T = i8,
30 N = 64,
31 Simd = i8x64,
32 UintSimd = u8x64,
33 T_BITS = 8,
34 T_BITS_MUL_2 = 16,
35 BitmaskType = u64,
36 [
37 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
38 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
39 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
40 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63
41 ],
42 optional_type_x86_inner { X86Inner = __m512i },
43 optional_type_arm_inner {},
44 optional_type_wasm_inner {},
45 }
46
47 #[inline]
48 fn simd_lt(self, rhs: Self) -> Self::Output {
49 rhs.simd_gt(self)
50 }
51
52 #[inline]
53 fn simd_gt(self, rhs: Self) -> Self::Output {
54 pick! {
55 if #[cfg(target_feature="avx512bw")] {
56 Self { avx512: cmp_op_mask_i8_m512i::<{cmp_int_op!(Nle)}>(self.avx512, rhs.avx512) }
57 } else {
58 Self {
59 a : self.a.simd_gt(rhs.a),
60 b : self.b.simd_gt(rhs.b),
61 }
62 }
63 }
64 }
65
66 #[inline]
67 fn simd_le(self, rhs: Self) -> Self::Output {
68 pick! {
69 if #[cfg(target_feature="avx512bw")] {
70 Self { avx512: cmp_op_mask_i8_m512i::<{cmp_int_op!(Le)}>(self.avx512, rhs.avx512) }
71 } else {
72 Self {
73 a : self.a.simd_le(rhs.a),
74 b : self.b.simd_le(rhs.b),
75 }
76 }
77 }
78 }
79
80 #[inline]
81 fn simd_ge(self, rhs: Self) -> Self::Output {
82 pick! {
83 if #[cfg(target_feature="avx512bw")] {
84 Self { avx512: cmp_op_mask_i8_m512i::<{cmp_int_op!(Nlt)}>(self.avx512, rhs.avx512) }
85 } else {
86 Self {
87 a : self.a.simd_ge(rhs.a),
88 b : self.b.simd_ge(rhs.b),
89 }
90 }
91 }
92 }
93
94 #[inline]
95 fn shr(self, rhs: u8x64) -> Self::Output {
96 let [self_a, self_b]: [i8x32; 2] = cast(self);
99 let [rhs_a, rhs_b]: [u8x32; 2] = cast(rhs);
100 cast([self_a >> rhs_a, self_b >> rhs_b])
101 }
102
103 #[inline]
104 fn shr(self, rhs: u32) -> Self::Output {
105 let [self_a, self_b]: [i8x32; 2] = cast(self);
106 cast([self_a >> rhs, self_b >> rhs])
107 }
108
109 #[inline]
110 pub fn max(self, rhs: Self) -> Self {
111 pick! {
112 if #[cfg(target_feature="avx512bw")] {
113 Self { avx512: max_i8_m512i(self.avx512, rhs.avx512) }
114 } else {
115 Self {
116 a : self.a.max(rhs.a),
117 b : self.b.max(rhs.b),
118 }
119 }
120 }
121 }
122
123 #[inline]
124 pub fn min(self, rhs: Self) -> Self {
125 pick! {
126 if #[cfg(target_feature="avx512bw")] {
127 Self { avx512: min_i8_m512i(self.avx512, rhs.avx512) }
128 } else {
129 Self {
130 a : self.a.min(rhs.a),
131 b : self.b.min(rhs.b),
132 }
133 }
134 }
135 }
136
137 #[inline]
138 pub fn reduce_max(self) -> i8 {
139 let array: [i8x32; 2] = cast(self);
140 array[0].max(array[1]).reduce_max()
141 }
142
143 #[inline]
144 pub fn reduce_min(self) -> i8 {
145 let array: [i8x32; 2] = cast(self);
146 array[0].min(array[1]).reduce_min()
147 }
148
149 #[inline]
150 pub fn unbounded_shr(self, rhs: u8x64) -> Self {
151 let [self_a, self_b] = cast::<i8x64, [i8x32; 2]>(self);
152 let [rhs_a, rhs_b] = cast::<u8x64, [u8x32; 2]>(rhs);
153 cast([self_a.unbounded_shr(rhs_a), self_b.unbounded_shr(rhs_b)])
154 }
155
156 #[inline]
157 pub fn unbounded_shr_scalar(self, rhs: u32) -> Self {
158 let [self_a, self_b] = cast::<i8x64, [i8x32; 2]>(self);
159 cast([self_a.unbounded_shr_scalar(rhs), self_b.unbounded_shr_scalar(rhs)])
160 }
161
162 #[inline]
163 pub fn saturating_add(self, rhs: Self) -> Self {
164 pick! {
165 if #[cfg(target_feature="avx512bw")] {
166 Self { avx512: add_saturating_i8_m512i(self.avx512, rhs.avx512) }
167 } else {
168 Self {
169 a : self.a.saturating_add(rhs.a),
170 b : self.b.saturating_add(rhs.b),
171 }
172 }
173 }
174 }
175
176 #[inline]
177 pub fn saturating_sub(self, rhs: Self) -> Self {
178 pick! {
179 if #[cfg(target_feature="avx512bw")] {
180 Self { avx512: sub_saturating_i8_m512i(self.avx512, rhs.avx512) }
181 } else {
182 Self {
183 a : self.a.saturating_sub(rhs.a),
184 b : self.b.saturating_sub(rhs.b),
185 }
186 }
187 }
188 }
189
190 #[inline]
191 pub fn overflowing_mul(self, rhs: Self) -> (Self, Self) {
192 let (low, high) = self.mul_keep_low_high(rhs);
193 let low = cast::<u8x64, i8x64>(low);
194
195 let overflow = high.simd_ne(low.is_negative());
196 (low, overflow)
197 }
198
199 optional_fn_widening_mul {
200 }
202
203 #[inline]
204 pub fn mul_keep_low_high(self, rhs: Self) -> (u8x64, i8x64) {
205 let [self_a, self_b] = cast::<i8x64, [i8x32; 2]>(self);
209 let [rhs_a, rhs_b] = cast::<i8x64, [i8x32; 2]>(rhs);
210
211 let result_a = self_a.mul_keep_low_high(rhs_a);
212 let result_b = self_b.mul_keep_low_high(rhs_b);
213 (cast([result_a.0, result_b.0]), cast([result_a.1, result_b.1]))
214 }
215
216 #[inline]
217 pub fn mul_keep_high(self, rhs: Self) -> Self {
218 let [self_a, self_b] = cast::<i8x64, [i8x32; 2]>(self);
222 let [rhs_a, rhs_b] = cast::<i8x64, [i8x32; 2]>(rhs);
223
224 cast([self_a.mul_keep_high(rhs_a), self_b.mul_keep_high(rhs_b)])
225 }
226
227 #[inline]
228 pub fn abs(self) -> Self {
229 pick! {
230 if #[cfg(target_feature="avx512bw")] {
231 Self { avx512: abs_i8_m512i(self.avx512) }
232 } else {
233 Self {
234 a : self.a.abs(),
235 b : self.b.abs(),
236 }
237 }
238 }
239 }
240
241 #[inline]
242 pub fn is_positive(self) -> Self {
243 pick! {
244 if #[cfg(target_feature="avx512bw")] {
245 self.simd_gt(Self::ZERO)
246 } else {
247 Self {
248 a : self.a.is_positive(),
249 b : self.b.is_positive(),
250 }
251 }
252 }
253 }
254
255 #[inline]
256 pub fn is_negative(self) -> Self {
257 pick! {
258 if #[cfg(target_feature="avx512bw")] {
259 self.simd_lt(Self::ZERO)
260 } else {
261 Self {
262 a : self.a.is_negative(),
263 b : self.b.is_negative(),
264 }
265 }
266 }
267 }
268
269 optional_fn_deserialize {
270 #[inline]
271 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
272 where
273 D: serde_core::Deserializer<'de>,
274 {
275 crate::simd::deserialize_array(deserializer)
276 }
277 }
278}