Skip to content

Commit ef4009d

Browse files
committed
Merge commit '50e8ae892d00f216fa920272a23204cd8c990265' into sync-portable-simd-2024-03-22
2 parents 1447f9d + 50e8ae8 commit ef4009d

File tree

12 files changed

+494
-53
lines changed

12 files changed

+494
-53
lines changed

library/portable-simd/Cargo.lock

Lines changed: 3 additions & 0 deletions
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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
)]
1818
#![cfg_attr(
1919
all(
20-
any(target_arch = "aarch64", target_arch = "arm",),
20+
any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "arm",),
2121
any(
2222
all(target_feature = "v6", not(target_feature = "mclass")),
2323
all(target_feature = "mclass", target_feature = "dsp"),
@@ -33,6 +33,10 @@
3333
any(target_arch = "powerpc", target_arch = "powerpc64"),
3434
feature(stdarch_powerpc)
3535
)]
36+
#![cfg_attr(
37+
all(target_arch = "x86_64", target_feature = "avx512f"),
38+
feature(stdarch_x86_avx512)
39+
)]
3640
#![warn(missing_docs, clippy::missing_inline_in_public_items)] // basically all items, really
3741
#![deny(unsafe_op_in_unsafe_fn, clippy::undocumented_unsafe_blocks)]
3842
#![allow(internal_features)]

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

Lines changed: 6 additions & 0 deletions
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

Lines changed: 6 additions & 2 deletions
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

Lines changed: 244 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::simd::{
22
cmp::SimdPartialOrd,
3+
num::SimdUint,
34
ptr::{SimdConstPtr, SimdMutPtr},
45
LaneCount, Mask, MaskElement, SupportedLaneCount, Swizzle,
56
};
6-
use core::convert::{TryFrom, TryInto};
77

88
/// A SIMD vector with the shape of `[T; N]` but the operations of `T`.
99
///
@@ -262,6 +262,7 @@ where
262262
/// # Panics
263263
///
264264
/// Panics if the slice's length is less than the vector's `Simd::N`.
265+
/// Use `load_or_default` for an alternative that does not panic.
265266
///
266267
/// # Example
267268
///
@@ -315,6 +316,143 @@ where
315316
unsafe { self.store(slice.as_mut_ptr().cast()) }
316317
}
317318

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

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

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

Lines changed: 1 addition & 1 deletion
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"))]

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ use crate::simd::*;
44
#[cfg(target_arch = "arm")]
55
use core::arch::arm::*;
66

7-
#[cfg(target_arch = "aarch64")]
7+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))]
88
use core::arch::aarch64::*;
99

1010
#[cfg(all(
1111
any(
1212
target_arch = "aarch64",
13+
target_arch = "arm64ec",
1314
all(target_arch = "arm", target_feature = "v7"),
1415
),
1516
target_endian = "little"
@@ -69,7 +70,10 @@ mod simd32 {
6970
from_transmute! { unsafe Simd<i8, 4> => int8x4_t }
7071
}
7172

72-
#[cfg(target_arch = "aarch64")]
73+
#[cfg(all(
74+
any(target_arch = "aarch64", target_arch = "arm64ec"),
75+
target_endian = "little"
76+
))]
7377
mod aarch64 {
7478
use super::neon::*;
7579
use super::*;

0 commit comments

Comments
 (0)