diff --git a/crates/core_simd/src/intrinsics.rs b/crates/core_simd/src/intrinsics.rs index 51689cd97be..4ea38376348 100644 --- a/crates/core_simd/src/intrinsics.rs +++ b/crates/core_simd/src/intrinsics.rs @@ -52,4 +52,12 @@ extern "platform-intrinsic" { pub(crate) fn simd_le(x: T, y: T) -> U; pub(crate) fn simd_gt(x: T, y: T) -> U; pub(crate) fn simd_ge(x: T, y: T) -> U; + + // shufflevector + pub(crate) fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + pub(crate) fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; + pub(crate) fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; + pub(crate) fn simd_shuffle16(x: T, y: T, idx: [u32; 16]) -> U; + pub(crate) fn simd_shuffle32(x: T, y: T, idx: [u32; 32]) -> U; + pub(crate) fn simd_shuffle64(x: T, y: T, idx: [u32; 64]) -> U; } diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs index 6c8da3a4e7f..62489e4fbd5 100644 --- a/crates/core_simd/src/lib.rs +++ b/crates/core_simd/src/lib.rs @@ -1,10 +1,19 @@ #![no_std] -#![feature(repr_simd, platform_intrinsics, link_llvm_intrinsics, simd_ffi)] +#![allow(incomplete_features)] +#![feature( + repr_simd, + platform_intrinsics, + link_llvm_intrinsics, + simd_ffi, + const_generics +)] #![warn(missing_docs)] //! Portable SIMD module. #[macro_use] mod macros; +#[macro_use] +mod permute; mod fmt; mod intrinsics; diff --git a/crates/core_simd/src/macros.rs b/crates/core_simd/src/macros.rs index 7e4d8514249..0abafe71f50 100644 --- a/crates/core_simd/src/macros.rs +++ b/crates/core_simd/src/macros.rs @@ -148,6 +148,8 @@ macro_rules! impl_vector { Self::splat(value) } } + + impl_shuffle_2pow_lanes!{ $name } } } diff --git a/crates/core_simd/src/permute.rs b/crates/core_simd/src/permute.rs new file mode 100644 index 00000000000..05a78c3764b --- /dev/null +++ b/crates/core_simd/src/permute.rs @@ -0,0 +1,29 @@ +macro_rules! impl_shuffle_lane { + { $name:ident, $fn:ident, $n:literal } => { + impl $name<$n> { + /// A const SIMD shuffle that takes 2 SIMD vectors and produces another vector, using + /// the indices in the const parameter. The first or "self" vector will have its lanes + /// indexed from 0, and the second vector will have its first lane indexed at $n. + /// Indices must be in-bounds of either vector at compile time. + /// + /// Some SIMD shuffle instructions can be quite slow, so avoiding them by loading data + /// into the desired patterns in advance is preferred, but shuffles are still faster + /// than storing and reloading from memory. + #[inline] + pub fn shuffle(self, second: Self) -> Self { + unsafe { crate::intrinsics::$fn(self, second, IDX) } + } + } + } +} + +macro_rules! impl_shuffle_2pow_lanes { + { $name:ident } => { + impl_shuffle_lane!{ $name, simd_shuffle2, 2 } + impl_shuffle_lane!{ $name, simd_shuffle4, 4 } + impl_shuffle_lane!{ $name, simd_shuffle8, 8 } + impl_shuffle_lane!{ $name, simd_shuffle16, 16 } + impl_shuffle_lane!{ $name, simd_shuffle32, 32 } + impl_shuffle_lane!{ $name, simd_shuffle64, 64 } + } +} diff --git a/crates/core_simd/tests/permute.rs b/crates/core_simd/tests/permute.rs new file mode 100644 index 00000000000..1c6c391d8d0 --- /dev/null +++ b/crates/core_simd/tests/permute.rs @@ -0,0 +1,15 @@ +use core_simd::SimdU32; + +#[cfg(target_arch = "wasm32")] +use wasm_bindgen_test::*; + +#[cfg(target_arch = "wasm32")] +wasm_bindgen_test_configure!(run_in_browser); + +#[test] +#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] +fn simple_shuffle() { + let a = SimdU32::from_array([2, 4, 1, 9]); + let b = a; + assert_eq!(a.shuffle::<{ [3, 1, 4, 6] }>(b).to_array(), [9, 4, 2, 1]); +}