core/portable-simd/crates/core_simd/src/
ops.rs1use crate::simd::{cmp::SimdPartialEq, LaneCount, Simd, SimdElement, SupportedLaneCount};
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 LaneCount<N>: SupportedLaneCount,
16 I: core::slice::SliceIndex<[T]>,
17{
18 type Output = I::Output;
19 #[inline]
20 fn index(&self, index: I) -> &Self::Output {
21 &self.as_array()[index]
22 }
23}
24
25impl<I, T, const N: usize> core::ops::IndexMut<I> for Simd<T, N>
26where
27 T: SimdElement,
28 LaneCount<N>: SupportedLaneCount,
29 I: core::slice::SliceIndex<[T]>,
30{
31 #[inline]
32 fn index_mut(&mut self, index: I) -> &mut Self::Output {
33 &mut self.as_mut_array()[index]
34 }
35}
36
37macro_rules! unsafe_base {
38 ($lhs:ident, $rhs:ident, {$simd_call:ident}, $($_:tt)*) => {
39 unsafe { core::intrinsics::simd::$simd_call($lhs, $rhs) }
41 };
42}
43
44macro_rules! wrap_bitshift {
54 ($lhs:ident, $rhs:ident, {$simd_call:ident}, $int:ident) => {
55 #[allow(clippy::suspicious_arithmetic_impl)]
56 unsafe {
58 core::intrinsics::simd::$simd_call(
59 $lhs,
60 $rhs.bitand(Simd::splat(<$int>::BITS as $int - 1)),
61 )
62 }
63 };
64}
65
66macro_rules! int_divrem_guard {
77 ( $lhs:ident,
78 $rhs:ident,
79 { const PANIC_ZERO: &'static str = $zero:literal;
80 $simd_call:ident, $op:tt
81 },
82 $int:ident ) => {
83 if $rhs.simd_eq(Simd::splat(0 as _)).any() {
84 panic!($zero);
85 } else {
86 let rhs = if <$int>::MIN != 0 {
88 ($lhs.simd_eq(Simd::splat(<$int>::MIN))
92 & $rhs.simd_eq(Simd::splat(-1i64 as _)))
94 .select(Simd::splat(1 as _), $rhs)
95 } else {
96 $rhs
98 };
99
100 #[cfg(target_arch = "aarch64")]
103 {
104 let mut out = Simd::splat(0 as _);
105 for i in 0..Self::LEN {
106 out[i] = $lhs[i] $op rhs[i];
107 }
108 out
109 }
110
111 #[cfg(not(target_arch = "aarch64"))]
112 {
113 unsafe { core::intrinsics::simd::$simd_call($lhs, rhs) }
115 }
116 }
117 };
118}
119
120macro_rules! for_base_types {
121 ( T = ($($scalar:ident),*);
122 type Lhs = Simd<T, N>;
123 type Rhs = Simd<T, N>;
124 type Output = $out:ty;
125
126 impl $op:ident::$call:ident {
127 $macro_impl:ident $inner:tt
128 }) => {
129 $(
130 impl<const N: usize> $op<Self> for Simd<$scalar, N>
131 where
132 $scalar: SimdElement,
133 LaneCount<N>: SupportedLaneCount,
134 {
135 type Output = $out;
136
137 #[inline]
138 #[must_use = "operator returns a new vector without mutating the inputs"]
139 #[track_caller]
142 fn $call(self, rhs: Self) -> Self::Output {
143 $macro_impl!(self, rhs, $inner, $scalar)
144 }
145 }
146 )*
147 }
148}
149
150macro_rules! for_base_ops {
158 (
159 T = $types:tt;
160 type Lhs = Simd<T, N>;
161 type Rhs = Simd<T, N>;
162 type Output = $out:ident;
163 impl $op:ident::$call:ident
164 $inner:tt
165 $($rest:tt)*
166 ) => {
167 for_base_types! {
168 T = $types;
169 type Lhs = Simd<T, N>;
170 type Rhs = Simd<T, N>;
171 type Output = $out;
172 impl $op::$call
173 $inner
174 }
175 for_base_ops! {
176 T = $types;
177 type Lhs = Simd<T, N>;
178 type Rhs = Simd<T, N>;
179 type Output = $out;
180 $($rest)*
181 }
182 };
183 ($($done:tt)*) => {
184 }
186}
187
188for_base_ops! {
191 T = (i8, i16, i32, i64, isize, u8, u16, u32, u64, usize);
192 type Lhs = Simd<T, N>;
193 type Rhs = Simd<T, N>;
194 type Output = Self;
195
196 impl Add::add {
197 unsafe_base { simd_add }
198 }
199
200 impl Mul::mul {
201 unsafe_base { simd_mul }
202 }
203
204 impl Sub::sub {
205 unsafe_base { simd_sub }
206 }
207
208 impl BitAnd::bitand {
209 unsafe_base { simd_and }
210 }
211
212 impl BitOr::bitor {
213 unsafe_base { simd_or }
214 }
215
216 impl BitXor::bitxor {
217 unsafe_base { simd_xor }
218 }
219
220 impl Div::div {
221 int_divrem_guard {
222 const PANIC_ZERO: &'static str = "attempt to divide by zero";
223 simd_div, /
224 }
225 }
226
227 impl Rem::rem {
228 int_divrem_guard {
229 const PANIC_ZERO: &'static str = "attempt to calculate the remainder with a divisor of zero";
230 simd_rem, %
231 }
232 }
233
234 impl Shl::shl {
237 wrap_bitshift { simd_shl }
238 }
239
240 impl Shr::shr {
241 wrap_bitshift {
242 simd_shr
245 }
246 }
247}
248
249for_base_ops! {
252 T = (f32, f64);
253 type Lhs = Simd<T, N>;
254 type Rhs = Simd<T, N>;
255 type Output = Self;
256
257 impl Add::add {
258 unsafe_base { simd_add }
259 }
260
261 impl Mul::mul {
262 unsafe_base { simd_mul }
263 }
264
265 impl Sub::sub {
266 unsafe_base { simd_sub }
267 }
268
269 impl Div::div {
270 unsafe_base { simd_div }
271 }
272
273 impl Rem::rem {
274 unsafe_base { simd_rem }
275 }
276}