1use crate::simd::{Select, Simd, SimdElement, cmp::SimdPartialEq};
2use core::ops::{Add, Mul};
3use core::ops::{BitAnd, BitOr, BitXor};
4use core::ops::{Div, Rem, Sub};
5use core::ops::{Shl, Shr};
6
7mod assign;
8mod deref;
9mod shift_scalar;
10mod unary;
11
12impl<I, T, const N: usize> core::ops::Index<I> for Simd<T, N>
13where
14 T: SimdElement,
15 I: core::slice::SliceIndex<[T]>,
16{
17 type Output = I::Output;
18 #[inline]
19 fn index(&self, index: I) -> &Self::Output {
20 &self.as_array()[index]
21 }
22}
23
24impl<I, T, const N: usize> core::ops::IndexMut<I> for Simd<T, N>
25where
26 T: SimdElement,
27 I: core::slice::SliceIndex<[T]>,
28{
29 #[inline]
30 fn index_mut(&mut self, index: I) -> &mut Self::Output {
31 &mut self.as_mut_array()[index]
32 }
33}
34
35macro_rules! unsafe_base {
36 ($lhs:ident, $rhs:ident, {$simd_call:ident}, $($_:tt)*) => {
37 unsafe { core::intrinsics::simd::$simd_call($lhs, $rhs) }
39 };
40}
41
42macro_rules! wrap_bitshift {
52 ($lhs:ident, $rhs:ident, {$simd_call:ident}, $int:ident) => {
53 #[allow(clippy::suspicious_arithmetic_impl)]
54 unsafe {
56 core::intrinsics::simd::$simd_call(
57 $lhs,
58 $rhs.bitand(Simd::splat(<$int>::BITS as $int - 1)),
59 )
60 }
61 };
62}
63
64macro_rules! int_divrem_guard {
75 ( $lhs:ident,
76 $rhs:ident,
77 { const PANIC_ZERO: &'static str = $zero:literal;
78 $simd_call:ident, $op:tt
79 },
80 $int:ident ) => {
81 if $rhs.simd_eq(Simd::splat(0 as _)).any() {
82 panic!($zero);
83 } else {
84 let rhs = if <$int>::MIN != 0 {
86 ($lhs.simd_eq(Simd::splat(<$int>::MIN))
90 & $rhs.simd_eq(Simd::splat(-1i64 as _)))
92 .select(Simd::splat(1 as _), $rhs)
93 } else {
94 $rhs
96 };
97
98 #[cfg(target_arch = "aarch64")]
101 {
102 let mut out = Simd::splat(0 as _);
103 for i in 0..Self::LEN {
104 out[i] = $lhs[i] $op rhs[i];
105 }
106 out
107 }
108
109 #[cfg(not(target_arch = "aarch64"))]
110 {
111 unsafe { core::intrinsics::simd::$simd_call($lhs, rhs) }
113 }
114 }
115 };
116}
117
118macro_rules! for_base_types {
119 ( T = ($($scalar:ident),*);
120 type Lhs = Simd<T, N>;
121 type Rhs = Simd<T, N>;
122 type Output = $out:ty;
123
124 impl $op:ident::$call:ident {
125 $macro_impl:ident $inner:tt
126 }) => {
127 $(
128 impl<const N: usize> $op<Self> for Simd<$scalar, N>
129 where
130 $scalar: SimdElement,
131 {
132 type Output = $out;
133
134 #[inline]
135 #[track_caller]
138 fn $call(self, rhs: Self) -> Self::Output {
139 $macro_impl!(self, rhs, $inner, $scalar)
140 }
141 }
142 )*
143 }
144}
145
146macro_rules! for_base_ops {
154 (
155 T = $types:tt;
156 type Lhs = Simd<T, N>;
157 type Rhs = Simd<T, N>;
158 type Output = $out:ident;
159 impl $op:ident::$call:ident
160 $inner:tt
161 $($rest:tt)*
162 ) => {
163 for_base_types! {
164 T = $types;
165 type Lhs = Simd<T, N>;
166 type Rhs = Simd<T, N>;
167 type Output = $out;
168 impl $op::$call
169 $inner
170 }
171 for_base_ops! {
172 T = $types;
173 type Lhs = Simd<T, N>;
174 type Rhs = Simd<T, N>;
175 type Output = $out;
176 $($rest)*
177 }
178 };
179 ($($done:tt)*) => {
180 }
182}
183
184for_base_ops! {
187 T = (i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
188 type Lhs = Simd<T, N>;
189 type Rhs = Simd<T, N>;
190 type Output = Self;
191
192 impl Add::add {
193 unsafe_base { simd_add }
194 }
195
196 impl Mul::mul {
197 unsafe_base { simd_mul }
198 }
199
200 impl Sub::sub {
201 unsafe_base { simd_sub }
202 }
203
204 impl BitAnd::bitand {
205 unsafe_base { simd_and }
206 }
207
208 impl BitOr::bitor {
209 unsafe_base { simd_or }
210 }
211
212 impl BitXor::bitxor {
213 unsafe_base { simd_xor }
214 }
215
216 impl Div::div {
217 int_divrem_guard {
218 const PANIC_ZERO: &'static str = "attempt to divide by zero";
219 simd_div, /
220 }
221 }
222
223 impl Rem::rem {
224 int_divrem_guard {
225 const PANIC_ZERO: &'static str = "attempt to calculate the remainder with a divisor of zero";
226 simd_rem, %
227 }
228 }
229
230 impl Shl::shl {
233 wrap_bitshift { simd_shl }
234 }
235
236 impl Shr::shr {
237 wrap_bitshift {
238 simd_shr
241 }
242 }
243}
244
245for_base_ops! {
248 T = (f32, f64);
249 type Lhs = Simd<T, N>;
250 type Rhs = Simd<T, N>;
251 type Output = Self;
252
253 impl Add::add {
254 unsafe_base { simd_add }
255 }
256
257 impl Mul::mul {
258 unsafe_base { simd_mul }
259 }
260
261 impl Sub::sub {
262 unsafe_base { simd_sub }
263 }
264
265 impl Div::div {
266 unsafe_base { simd_div }
267 }
268
269 impl Rem::rem {
270 unsafe_base { simd_rem }
271 }
272}