Skip to content

Commit 128b6f5

Browse files
Add SimdArray::gather_{or,or_default,select}
1 parent 2f99cc8 commit 128b6f5

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

crates/core_simd/src/array.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
use crate::intrinsics;
12
use crate::masks::*;
3+
use crate::vector::ptr::SimdConstPtr;
24
use crate::vector::*;
35

46
/// A representation of a vector as an "array" with indices, implementing
@@ -17,6 +19,70 @@ where
1719
/// Generates a SIMD vector with the same value in every lane.
1820
#[must_use]
1921
fn splat(val: Self::Scalar) -> Self;
22+
23+
/// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
24+
/// If an index is out of bounds, that lane instead selects the value from the "or" vector.
25+
/// ```
26+
/// # use core_simd::*;
27+
/// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
28+
/// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 5]);
29+
/// let alt = SimdI32::from_array([-5, -4, -3, -2]);
30+
///
31+
/// let result = SimdI32::<4>::gather_or(&vec, idxs, alt); // Note the lane that is out-of-bounds.
32+
/// assert_eq!(result, SimdI32::from_array([-5, 13, 10, 15]));
33+
/// ```
34+
#[must_use]
35+
#[inline]
36+
fn gather_or(slice: &[Self::Scalar], idxs: SimdUsize<LANES>, or: Self) -> Self {
37+
Self::gather_select(slice, MaskSize::splat(true), idxs, or)
38+
}
39+
40+
/// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
41+
/// Out-of-bounds indices instead use the default value for that lane (0).
42+
/// ```
43+
/// # use core_simd::*;
44+
/// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
45+
/// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 5]);
46+
///
47+
/// let result = SimdI32::<4>::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds.
48+
/// assert_eq!(result, SimdI32::from_array([0, 13, 10, 15]));
49+
/// ```
50+
#[must_use]
51+
#[inline]
52+
fn gather_or_default(slice: &[Self::Scalar], idxs: SimdUsize<LANES>) -> Self
53+
where
54+
Self::Scalar: Default,
55+
{
56+
Self::gather_or(slice, idxs, Self::splat(Self::Scalar::default()))
57+
}
58+
59+
/// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
60+
/// Out-of-bounds or masked indices instead select the value from the "or" vector.
61+
/// ```
62+
/// # use core_simd::*;
63+
/// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
64+
/// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 5]);
65+
/// let alt = SimdI32::from_array([-5, -4, -3, -2]);
66+
/// let mask = MaskSize::from_array([true, true, true, false]); // Note the mask of the last lane.
67+
///
68+
/// let result = SimdI32::<4>::gather_select(&vec, mask, idxs, alt); // Note the lane that is out-of-bounds.
69+
/// assert_eq!(result, SimdI32::from_array([-5, 13, 10, -2]));
70+
/// ```
71+
#[must_use]
72+
#[inline]
73+
fn gather_select(
74+
slice: &[Self::Scalar],
75+
mask: MaskSize<LANES>,
76+
idxs: SimdUsize<LANES>,
77+
or: Self,
78+
) -> Self {
79+
let mask = (mask & idxs.lanes_lt(SimdUsize::splat(slice.len()))).to_int();
80+
let base_ptr = SimdConstPtr::splat(slice.as_ptr());
81+
// Ferris forgive me, I have done pointer arithmetic here.
82+
let ptrs = base_ptr.wrapping_add(idxs);
83+
// SAFETY: The ptrs have been bounds-masked to prevent memory-unsafe reads insha'allah
84+
unsafe { intrinsics::simd_gather(or, ptrs, mask) }
85+
}
2086
}
2187

2288
macro_rules! impl_simdarray_for {

crates/core_simd/src/intrinsics.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ extern "platform-intrinsic" {
4545

4646
/// fabs
4747
pub(crate) fn simd_fabs<T>(x: T) -> T;
48-
48+
4949
/// fsqrt
5050
pub(crate) fn simd_fsqrt<T>(x: T) -> T;
5151

@@ -63,6 +63,8 @@ extern "platform-intrinsic" {
6363
pub(crate) fn simd_shuffle16<T, U>(x: T, y: T, idx: [u32; 16]) -> U;
6464
pub(crate) fn simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U;
6565

66+
pub(crate) fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;
67+
6668
// {s,u}add.sat
6769
pub(crate) fn simd_saturating_add<T>(x: T, y: T) -> T;
6870

0 commit comments

Comments
 (0)