diff --git a/crates/core_simd/src/lane_count.rs b/crates/core_simd/src/lane_count.rs index 3b316f12b3e..63723e2ec13 100644 --- a/crates/core_simd/src/lane_count.rs +++ b/crates/core_simd/src/lane_count.rs @@ -3,7 +3,7 @@ mod sealed { } use sealed::Sealed; -/// A type representing a vector lane count. +/// Specifies the number of lanes in a SIMD vector as a type. pub struct LaneCount; impl LaneCount { @@ -11,7 +11,11 @@ impl LaneCount { pub const BITMASK_LEN: usize = (LANES + 7) / 8; } -/// Helper trait for vector lane counts. +/// Statically guarantees that a lane count is marked as supported. +/// +/// This trait is *sealed*: the list of implementors below is total. +/// Users do not have the ability to mark additional `LaneCount` values as supported. +/// Only SIMD vectors with supported lane counts are constructable. pub trait SupportedLaneCount: Sealed { #[doc(hidden)] type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>; diff --git a/crates/core_simd/src/reduction.rs b/crates/core_simd/src/reduction.rs index 3177fd167fc..642ab319cdd 100644 --- a/crates/core_simd/src/reduction.rs +++ b/crates/core_simd/src/reduction.rs @@ -12,13 +12,41 @@ macro_rules! impl_integer_reductions { LaneCount: SupportedLaneCount, { /// Reducing wrapping add. Returns the sum of the lanes of the vector, with wrapping addition. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")] + #[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")] + /// assert_eq!(v.reduce_sum(), 10); + /// + /// // SIMD integer addition is always wrapping + #[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([", stringify!($scalar) ,"::MAX, 1, 0, 0]);")] + #[doc = concat!("assert_eq!(v.reduce_sum(), ", stringify!($scalar), "::MIN);")] + /// ``` #[inline] pub fn reduce_sum(self) -> $scalar { // Safety: `self` is an integer vector unsafe { simd_reduce_add_ordered(self, 0) } } - /// Reducing wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication. + /// Reducing wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")] + #[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")] + /// assert_eq!(v.reduce_product(), 24); + /// + /// // SIMD integer multiplication is always wrapping + #[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([", stringify!($scalar) ,"::MAX, 2, 1, 1]);")] + #[doc = concat!("assert!(v.reduce_product() < ", stringify!($scalar), "::MAX);")] + /// ``` #[inline] pub fn reduce_product(self) -> $scalar { // Safety: `self` is an integer vector @@ -26,6 +54,16 @@ macro_rules! impl_integer_reductions { } /// Reducing maximum. Returns the maximum lane in the vector. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")] + #[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")] + /// assert_eq!(v.reduce_max(), 4); + /// ``` #[inline] pub fn reduce_max(self) -> $scalar { // Safety: `self` is an integer vector @@ -33,6 +71,16 @@ macro_rules! impl_integer_reductions { } /// Reducing minimum. Returns the minimum lane in the vector. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")] + #[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")] + /// assert_eq!(v.reduce_min(), 1); + /// ``` #[inline] pub fn reduce_min(self) -> $scalar { // Safety: `self` is an integer vector @@ -61,6 +109,16 @@ macro_rules! impl_float_reductions { { /// Reducing add. Returns the sum of the lanes of the vector. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")] + #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., 2.]);")] + /// assert_eq!(v.reduce_sum(), 3.); + /// ``` #[inline] pub fn reduce_sum(self) -> $scalar { // LLVM sum is inaccurate on i586 @@ -73,6 +131,16 @@ macro_rules! impl_float_reductions { } /// Reducing multiply. Returns the product of the lanes of the vector. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")] + #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([3., 4.]);")] + /// assert_eq!(v.reduce_product(), 12.); + /// ``` #[inline] pub fn reduce_product(self) -> $scalar { // LLVM product is inaccurate on i586 @@ -87,7 +155,30 @@ macro_rules! impl_float_reductions { /// Reducing maximum. Returns the maximum lane in the vector. /// /// Returns values based on equality, so a vector containing both `0.` and `-0.` may - /// return either. This function will not return `NaN` unless all lanes are `NaN`. + /// return either. + /// + /// This function will not return `NaN` unless all lanes are `NaN`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")] + #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., 2.]);")] + /// assert_eq!(v.reduce_max(), 2.); + /// + /// // NaN values are skipped... + #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., ", stringify!($scalar), "::NAN]);")] + /// assert_eq!(v.reduce_max(), 1.); + /// + /// // ...unless all values are NaN + #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([", + stringify!($scalar), "::NAN, ", + stringify!($scalar), "::NAN]);" + )] + /// assert!(v.reduce_max().is_nan()); + /// ``` #[inline] pub fn reduce_max(self) -> $scalar { // Safety: `self` is a float vector @@ -97,7 +188,30 @@ macro_rules! impl_float_reductions { /// Reducing minimum. Returns the minimum lane in the vector. /// /// Returns values based on equality, so a vector containing both `0.` and `-0.` may - /// return either. This function will not return `NaN` unless all lanes are `NaN`. + /// return either. + /// + /// This function will not return `NaN` unless all lanes are `NaN`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::Simd; + #[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")] + #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([3., 7.]);")] + /// assert_eq!(v.reduce_min(), 3.); + /// + /// // NaN values are skipped... + #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., ", stringify!($scalar), "::NAN]);")] + /// assert_eq!(v.reduce_min(), 1.); + /// + /// // ...unless all values are NaN + #[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([", + stringify!($scalar), "::NAN, ", + stringify!($scalar), "::NAN]);" + )] + /// assert!(v.reduce_min().is_nan()); + /// ``` #[inline] pub fn reduce_min(self) -> $scalar { // Safety: `self` is a float vector diff --git a/crates/core_simd/src/swizzle.rs b/crates/core_simd/src/swizzle.rs index ef47c4f3a4c..22999d24950 100644 --- a/crates/core_simd/src/swizzle.rs +++ b/crates/core_simd/src/swizzle.rs @@ -1,44 +1,46 @@ use crate::simd::intrinsics; use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount}; -/// Constructs a new vector by selecting values from the lanes of the source vector or vectors to use. +/// Constructs a new SIMD vector by copying elements from selected lanes in other vectors. /// -/// When swizzling one vector, the indices of the result vector are indicated by a `const` array -/// of `usize`, like [`Swizzle`]. -/// When swizzling two vectors, the indices are indicated by a `const` array of [`Which`], like -/// [`Swizzle2`]. +/// When swizzling one vector, lanes are selected by a `const` array of `usize`, +/// like [`Swizzle`]. +/// +/// When swizzling two vectors, lanes are selected by a `const` array of [`Which`], +/// like [`Swizzle2`]. /// /// # Examples -/// ## One source vector +/// +/// With a single SIMD vector, the const array specifies lane indices in that vector: /// ``` /// # #![feature(portable_simd)] -/// # use core::simd::{Simd, simd_swizzle}; -/// let v = Simd::::from_array([0., 1., 2., 3.]); +/// # use core::simd::{u32x2, u32x4, simd_swizzle}; +/// let v = u32x4::from_array([10, 11, 12, 13]); /// /// // Keeping the same size -/// let r = simd_swizzle!(v, [3, 0, 1, 2]); -/// assert_eq!(r.to_array(), [3., 0., 1., 2.]); +/// let r: u32x4 = simd_swizzle!(v, [3, 0, 1, 2]); +/// assert_eq!(r.to_array(), [13, 10, 11, 12]); /// /// // Changing the number of lanes -/// let r = simd_swizzle!(v, [3, 1]); -/// assert_eq!(r.to_array(), [3., 1.]); +/// let r: u32x2 = simd_swizzle!(v, [3, 1]); +/// assert_eq!(r.to_array(), [13, 11]); /// ``` /// -/// ## Two source vectors +/// With two input SIMD vectors, the const array uses `Which` to specify the source of each index: /// ``` /// # #![feature(portable_simd)] -/// # use core::simd::{Simd, simd_swizzle, Which}; -/// use Which::*; -/// let a = Simd::::from_array([0., 1., 2., 3.]); -/// let b = Simd::::from_array([4., 5., 6., 7.]); +/// # use core::simd::{u32x2, u32x4, simd_swizzle, Which}; +/// use Which::{First, Second}; +/// let a = u32x4::from_array([0, 1, 2, 3]); +/// let b = u32x4::from_array([4, 5, 6, 7]); /// /// // Keeping the same size -/// let r = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]); -/// assert_eq!(r.to_array(), [0., 1., 6., 7.]); +/// let r: u32x4 = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]); +/// assert_eq!(r.to_array(), [0, 1, 6, 7]); /// /// // Changing the number of lanes -/// let r = simd_swizzle!(a, b, [First(0), Second(0)]); -/// assert_eq!(r.to_array(), [0., 4.]); +/// let r: u32x2 = simd_swizzle!(a, b, [First(0), Second(0)]); +/// assert_eq!(r.to_array(), [0, 4]); /// ``` #[allow(unused_macros)] pub macro simd_swizzle { @@ -68,12 +70,14 @@ pub macro simd_swizzle { } } -/// An index into one of two vectors. +/// Specifies a lane index into one of two SIMD vectors. +/// +/// This is an input type for [Swizzle2] and helper macros like [simd_swizzle]. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Which { - /// Indexes the first vector. + /// Index of a lane in the first input SIMD vector. First(usize), - /// Indexes the second vector. + /// Index of a lane in the second input SIMD vector. Second(usize), } diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs index 13e35ecfa49..c2a0ffbd051 100644 --- a/crates/core_simd/src/vector.rs +++ b/crates/core_simd/src/vector.rs @@ -99,17 +99,44 @@ where /// Number of lanes in this vector. pub const LANES: usize = LANES; - /// Get the number of lanes in this vector. + /// Returns the number of lanes in this SIMD vector. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::u32x4; + /// let v = u32x4::splat(0); + /// assert_eq!(v.lanes(), 4); + /// ``` pub const fn lanes(&self) -> usize { LANES } - /// Construct a SIMD vector by setting all lanes to the given value. + /// Constructs a new SIMD vector with all lanes set to the given value. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::u32x4; + /// let v = u32x4::splat(8); + /// assert_eq!(v.as_array(), &[8, 8, 8, 8]); + /// ``` pub const fn splat(value: T) -> Self { Self([value; LANES]) } /// Returns an array reference containing the entire SIMD vector. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::{Simd, u64x4}; + /// let v: u64x4 = Simd::from_array([0, 1, 2, 3]); + /// assert_eq!(v.as_array(), &[0, 1, 2, 3]); + /// ``` pub const fn as_array(&self) -> &[T; LANES] { &self.0 } @@ -129,9 +156,21 @@ where self.0 } - /// Converts a slice to a SIMD vector containing `slice[..LANES]` + /// Converts a slice to a SIMD vector containing `slice[..LANES]`. + /// /// # Panics - /// `from_slice` will panic if the slice's `len` is less than the vector's `Simd::LANES`. + /// + /// Panics if the slice's length is less than the vector's `Simd::LANES`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(portable_simd)] + /// # use core::simd::{Simd, u32x4}; + /// let source = vec![1, 2, 3, 4, 5, 6]; + /// let v = u32x4::from_slice(&source); + /// assert_eq!(v.as_array(), &[1, 2, 3, 4]); + /// ``` #[must_use] pub const fn from_slice(slice: &[T]) -> Self { assert!( @@ -148,6 +187,7 @@ where } /// Performs lanewise conversion of a SIMD vector's elements to another SIMD-valid type. + /// /// This follows the semantics of Rust's `as` conversion for casting /// integers to unsigned integers (interpreting as the other type, so `-1` to `MAX`), /// and from floats to integers (truncating, or saturating at the limits) for each lane,