Skip to content

Commit 9cdcec4

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

File tree

8 files changed

+153
-39
lines changed

8 files changed

+153
-39
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: 0 additions & 23 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

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