Skip to content

Commit f88957f

Browse files
committed
Remove Simd: Index
1 parent 4215b72 commit f88957f

File tree

9 files changed

+164
-45
lines changed

9 files changed

+164
-45
lines changed

crates/core_simd/examples/nbody.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ mod nbody {
139139
(r[i + 1] * r[i + 1]).reduce_sum(),
140140
]);
141141
let dmags = f64x2::splat(dt) / (d2s * d2s.sqrt());
142-
mag[i] = dmags[0];
143-
mag[i + 1] = dmags[1];
142+
mag[i] = dmags.get(0);
143+
mag[i + 1] = dmags.get(1);
144144
}
145145

146146
let mut i = 0;

crates/core_simd/src/masks.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ where
250250
#[must_use = "method returns a new bool and does not mutate the original value"]
251251
#[track_caller]
252252
pub fn test(&self, index: usize) -> bool {
253-
T::eq(self.0[index], T::TRUE)
253+
T::eq(self.0.get(index), T::TRUE)
254254
}
255255

256256
/// Sets the value of the specified element.
@@ -261,7 +261,9 @@ where
261261
pub unsafe fn set_unchecked(&mut self, index: usize, value: bool) {
262262
// Safety: the caller must confirm this invariant
263263
unsafe {
264-
*self.0.as_mut_array().get_unchecked_mut(index) = if value { T::TRUE } else { T::FALSE }
264+
self.0 = self
265+
.0
266+
.set_unchecked(index, if value { T::TRUE } else { T::FALSE });
265267
}
266268
}
267269

@@ -272,7 +274,7 @@ where
272274
#[inline]
273275
#[track_caller]
274276
pub fn set(&mut self, index: usize, value: bool) {
275-
self.0[index] = if value { T::TRUE } else { T::FALSE }
277+
self.0 = self.0.set(index, if value { T::TRUE } else { T::FALSE });
276278
}
277279

278280
/// Returns true if any element is set, or false otherwise.

crates/core_simd/src/ops.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,6 @@ mod deref;
99
mod shift_scalar;
1010
mod unary;
1111

12-
impl<I, T, const N: usize> core::ops::Index<I> for Simd<T, N>
13-
where
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-
24-
impl<I, T, const N: usize> core::ops::IndexMut<I> for Simd<T, N>
25-
where
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-
3512
macro_rules! unsafe_base {
3613
($lhs:ident, $rhs:ident, {$simd_call:ident}, $($_:tt)*) => {
3714
// Safety: $lhs and $rhs are vectors
@@ -101,7 +78,8 @@ macro_rules! int_divrem_guard {
10178
{
10279
let mut out = Simd::splat(0 as _);
10380
for i in 0..Self::LEN {
104-
out[i] = $lhs[i] $op rhs[i];
81+
let val = $lhs.get(i) $op rhs.get(i);
82+
out = out.set(i, val);
10583
}
10684
out
10785
}

crates/core_simd/src/select.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ where
8989
where
9090
T: SimdElement,
9191
{
92-
let default = true_values[0];
92+
let default = true_values.get(0);
9393
let true_values = true_values.resize::<M>(default);
9494
let false_values = false_values.resize::<M>(default);
9595

crates/core_simd/src/simd/num/float.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -269,19 +269,19 @@ macro_rules! impl_trait {
269269
unsafe { core::intrinsics::simd::simd_as(self) }
270270
} else if N < 4 {
271271
let x = self.resize::<4>(Default::default()).cast();
272-
x.resize::<N>(x[0])
272+
x.resize::<N>(x.get(0))
273273
} else if N < 8 {
274274
let x = self.resize::<8>(Default::default()).cast();
275-
x.resize::<N>(x[0])
275+
x.resize::<N>(x.get(0))
276276
} else if N < 16 {
277277
let x = self.resize::<16>(Default::default()).cast();
278-
x.resize::<N>(x[0])
278+
x.resize::<N>(x.get(0))
279279
} else if N < 32 {
280280
let x = self.resize::<32>(Default::default()).cast();
281-
x.resize::<N>(x[0])
281+
x.resize::<N>(x.get(0))
282282
} else {
283283
let x = self.resize::<64>(Default::default()).cast();
284-
x.resize::<N>(x[0])
284+
x.resize::<N>(x.get(0))
285285
}
286286
}
287287

crates/core_simd/src/swizzle_dyn.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,9 @@ impl<const N: usize> Simd<u8, N> {
9393
_ => {
9494
let mut array = [0; N];
9595
for (i, k) in idxs.to_array().into_iter().enumerate() {
96-
if (k as usize) < N {
97-
array[i] = self[k as usize];
98-
};
96+
if let Some(val) = self.get_checked(usize::from(k)) {
97+
array[i] = val;
98+
}
9999
}
100100
array.into()
101101
}

crates/core_simd/src/vector.rs

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ where
173173

174174
/// Returns an array reference containing the entire SIMD vector.
175175
///
176+
/// While this exists and *can* be used to read an arbitrary element from a
177+
/// vector, like `v.as_array()[i]`, that's discouraged because it forces the
178+
/// vector to memory which tends to perform poorly. Instead, use
179+
/// [`Self::get`]. (This is also why `Index` is not implemented.)
180+
///
176181
/// # Examples
177182
///
178183
/// ```
@@ -193,6 +198,11 @@ where
193198
}
194199

195200
/// Returns a mutable array reference containing the entire SIMD vector.
201+
///
202+
/// While this exists and *can* be used to write an arbitrary element into a
203+
/// vector, like `v.as_mut_array()[i] = x`, that's discouraged because it
204+
/// forces the vector to memory which tends to perform poorly. Instead, use
205+
/// [`Self::set`]. (This is also why `IndexMut` is not implemented.)
196206
#[inline]
197207
pub const fn as_mut_array(&mut self) -> &mut [T; N] {
198208
// SAFETY: `Simd<T, N>` is just an overaligned `[T; N]` with
@@ -204,6 +214,135 @@ where
204214
unsafe { &mut *(self as *mut Self as *mut [T; N]) }
205215
}
206216

217+
/// # Safety
218+
/// `idx` must be in-bounds (`idx < N`)
219+
#[inline]
220+
unsafe fn get_inner(self, idx: usize) -> T {
221+
// SAFETY: our precondition is also that the value is in-bounds
222+
// and this type is a simd type of the correct element type.
223+
unsafe { core::intrinsics::simd::simd_extract_dyn(self, idx as u32) }
224+
}
225+
226+
/// Gets the value at `idx` to `val`.
227+
///
228+
/// This typically faster than reading via `as_array`.
229+
///
230+
/// # Panics
231+
///
232+
/// If `idx` is out of bounds (aka if `idx >= N`).
233+
///
234+
/// # Examples
235+
///
236+
/// ```
237+
/// # #![feature(portable_simd)]
238+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
239+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
240+
/// # use simd::{Simd, u64x4};
241+
/// let v: u64x4 = Simd::from_array([3, 5, 7, 11]);
242+
/// assert_eq!(v.get(2), 7);
243+
/// ```
244+
#[inline]
245+
pub fn get(self, idx: usize) -> T {
246+
assert!(idx < N);
247+
// SAFETY: just checked in-bounds with the assert
248+
unsafe { self.get_inner(idx) }
249+
}
250+
251+
/// Gets the value at `idx` to `val`, or `None` if `idx >= N`.
252+
///
253+
/// This typically faster than reading via `as_array`.
254+
#[inline]
255+
pub fn get_checked(self, idx: usize) -> Option<T> {
256+
if idx < N {
257+
// SAFETY: just checked in-bounds with the if
258+
Some(unsafe { self.get_inner(idx) })
259+
} else {
260+
None
261+
}
262+
}
263+
264+
/// Gets the value at `idx` to `val`.
265+
///
266+
/// This typically faster than reading via `as_array`.
267+
///
268+
/// # Safety
269+
/// `idx` must be in-bounds (`idx < N`)
270+
#[inline]
271+
pub unsafe fn get_unchecked(self, idx: usize) -> T {
272+
// SAFETY: our precondition is also that the value is in-bounds
273+
unsafe {
274+
core::hint::assert_unchecked(idx < N);
275+
self.get_inner(idx)
276+
}
277+
}
278+
279+
/// # Safety
280+
/// `idx` must be in-bounds (`idx < N`)
281+
#[inline]
282+
#[must_use = "This returns a new vector, rather than updating in-place"]
283+
unsafe fn set_inner(self, idx: usize, val: T) -> Self {
284+
// SAFETY: our precondition is also that the value is in-bounds
285+
// and this type is a simd type of the correct element type.
286+
unsafe { core::intrinsics::simd::simd_insert_dyn(self, idx as u32, val) }
287+
}
288+
289+
/// Sets the value at `idx` to `val`, returning the updated vector.
290+
///
291+
/// This typically faster than updating via `as_mut_array`.
292+
///
293+
/// # Panics
294+
///
295+
/// If `idx` is out of bounds (aka if `idx >= N`).
296+
///
297+
/// # Examples
298+
///
299+
/// ```
300+
/// # #![feature(portable_simd)]
301+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
302+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
303+
/// # use simd::{Simd, u64x4};
304+
/// let v: u64x4 = Simd::from_array([3, 5, 7, 11]);
305+
/// assert_eq!(v.set(2, 99).as_array(), &[3, 5, 99, 11]);
306+
/// ```
307+
#[inline]
308+
#[must_use = "This returns a new vector, rather than updating in-place"]
309+
pub fn set(self, idx: usize, val: T) -> Self {
310+
assert!(idx < N);
311+
// SAFETY: just checked in-bounds with the assert
312+
unsafe { self.set_inner(idx, val) }
313+
}
314+
315+
/// Sets the value at `idx` to `val` and returns the updated vector
316+
/// or returns `None` if `idx >= N`.
317+
///
318+
/// This typically faster than updating via `as_mut_array`.
319+
#[inline]
320+
#[must_use = "This returns a new vector, rather than updating in-place"]
321+
pub fn set_checked(self, idx: usize, val: T) -> Option<Self> {
322+
if idx < N {
323+
// SAFETY: just checked in-bounds with the if
324+
Some(unsafe { self.set_inner(idx, val) })
325+
} else {
326+
None
327+
}
328+
}
329+
330+
/// Sets the value at `idx` to `val`, returning the updated vector.
331+
///
332+
/// This typically faster than updating via `as_mut_array`.
333+
///
334+
/// # Safety
335+
/// `idx` must be in-bounds (`idx < N`)
336+
#[inline]
337+
#[must_use = "This returns a new vector, rather than updating in-place"]
338+
pub unsafe fn set_unchecked(self, idx: usize, val: T) -> Self {
339+
// SAFETY: our precondition is also that the value is in-bounds
340+
unsafe {
341+
core::hint::assert_unchecked(idx < N);
342+
self.set_inner(idx, val)
343+
}
344+
}
345+
207346
/// Loads a vector from an array of `T`.
208347
///
209348
/// This function is necessary since `repr(simd)` has padding for non-power-of-2 vectors (at the time of writing).

crates/core_simd/tests/ops_macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ macro_rules! impl_signed_tests {
375375
fn div_by_one_zero_panics<const LANES: usize>() {
376376
let a = Vector::<LANES>::splat(42);
377377
let mut b = Vector::<LANES>::splat(21);
378-
b[0] = 0 as _;
378+
b = b.set(0, 0 as _);
379379
let _ = a / b;
380380
}
381381

crates/core_simd/tests/to_bytes.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ fn byte_convert() {
88
let ne_bytes = int.to_ne_bytes();
99
let be_bytes = int.to_be_bytes();
1010
let le_bytes = int.to_le_bytes();
11-
assert_eq!(int[0].to_ne_bytes(), ne_bytes[..4]);
12-
assert_eq!(int[1].to_ne_bytes(), ne_bytes[4..]);
13-
assert_eq!(int[0].to_be_bytes(), be_bytes[..4]);
14-
assert_eq!(int[1].to_be_bytes(), be_bytes[4..]);
15-
assert_eq!(int[0].to_le_bytes(), le_bytes[..4]);
16-
assert_eq!(int[1].to_le_bytes(), le_bytes[4..]);
11+
assert_eq!(int.get(0).to_ne_bytes(), ne_bytes.as_array()[..4]);
12+
assert_eq!(int.get(1).to_ne_bytes(), ne_bytes.as_array()[4..]);
13+
assert_eq!(int.get(0).to_be_bytes(), be_bytes.as_array()[..4]);
14+
assert_eq!(int.get(1).to_be_bytes(), be_bytes.as_array()[4..]);
15+
assert_eq!(int.get(0).to_le_bytes(), le_bytes.as_array()[..4]);
16+
assert_eq!(int.get(1).to_le_bytes(), le_bytes.as_array()[4..]);
1717
assert_eq!(Simd::<u32, 2>::from_ne_bytes(ne_bytes), int);
1818
assert_eq!(Simd::<u32, 2>::from_be_bytes(be_bytes), int);
1919
assert_eq!(Simd::<u32, 2>::from_le_bytes(le_bytes), int);

0 commit comments

Comments
 (0)