Skip to content

Commit

Permalink
Add SimdArray::{gather, gather_or}
Browse files Browse the repository at this point in the history
  • Loading branch information
workingjubilee committed Jun 15, 2021
1 parent 048b547 commit 2e13093
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 1 deletion.
45 changes: 45 additions & 0 deletions crates/core_simd/src/array.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use crate::intrinsics;
use crate::masks::*;
use crate::vector::ptr::SimdConst;
use crate::vector::*;

/// A representation of a vector as an "array" with indices,
Expand All @@ -17,6 +19,49 @@ where
/// Generates a SIMD vector with the same value in every lane.
#[must_use]
fn splat(val: Self::Scalar) -> Self;

/// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
/// Out-of-bounds indices instead use the default value (zero, generally).
/// ```
/// # use core_simd::*;
/// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
/// let indices = SimdUsize::<4>::from_array([9, 3, 0, 5]);
///
/// let result = SimdI32::<4>::gather(&vec, indices);
/// assert!(result == SimdI32::from_array([0, 13, 10, 15]));
/// ```
#[must_use]
#[inline]
fn gather(slice: &[Self::Scalar], idxs: SimdUsize<LANES>) -> Self
where
Self::Scalar: Default,
{
Self::gather_or(slice, idxs, Self::splat(Self::Scalar::default()))
}

/// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
/// If an index is out of bounds, it instead selects from the values in the "or" vector.
/// ```
/// # use core_simd::*;
/// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
/// let indices = SimdUsize::<4>::from_array([9, 3, 0, 5]);
/// let alt = SimdI32::from_array([-5, -4, -3, -2]);
///
/// let result = SimdI32::<4>::gather_or(&vec, indices, alt);
/// assert!(result == SimdI32::from_array([-5, 13, 10, 15]), "oh no, got {:?}", result);
/// ```
#[must_use]
#[inline]
fn gather_or(slice: &[Self::Scalar], idxs: SimdUsize<LANES>, or: Self) -> Self {
// IMPORTANT: We MUST construct our gather mask before we derive a pointer!
let mask = idxs.lanes_lt(SimdUsize::splat(slice.len())).to_int();
// IMPORTANT: We MUST obtain a pointer via as_ptr or an equivalent method!
let base_ptr = SimdConst::splat(slice.as_ptr());
// Ferris forgive me, I have done pointer arithmetic here.
let ptrs = base_ptr.wrapping_add(idxs);
// SAFETY: We bounds-mask the pointers so nothing fishy can emerge from this insha'allah
unsafe { intrinsics::simd_gather(or, ptrs, mask) }
}
}

macro_rules! impl_simdarray_for {
Expand Down
4 changes: 3 additions & 1 deletion crates/core_simd/src/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ extern "platform-intrinsic" {

/// fabs
pub(crate) fn simd_fabs<T>(x: T) -> T;

/// fsqrt
pub(crate) fn simd_fsqrt<T>(x: T) -> T;

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

pub(crate) fn simd_gather<T, U, V>(val: T, ptr: U, mask: V) -> T;

// {s,u}add.sat
pub(crate) fn simd_saturating_add<T>(x: T, y: T) -> T;

Expand Down

0 comments on commit 2e13093

Please sign in to comment.