Skip to content

Commit 72cc10d

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

File tree

9 files changed

+142
-45
lines changed

9 files changed

+142
-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: 117 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,113 @@ 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+
#[inline]
234+
pub fn get(self, idx: usize) -> T {
235+
assert!(idx < N);
236+
// SAFETY: just checked in-bounds with the assert
237+
unsafe { self.get_inner(idx) }
238+
}
239+
240+
/// Gets the value at `idx` to `val`, or `None` if `idx >= N`.
241+
///
242+
/// This typically faster than reading via `as_array`.
243+
#[inline]
244+
pub fn get_checked(self, idx: usize) -> Option<T> {
245+
if idx < N {
246+
// SAFETY: just checked in-bounds with the if
247+
Some(unsafe { self.get_inner(idx) })
248+
} else {
249+
None
250+
}
251+
}
252+
253+
/// Gets the value at `idx` to `val`.
254+
///
255+
/// This typically faster than reading via `as_array`.
256+
///
257+
/// # Safety
258+
/// `idx` must be in-bounds (`idx < N`)
259+
#[inline]
260+
pub unsafe fn get_unchecked(self, idx: usize) -> T {
261+
// SAFETY: our precondition is also that the value is in-bounds
262+
unsafe {
263+
core::hint::assert_unchecked(idx < N);
264+
self.get_inner(idx)
265+
}
266+
}
267+
268+
/// # Safety
269+
/// `idx` must be in-bounds (`idx < N`)
270+
#[inline]
271+
#[must_use = "This returns a new vector, rather than updating in-place"]
272+
unsafe fn set_inner(self, idx: usize, val: T) -> Self {
273+
// SAFETY: our precondition is also that the value is in-bounds
274+
// and this type is a simd type of the correct element type.
275+
unsafe { core::intrinsics::simd::simd_insert_dyn(self, idx as u32, val) }
276+
}
277+
278+
/// Sets the value at `idx` to `val`, returning the updated vector.
279+
///
280+
/// This typically faster than updating via `as_mut_array`.
281+
///
282+
/// # Panics
283+
///
284+
/// If `idx` is out of bounds (aka if `idx >= N`).
285+
#[inline]
286+
#[must_use = "This returns a new vector, rather than updating in-place"]
287+
pub fn set(self, idx: usize, val: T) -> Self {
288+
assert!(idx < N);
289+
// SAFETY: just checked in-bounds with the assert
290+
unsafe { self.set_inner(idx, val) }
291+
}
292+
293+
/// Sets the value at `idx` to `val` and returns the updated vector
294+
/// or returns `None` if `idx >= N`.
295+
///
296+
/// This typically faster than updating via `as_mut_array`.
297+
#[inline]
298+
#[must_use = "This returns a new vector, rather than updating in-place"]
299+
pub fn set_checked(self, idx: usize, val: T) -> Option<Self> {
300+
if idx < N {
301+
// SAFETY: just checked in-bounds with the if
302+
Some(unsafe { self.set_inner(idx, val) })
303+
} else {
304+
None
305+
}
306+
}
307+
308+
/// Sets the value at `idx` to `val`, returning the updated vector.
309+
///
310+
/// This typically faster than updating via `as_mut_array`.
311+
///
312+
/// # Safety
313+
/// `idx` must be in-bounds (`idx < N`)
314+
#[inline]
315+
#[must_use = "This returns a new vector, rather than updating in-place"]
316+
pub unsafe fn set_unchecked(self, idx: usize, val: T) -> Self {
317+
// SAFETY: our precondition is also that the value is in-bounds
318+
unsafe {
319+
core::hint::assert_unchecked(idx < N);
320+
self.set_inner(idx, val)
321+
}
322+
}
323+
207324
/// Loads a vector from an array of `T`.
208325
///
209326
/// 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)