Skip to content

Commit fcc5ca0

Browse files
authored
#273: Documentation update for reduce functions, swizzle
Working through giving example documentation to every Simd function. The major change in this patch is using doc macros to generate type-specific examples for each function, using a visually-apparent type constructor. This makes it feel nicer to have twelve separate documentation entries for reduce_product(), for example.
1 parent 7136841 commit fcc5ca0

File tree

4 files changed

+195
-33
lines changed

4 files changed

+195
-33
lines changed

crates/core_simd/src/lane_count.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@ mod sealed {
33
}
44
use sealed::Sealed;
55

6-
/// A type representing a vector lane count.
6+
/// Specifies the number of lanes in a SIMD vector as a type.
77
pub struct LaneCount<const LANES: usize>;
88

99
impl<const LANES: usize> LaneCount<LANES> {
1010
/// The number of bytes in a bitmask with this many lanes.
1111
pub const BITMASK_LEN: usize = (LANES + 7) / 8;
1212
}
1313

14-
/// Helper trait for vector lane counts.
14+
/// Statically guarantees that a lane count is marked as supported.
15+
///
16+
/// This trait is *sealed*: the list of implementors below is total.
17+
/// Users do not have the ability to mark additional `LaneCount<N>` values as supported.
18+
/// Only SIMD vectors with supported lane counts are constructable.
1519
pub trait SupportedLaneCount: Sealed {
1620
#[doc(hidden)]
1721
type BitMask: Copy + Default + AsRef<[u8]> + AsMut<[u8]>;

crates/core_simd/src/reduction.rs

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,75 @@ macro_rules! impl_integer_reductions {
1212
LaneCount<LANES>: SupportedLaneCount,
1313
{
1414
/// Reducing wrapping add. Returns the sum of the lanes of the vector, with wrapping addition.
15+
///
16+
/// # Examples
17+
///
18+
/// ```
19+
/// # #![feature(portable_simd)]
20+
/// # use core::simd::Simd;
21+
#[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")]
22+
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")]
23+
/// assert_eq!(v.reduce_sum(), 10);
24+
///
25+
/// // SIMD integer addition is always wrapping
26+
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([", stringify!($scalar) ,"::MAX, 1, 0, 0]);")]
27+
#[doc = concat!("assert_eq!(v.reduce_sum(), ", stringify!($scalar), "::MIN);")]
28+
/// ```
1529
#[inline]
1630
pub fn reduce_sum(self) -> $scalar {
1731
// Safety: `self` is an integer vector
1832
unsafe { simd_reduce_add_ordered(self, 0) }
1933
}
2034

21-
/// Reducing wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication.
35+
/// Reducing wrapping multiply. Returns the product of the lanes of the vector, with wrapping multiplication.
36+
///
37+
/// # Examples
38+
///
39+
/// ```
40+
/// # #![feature(portable_simd)]
41+
/// # use core::simd::Simd;
42+
#[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")]
43+
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")]
44+
/// assert_eq!(v.reduce_product(), 24);
45+
///
46+
/// // SIMD integer multiplication is always wrapping
47+
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([", stringify!($scalar) ,"::MAX, 2, 1, 1]);")]
48+
#[doc = concat!("assert!(v.reduce_product() < ", stringify!($scalar), "::MAX);")]
49+
/// ```
2250
#[inline]
2351
pub fn reduce_product(self) -> $scalar {
2452
// Safety: `self` is an integer vector
2553
unsafe { simd_reduce_mul_ordered(self, 1) }
2654
}
2755

2856
/// Reducing maximum. Returns the maximum lane in the vector.
57+
///
58+
/// # Examples
59+
///
60+
/// ```
61+
/// # #![feature(portable_simd)]
62+
/// # use core::simd::Simd;
63+
#[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")]
64+
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")]
65+
/// assert_eq!(v.reduce_max(), 4);
66+
/// ```
2967
#[inline]
3068
pub fn reduce_max(self) -> $scalar {
3169
// Safety: `self` is an integer vector
3270
unsafe { simd_reduce_max(self) }
3371
}
3472

3573
/// Reducing minimum. Returns the minimum lane in the vector.
74+
///
75+
/// # Examples
76+
///
77+
/// ```
78+
/// # #![feature(portable_simd)]
79+
/// # use core::simd::Simd;
80+
#[doc = concat!("# use core::simd::", stringify!($scalar), "x4;")]
81+
#[doc = concat!("let v = ", stringify!($scalar), "x4::from_array([1, 2, 3, 4]);")]
82+
/// assert_eq!(v.reduce_min(), 1);
83+
/// ```
3684
#[inline]
3785
pub fn reduce_min(self) -> $scalar {
3886
// Safety: `self` is an integer vector
@@ -61,6 +109,16 @@ macro_rules! impl_float_reductions {
61109
{
62110

63111
/// Reducing add. Returns the sum of the lanes of the vector.
112+
///
113+
/// # Examples
114+
///
115+
/// ```
116+
/// # #![feature(portable_simd)]
117+
/// # use core::simd::Simd;
118+
#[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")]
119+
#[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., 2.]);")]
120+
/// assert_eq!(v.reduce_sum(), 3.);
121+
/// ```
64122
#[inline]
65123
pub fn reduce_sum(self) -> $scalar {
66124
// LLVM sum is inaccurate on i586
@@ -73,6 +131,16 @@ macro_rules! impl_float_reductions {
73131
}
74132

75133
/// Reducing multiply. Returns the product of the lanes of the vector.
134+
///
135+
/// # Examples
136+
///
137+
/// ```
138+
/// # #![feature(portable_simd)]
139+
/// # use core::simd::Simd;
140+
#[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")]
141+
#[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([3., 4.]);")]
142+
/// assert_eq!(v.reduce_product(), 12.);
143+
/// ```
76144
#[inline]
77145
pub fn reduce_product(self) -> $scalar {
78146
// LLVM product is inaccurate on i586
@@ -87,7 +155,30 @@ macro_rules! impl_float_reductions {
87155
/// Reducing maximum. Returns the maximum lane in the vector.
88156
///
89157
/// Returns values based on equality, so a vector containing both `0.` and `-0.` may
90-
/// return either. This function will not return `NaN` unless all lanes are `NaN`.
158+
/// return either.
159+
///
160+
/// This function will not return `NaN` unless all lanes are `NaN`.
161+
///
162+
/// # Examples
163+
///
164+
/// ```
165+
/// # #![feature(portable_simd)]
166+
/// # use core::simd::Simd;
167+
#[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")]
168+
#[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., 2.]);")]
169+
/// assert_eq!(v.reduce_max(), 2.);
170+
///
171+
/// // NaN values are skipped...
172+
#[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., ", stringify!($scalar), "::NAN]);")]
173+
/// assert_eq!(v.reduce_max(), 1.);
174+
///
175+
/// // ...unless all values are NaN
176+
#[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([",
177+
stringify!($scalar), "::NAN, ",
178+
stringify!($scalar), "::NAN]);"
179+
)]
180+
/// assert!(v.reduce_max().is_nan());
181+
/// ```
91182
#[inline]
92183
pub fn reduce_max(self) -> $scalar {
93184
// Safety: `self` is a float vector
@@ -97,7 +188,30 @@ macro_rules! impl_float_reductions {
97188
/// Reducing minimum. Returns the minimum lane in the vector.
98189
///
99190
/// Returns values based on equality, so a vector containing both `0.` and `-0.` may
100-
/// return either. This function will not return `NaN` unless all lanes are `NaN`.
191+
/// return either.
192+
///
193+
/// This function will not return `NaN` unless all lanes are `NaN`.
194+
///
195+
/// # Examples
196+
///
197+
/// ```
198+
/// # #![feature(portable_simd)]
199+
/// # use core::simd::Simd;
200+
#[doc = concat!("# use core::simd::", stringify!($scalar), "x2;")]
201+
#[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([3., 7.]);")]
202+
/// assert_eq!(v.reduce_min(), 3.);
203+
///
204+
/// // NaN values are skipped...
205+
#[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([1., ", stringify!($scalar), "::NAN]);")]
206+
/// assert_eq!(v.reduce_min(), 1.);
207+
///
208+
/// // ...unless all values are NaN
209+
#[doc = concat!("let v = ", stringify!($scalar), "x2::from_array([",
210+
stringify!($scalar), "::NAN, ",
211+
stringify!($scalar), "::NAN]);"
212+
)]
213+
/// assert!(v.reduce_min().is_nan());
214+
/// ```
101215
#[inline]
102216
pub fn reduce_min(self) -> $scalar {
103217
// Safety: `self` is a float vector

crates/core_simd/src/swizzle.rs

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,46 @@
11
use crate::simd::intrinsics;
22
use crate::simd::{LaneCount, Simd, SimdElement, SupportedLaneCount};
33

4-
/// Constructs a new vector by selecting values from the lanes of the source vector or vectors to use.
4+
/// Constructs a new SIMD vector by copying elements from selected lanes in other vectors.
55
///
6-
/// When swizzling one vector, the indices of the result vector are indicated by a `const` array
7-
/// of `usize`, like [`Swizzle`].
8-
/// When swizzling two vectors, the indices are indicated by a `const` array of [`Which`], like
9-
/// [`Swizzle2`].
6+
/// When swizzling one vector, lanes are selected by a `const` array of `usize`,
7+
/// like [`Swizzle`].
8+
///
9+
/// When swizzling two vectors, lanes are selected by a `const` array of [`Which`],
10+
/// like [`Swizzle2`].
1011
///
1112
/// # Examples
12-
/// ## One source vector
13+
///
14+
/// With a single SIMD vector, the const array specifies lane indices in that vector:
1315
/// ```
1416
/// # #![feature(portable_simd)]
15-
/// # use core::simd::{Simd, simd_swizzle};
16-
/// let v = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
17+
/// # use core::simd::{u32x2, u32x4, simd_swizzle};
18+
/// let v = u32x4::from_array([10, 11, 12, 13]);
1719
///
1820
/// // Keeping the same size
19-
/// let r = simd_swizzle!(v, [3, 0, 1, 2]);
20-
/// assert_eq!(r.to_array(), [3., 0., 1., 2.]);
21+
/// let r: u32x4 = simd_swizzle!(v, [3, 0, 1, 2]);
22+
/// assert_eq!(r.to_array(), [13, 10, 11, 12]);
2123
///
2224
/// // Changing the number of lanes
23-
/// let r = simd_swizzle!(v, [3, 1]);
24-
/// assert_eq!(r.to_array(), [3., 1.]);
25+
/// let r: u32x2 = simd_swizzle!(v, [3, 1]);
26+
/// assert_eq!(r.to_array(), [13, 11]);
2527
/// ```
2628
///
27-
/// ## Two source vectors
29+
/// With two input SIMD vectors, the const array uses `Which` to specify the source of each index:
2830
/// ```
2931
/// # #![feature(portable_simd)]
30-
/// # use core::simd::{Simd, simd_swizzle, Which};
31-
/// use Which::*;
32-
/// let a = Simd::<f32, 4>::from_array([0., 1., 2., 3.]);
33-
/// let b = Simd::<f32, 4>::from_array([4., 5., 6., 7.]);
32+
/// # use core::simd::{u32x2, u32x4, simd_swizzle, Which};
33+
/// use Which::{First, Second};
34+
/// let a = u32x4::from_array([0, 1, 2, 3]);
35+
/// let b = u32x4::from_array([4, 5, 6, 7]);
3436
///
3537
/// // Keeping the same size
36-
/// let r = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]);
37-
/// assert_eq!(r.to_array(), [0., 1., 6., 7.]);
38+
/// let r: u32x4 = simd_swizzle!(a, b, [First(0), First(1), Second(2), Second(3)]);
39+
/// assert_eq!(r.to_array(), [0, 1, 6, 7]);
3840
///
3941
/// // Changing the number of lanes
40-
/// let r = simd_swizzle!(a, b, [First(0), Second(0)]);
41-
/// assert_eq!(r.to_array(), [0., 4.]);
42+
/// let r: u32x2 = simd_swizzle!(a, b, [First(0), Second(0)]);
43+
/// assert_eq!(r.to_array(), [0, 4]);
4244
/// ```
4345
#[allow(unused_macros)]
4446
pub macro simd_swizzle {
@@ -68,12 +70,14 @@ pub macro simd_swizzle {
6870
}
6971
}
7072

71-
/// An index into one of two vectors.
73+
/// Specifies a lane index into one of two SIMD vectors.
74+
///
75+
/// This is an input type for [Swizzle2] and helper macros like [simd_swizzle].
7276
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
7377
pub enum Which {
74-
/// Indexes the first vector.
78+
/// Index of a lane in the first input SIMD vector.
7579
First(usize),
76-
/// Indexes the second vector.
80+
/// Index of a lane in the second input SIMD vector.
7781
Second(usize),
7882
}
7983

crates/core_simd/src/vector.rs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,44 @@ where
9999
/// Number of lanes in this vector.
100100
pub const LANES: usize = LANES;
101101

102-
/// Get the number of lanes in this vector.
102+
/// Returns the number of lanes in this SIMD vector.
103+
///
104+
/// # Examples
105+
///
106+
/// ```
107+
/// # #![feature(portable_simd)]
108+
/// # use core::simd::u32x4;
109+
/// let v = u32x4::splat(0);
110+
/// assert_eq!(v.lanes(), 4);
111+
/// ```
103112
pub const fn lanes(&self) -> usize {
104113
LANES
105114
}
106115

107-
/// Construct a SIMD vector by setting all lanes to the given value.
116+
/// Constructs a new SIMD vector with all lanes set to the given value.
117+
///
118+
/// # Examples
119+
///
120+
/// ```
121+
/// # #![feature(portable_simd)]
122+
/// # use core::simd::u32x4;
123+
/// let v = u32x4::splat(8);
124+
/// assert_eq!(v.as_array(), &[8, 8, 8, 8]);
125+
/// ```
108126
pub const fn splat(value: T) -> Self {
109127
Self([value; LANES])
110128
}
111129

112130
/// Returns an array reference containing the entire SIMD vector.
131+
///
132+
/// # Examples
133+
///
134+
/// ```
135+
/// # #![feature(portable_simd)]
136+
/// # use core::simd::{Simd, u64x4};
137+
/// let v: u64x4 = Simd::from_array([0, 1, 2, 3]);
138+
/// assert_eq!(v.as_array(), &[0, 1, 2, 3]);
139+
/// ```
113140
pub const fn as_array(&self) -> &[T; LANES] {
114141
&self.0
115142
}
@@ -129,9 +156,21 @@ where
129156
self.0
130157
}
131158

132-
/// Converts a slice to a SIMD vector containing `slice[..LANES]`
159+
/// Converts a slice to a SIMD vector containing `slice[..LANES]`.
160+
///
133161
/// # Panics
134-
/// `from_slice` will panic if the slice's `len` is less than the vector's `Simd::LANES`.
162+
///
163+
/// Panics if the slice's length is less than the vector's `Simd::LANES`.
164+
///
165+
/// # Examples
166+
///
167+
/// ```
168+
/// # #![feature(portable_simd)]
169+
/// # use core::simd::{Simd, u32x4};
170+
/// let source = vec![1, 2, 3, 4, 5, 6];
171+
/// let v = u32x4::from_slice(&source);
172+
/// assert_eq!(v.as_array(), &[1, 2, 3, 4]);
173+
/// ```
135174
#[must_use]
136175
pub const fn from_slice(slice: &[T]) -> Self {
137176
assert!(
@@ -148,6 +187,7 @@ where
148187
}
149188

150189
/// Performs lanewise conversion of a SIMD vector's elements to another SIMD-valid type.
190+
///
151191
/// This follows the semantics of Rust's `as` conversion for casting
152192
/// integers to unsigned integers (interpreting as the other type, so `-1` to `MAX`),
153193
/// and from floats to integers (truncating, or saturating at the limits) for each lane,

0 commit comments

Comments
 (0)