Skip to content

Commit 9b8d12c

Browse files
committed
Auto merge of rust-lang#122905 - dpaoliello:sync-portable-simd-2024-03-22, r=workingjubilee
Portable SIMD subtree update Syncs nightly to the latest changes from rust-lang/portable-simd r? `@calebzulawski`
2 parents 2f090c3 + 9e0ec25 commit 9b8d12c

File tree

13 files changed

+505
-52
lines changed

13 files changed

+505
-52
lines changed

library/portable-simd/.github/workflows/ci.yml

+5
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ jobs:
141141
- name: Test (release)
142142
run: cargo test --verbose --target=${{ matrix.target }} --release
143143

144+
- name: Generate docs
145+
run: cargo doc --verbose --target=${{ matrix.target }}
146+
env:
147+
RUSTDOCFLAGS: -Dwarnings
148+
144149
wasm-tests:
145150
name: "wasm (firefox, ${{ matrix.name }})"
146151
runs-on: ubuntu-latest

library/portable-simd/Cargo.lock

+3
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ name = "std_float"
177177
version = "0.1.0"
178178
dependencies = [
179179
"core_simd",
180+
"test_helpers",
181+
"wasm-bindgen",
182+
"wasm-bindgen-test",
180183
]
181184

182185
[[package]]

library/portable-simd/crates/core_simd/src/lib.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
simd_ffi,
1414
staged_api,
1515
strict_provenance,
16+
prelude_import,
1617
ptr_metadata
1718
)]
1819
#![cfg_attr(
1920
all(
20-
any(target_arch = "aarch64", target_arch = "arm",),
21+
any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm",),
2122
any(
2223
all(target_feature = "v6", not(target_feature = "mclass")),
2324
all(target_feature = "mclass", target_feature = "dsp"),
@@ -33,12 +34,21 @@
3334
any(target_arch = "powerpc", target_arch = "powerpc64"),
3435
feature(stdarch_powerpc)
3536
)]
37+
#![cfg_attr(
38+
all(target_arch = "x86_64", target_feature = "avx512f"),
39+
feature(stdarch_x86_avx512)
40+
)]
3641
#![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really
3742
#![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)]
43+
#![doc(test(attr(deny(warnings))))]
3844
#![allow(internal_features)]
3945
#![unstable(feature = "portable_simd", issue = "86656")]
4046
//! Portable SIMD module.
4147
48+
#[prelude_import]
49+
#[allow(unused_imports)]
50+
use core::prelude::v1::*;
51+
4252
#[path = "mod.rs"]
4353
mod core_simd;
4454
pub use self::core_simd::simd;

library/portable-simd/crates/core_simd/src/masks.rs

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ mod sealed {
3434
fn eq(self, other: Self) -> bool;
3535

3636
fn to_usize(self) -> usize;
37+
fn max_unsigned() -> u64;
3738

3839
type Unsigned: SimdElement;
3940

@@ -78,6 +79,11 @@ macro_rules! impl_element {
7879
self as usize
7980
}
8081

82+
#[inline]
83+
fn max_unsigned() -> u64 {
84+
<$unsigned>::MAX as u64
85+
}
86+
8187
type Unsigned = $unsigned;
8288

8389
const TRUE: Self = -1;

library/portable-simd/crates/core_simd/src/swizzle_dyn.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ where
1616
#[inline]
1717
pub fn swizzle_dyn(self, idxs: Simd<u8, N>) -> Self {
1818
#![allow(unused_imports, unused_unsafe)]
19-
#[cfg(all(target_arch = "aarch64", target_endian = "little"))]
19+
#[cfg(all(
20+
any(target_arch = "aarch64", target_arch = "arm64ec"),
21+
target_endian = "little"
22+
))]
2023
use core::arch::aarch64::{uint8x8_t, vqtbl1q_u8, vtbl1_u8};
2124
#[cfg(all(
2225
target_arch = "arm",
@@ -37,6 +40,7 @@ where
3740
#[cfg(all(
3841
any(
3942
target_arch = "aarch64",
43+
target_arch = "arm64ec",
4044
all(target_arch = "arm", target_feature = "v7")
4145
),
4246
target_feature = "neon",
@@ -48,7 +52,7 @@ where
4852
#[cfg(target_feature = "simd128")]
4953
16 => transize(wasm::i8x16_swizzle, self, idxs),
5054
#[cfg(all(
51-
target_arch = "aarch64",
55+
any(target_arch = "aarch64", target_arch = "arm64ec"),
5256
target_feature = "neon",
5357
target_endian = "little"
5458
))]

library/portable-simd/crates/core_simd/src/vector.rs

+244
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::simd::{
22
cmp::SimdPartialOrd,
3+
num::SimdUint,
34
ptr::{SimdConstPtr, SimdMutPtr},
45
LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle,
56
};
@@ -262,6 +263,7 @@ where
262263
/// # Panics
263264
///
264265
/// Panics if the slice's length is less than the vector's `Simd::N`.
266+
/// Use `load_or_default` for an alternative that does not panic.
265267
///
266268
/// # Example
267269
///
@@ -315,6 +317,143 @@ where
315317
unsafe { self.store(slice.as_mut_ptr().cast()) }
316318
}
317319

320+
/// Reads contiguous elements from `slice`. Elements are read so long as they're in-bounds for
321+
/// the `slice`. Otherwise, the default value for the element type is returned.
322+
///
323+
/// # Examples
324+
/// ```
325+
/// # #![feature(portable_simd)]
326+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
327+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
328+
/// # use simd::Simd;
329+
/// let vec: Vec<i32> = vec![10, 11];
330+
///
331+
/// let result = Simd::<i32, 4>::load_or_default(&vec);
332+
/// assert_eq!(result, Simd::from_array([10, 11, 0, 0]));
333+
/// ```
334+
#[must_use]
335+
#[inline]
336+
pub fn load_or_default(slice: &[T]) -> Self
337+
where
338+
T: Default,
339+
{
340+
Self::load_or(slice, Default::default())
341+
}
342+
343+
/// Reads contiguous elements from `slice`. Elements are read so long as they're in-bounds for
344+
/// the `slice`. Otherwise, the corresponding value from `or` is passed through.
345+
///
346+
/// # Examples
347+
/// ```
348+
/// # #![feature(portable_simd)]
349+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
350+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
351+
/// # use simd::Simd;
352+
/// let vec: Vec<i32> = vec![10, 11];
353+
/// let or = Simd::from_array([-5, -4, -3, -2]);
354+
///
355+
/// let result = Simd::load_or(&vec, or);
356+
/// assert_eq!(result, Simd::from_array([10, 11, -3, -2]));
357+
/// ```
358+
#[must_use]
359+
#[inline]
360+
pub fn load_or(slice: &[T], or: Self) -> Self {
361+
Self::load_select(slice, Mask::splat(true), or)
362+
}
363+
364+
/// Reads contiguous elements from `slice`. Each element is read from memory if its
365+
/// corresponding element in `enable` is `true`.
366+
///
367+
/// When the element is disabled or out of bounds for the slice, that memory location
368+
/// is not accessed and the corresponding value from `or` is passed through.
369+
///
370+
/// # Examples
371+
/// ```
372+
/// # #![feature(portable_simd)]
373+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
374+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
375+
/// # use simd::{Simd, Mask};
376+
/// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
377+
/// let enable = Mask::from_array([true, true, false, true]);
378+
/// let or = Simd::from_array([-5, -4, -3, -2]);
379+
///
380+
/// let result = Simd::load_select(&vec, enable, or);
381+
/// assert_eq!(result, Simd::from_array([10, 11, -3, 13]));
382+
/// ```
383+
#[must_use]
384+
#[inline]
385+
pub fn load_select_or_default(slice: &[T], enable: Mask<<T as SimdElement>::Mask, N>) -> Self
386+
where
387+
T: Default,
388+
{
389+
Self::load_select(slice, enable, Default::default())
390+
}
391+
392+
/// Reads contiguous elements from `slice`. Each element is read from memory if its
393+
/// corresponding element in `enable` is `true`.
394+
///
395+
/// When the element is disabled or out of bounds for the slice, that memory location
396+
/// is not accessed and the corresponding value from `or` is passed through.
397+
///
398+
/// # Examples
399+
/// ```
400+
/// # #![feature(portable_simd)]
401+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
402+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
403+
/// # use simd::{Simd, Mask};
404+
/// let vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18];
405+
/// let enable = Mask::from_array([true, true, false, true]);
406+
/// let or = Simd::from_array([-5, -4, -3, -2]);
407+
///
408+
/// let result = Simd::load_select(&vec, enable, or);
409+
/// assert_eq!(result, Simd::from_array([10, 11, -3, 13]));
410+
/// ```
411+
#[must_use]
412+
#[inline]
413+
pub fn load_select(
414+
slice: &[T],
415+
mut enable: Mask<<T as SimdElement>::Mask, N>,
416+
or: Self,
417+
) -> Self {
418+
enable &= mask_up_to(slice.len());
419+
// SAFETY: We performed the bounds check by updating the mask. &[T] is properly aligned to
420+
// the element.
421+
unsafe { Self::load_select_ptr(slice.as_ptr(), enable, or) }
422+
}
423+
424+
/// Reads contiguous elements from `slice`. Each element is read from memory if its
425+
/// corresponding element in `enable` is `true`.
426+
///
427+
/// When the element is disabled, that memory location is not accessed and the corresponding
428+
/// value from `or` is passed through.
429+
#[must_use]
430+
#[inline]
431+
pub unsafe fn load_select_unchecked(
432+
slice: &[T],
433+
enable: Mask<<T as SimdElement>::Mask, N>,
434+
or: Self,
435+
) -> Self {
436+
let ptr = slice.as_ptr();
437+
// SAFETY: The safety of reading elements from `slice` is ensured by the caller.
438+
unsafe { Self::load_select_ptr(ptr, enable, or) }
439+
}
440+
441+
/// Reads contiguous elements starting at `ptr`. Each element is read from memory if its
442+
/// corresponding element in `enable` is `true`.
443+
///
444+
/// When the element is disabled, that memory location is not accessed and the corresponding
445+
/// value from `or` is passed through.
446+
#[must_use]
447+
#[inline]
448+
pub unsafe fn load_select_ptr(
449+
ptr: *const T,
450+
enable: Mask<<T as SimdElement>::Mask, N>,
451+
or: Self,
452+
) -> Self {
453+
// SAFETY: The safety of reading elements through `ptr` is ensured by the caller.
454+
unsafe { core::intrinsics::simd::simd_masked_load(enable.to_int(), ptr, or) }
455+
}
456+
318457
/// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
319458
/// If an index is out-of-bounds, the element is instead selected from the `or` vector.
320459
///
@@ -493,6 +632,77 @@ where
493632
unsafe { core::intrinsics::simd::simd_gather(or, source, enable.to_int()) }
494633
}
495634

635+
/// Conditionally write contiguous elements to `slice`. The `enable` mask controls
636+
/// which elements are written, as long as they're in-bounds of the `slice`.
637+
/// If the element is disabled or out of bounds, no memory access to that location
638+
/// is made.
639+
///
640+
/// # Examples
641+
/// ```
642+
/// # #![feature(portable_simd)]
643+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
644+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
645+
/// # use simd::{Simd, Mask};
646+
/// let mut arr = [0i32; 4];
647+
/// let write = Simd::from_array([-5, -4, -3, -2]);
648+
/// let enable = Mask::from_array([false, true, true, true]);
649+
///
650+
/// write.store_select(&mut arr[..3], enable);
651+
/// assert_eq!(arr, [0, -4, -3, 0]);
652+
/// ```
653+
#[inline]
654+
pub fn store_select(self, slice: &mut [T], mut enable: Mask<<T as SimdElement>::Mask, N>) {
655+
enable &= mask_up_to(slice.len());
656+
// SAFETY: We performed the bounds check by updating the mask. &[T] is properly aligned to
657+
// the element.
658+
unsafe { self.store_select_ptr(slice.as_mut_ptr(), enable) }
659+
}
660+
661+
/// Conditionally write contiguous elements to `slice`. The `enable` mask controls
662+
/// which elements are written.
663+
///
664+
/// # Safety
665+
///
666+
/// Every enabled element must be in bounds for the `slice`.
667+
///
668+
/// # Examples
669+
/// ```
670+
/// # #![feature(portable_simd)]
671+
/// # #[cfg(feature = "as_crate")] use core_simd::simd;
672+
/// # #[cfg(not(feature = "as_crate"))] use core::simd;
673+
/// # use simd::{Simd, Mask};
674+
/// let mut arr = [0i32; 4];
675+
/// let write = Simd::from_array([-5, -4, -3, -2]);
676+
/// let enable = Mask::from_array([false, true, true, true]);
677+
///
678+
/// unsafe { write.store_select_unchecked(&mut arr, enable) };
679+
/// assert_eq!(arr, [0, -4, -3, -2]);
680+
/// ```
681+
#[inline]
682+
pub unsafe fn store_select_unchecked(
683+
self,
684+
slice: &mut [T],
685+
enable: Mask<<T as SimdElement>::Mask, N>,
686+
) {
687+
let ptr = slice.as_mut_ptr();
688+
// SAFETY: The safety of writing elements in `slice` is ensured by the caller.
689+
unsafe { self.store_select_ptr(ptr, enable) }
690+
}
691+
692+
/// Conditionally write contiguous elements starting from `ptr`.
693+
/// The `enable` mask controls which elements are written.
694+
/// When disabled, the memory location corresponding to that element is not accessed.
695+
///
696+
/// # Safety
697+
///
698+
/// Memory addresses for element are calculated [`pointer::wrapping_offset`] and
699+
/// each enabled element must satisfy the same conditions as [`core::ptr::write`].
700+
#[inline]
701+
pub unsafe fn store_select_ptr(self, ptr: *mut T, enable: Mask<<T as SimdElement>::Mask, N>) {
702+
// SAFETY: The safety of writing elements through `ptr` is ensured by the caller.
703+
unsafe { core::intrinsics::simd::simd_masked_store(enable.to_int(), ptr, self) }
704+
}
705+
496706
/// Writes the values in a SIMD vector to potentially discontiguous indices in `slice`.
497707
/// If an index is out-of-bounds, the write is suppressed without panicking.
498708
/// If two elements in the scattered vector would write to the same index
@@ -980,3 +1190,37 @@ where
9801190
{
9811191
type Mask = isize;
9821192
}
1193+
1194+
#[inline]
1195+
fn lane_indices<const N: usize>() -> Simd<usize, N>
1196+
where
1197+
LaneCount<N>: SupportedLaneCount,
1198+
{
1199+
let mut index = [0; N];
1200+
for i in 0..N {
1201+
index[i] = i;
1202+
}
1203+
Simd::from_array(index)
1204+
}
1205+
1206+
#[inline]
1207+
fn mask_up_to<M, const N: usize>(len: usize) -> Mask<M, N>
1208+
where
1209+
LaneCount<N>: SupportedLaneCount,
1210+
M: MaskElement,
1211+
{
1212+
let index = lane_indices::<N>();
1213+
let max_value: u64 = M::max_unsigned();
1214+
macro_rules! case {
1215+
($ty:ty) => {
1216+
if N < <$ty>::MAX as usize && max_value as $ty as u64 == max_value {
1217+
return index.cast().simd_lt(Simd::splat(len.min(N) as $ty)).cast();
1218+
}
1219+
};
1220+
}
1221+
case!(u8);
1222+
case!(u16);
1223+
case!(u32);
1224+
case!(u64);
1225+
index.simd_lt(Simd::splat(len)).cast()
1226+
}

library/portable-simd/crates/core_simd/src/vendor.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ mod x86;
2424
#[cfg(target_arch = "wasm32")]
2525
mod wasm32;
2626

27-
#[cfg(any(target_arch = "aarch64", target_arch = "arm",))]
27+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm",))]
2828
mod arm;
2929

3030
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]

0 commit comments

Comments
 (0)