Add vectors of pointers
This commit is contained in:
parent
7c80b6967a
commit
d3cfd7c5c9
45
crates/core_simd/src/cast.rs
Normal file
45
crates/core_simd/src/cast.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use crate::simd::SimdElement;
|
||||
|
||||
/// Supporting trait for `Simd::cast`. Typically doesn't need to be used directly.
|
||||
pub trait SimdCast<Target: SimdElement>: SimdElement {}
|
||||
|
||||
macro_rules! into_number {
|
||||
{ $($type:ty),* } => {
|
||||
$(
|
||||
impl SimdCast<i8> for $type {}
|
||||
impl SimdCast<i16> for $type {}
|
||||
impl SimdCast<i32> for $type {}
|
||||
impl SimdCast<i64> for $type {}
|
||||
impl SimdCast<isize> for $type {}
|
||||
|
||||
impl SimdCast<u8> for $type {}
|
||||
impl SimdCast<u16> for $type {}
|
||||
impl SimdCast<u32> for $type {}
|
||||
impl SimdCast<u64> for $type {}
|
||||
impl SimdCast<usize> for $type {}
|
||||
|
||||
impl SimdCast<f32> for $type {}
|
||||
impl SimdCast<f64> for $type {}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
into_number! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, f32, f64 }
|
||||
|
||||
macro_rules! into_pointer {
|
||||
{ $($type:ty),* } => {
|
||||
$(
|
||||
impl<T> SimdCast<$type> for *const T {}
|
||||
impl<T> SimdCast<$type> for *mut T {}
|
||||
impl<T> SimdCast<*const T> for $type {}
|
||||
impl<T> SimdCast<*mut T> for $type {}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
into_pointer! { i8, i16, i32, i64, isize, u8, u16, u32, u64, usize }
|
||||
|
||||
impl<T, U> SimdCast<*const T> for *const U {}
|
||||
impl<T, U> SimdCast<*const T> for *mut U {}
|
||||
impl<T, U> SimdCast<*mut T> for *const U {}
|
||||
impl<T, U> SimdCast<*mut T> for *mut U {}
|
@ -1,11 +1,15 @@
|
||||
mod const_ptr;
|
||||
mod float;
|
||||
mod int;
|
||||
mod mut_ptr;
|
||||
mod uint;
|
||||
|
||||
mod sealed {
|
||||
pub trait Sealed {}
|
||||
}
|
||||
|
||||
pub use const_ptr::*;
|
||||
pub use float::*;
|
||||
pub use int::*;
|
||||
pub use mut_ptr::*;
|
||||
pub use uint::*;
|
||||
|
59
crates/core_simd/src/elements/const_ptr.rs
Normal file
59
crates/core_simd/src/elements/const_ptr.rs
Normal file
@ -0,0 +1,59 @@
|
||||
use super::sealed::Sealed;
|
||||
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
|
||||
|
||||
/// Operations on SIMD vectors of constant pointers.
|
||||
pub trait SimdConstPtr: Copy + Sealed {
|
||||
/// Vector type representing the pointers as bits.
|
||||
type Bits;
|
||||
|
||||
/// Vector of mutable pointers to the same type.
|
||||
type MutPtr;
|
||||
|
||||
/// Mask type used for manipulating this SIMD vector type.
|
||||
type Mask;
|
||||
|
||||
/// Returns `true` for each lane that is null.
|
||||
fn is_null(self) -> Self::Mask;
|
||||
|
||||
/// Changes constness without changing the type.
|
||||
fn as_mut(self) -> Self::MutPtr;
|
||||
|
||||
/// Cast pointers to raw bits.
|
||||
fn to_bits(self) -> Self::Bits;
|
||||
|
||||
/// Cast raw bits to pointers.
|
||||
fn from_bits(bits: Self::Bits) -> Self;
|
||||
}
|
||||
|
||||
impl<T, const LANES: usize> Sealed for Simd<*const T, LANES> where
|
||||
LaneCount<LANES>: SupportedLaneCount
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, const LANES: usize> SimdConstPtr for Simd<*const T, LANES>
|
||||
where
|
||||
LaneCount<LANES>: SupportedLaneCount,
|
||||
{
|
||||
type Bits = Simd<usize, LANES>;
|
||||
type MutPtr = Simd<*mut T, LANES>;
|
||||
type Mask = Mask<isize, LANES>;
|
||||
|
||||
fn is_null(self) -> Self::Mask {
|
||||
Simd::splat(core::ptr::null()).simd_eq(self)
|
||||
}
|
||||
|
||||
fn as_mut(self) -> Self::MutPtr {
|
||||
// Converting between pointers is safe
|
||||
unsafe { intrinsics::simd_as(self) }
|
||||
}
|
||||
|
||||
fn to_bits(self) -> Self::Bits {
|
||||
// Casting pointers to usize is safe
|
||||
unsafe { intrinsics::simd_as(self) }
|
||||
}
|
||||
|
||||
fn from_bits(bits: Self::Bits) -> Self {
|
||||
// Casting usize to pointers is safe
|
||||
unsafe { intrinsics::simd_as(bits) }
|
||||
}
|
||||
}
|
57
crates/core_simd/src/elements/mut_ptr.rs
Normal file
57
crates/core_simd/src/elements/mut_ptr.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use super::sealed::Sealed;
|
||||
use crate::simd::{intrinsics, LaneCount, Mask, Simd, SimdPartialEq, SupportedLaneCount};
|
||||
|
||||
/// Operations on SIMD vectors of mutable pointers.
|
||||
pub trait SimdMutPtr: Copy + Sealed {
|
||||
/// Vector type representing the pointers as bits.
|
||||
type Bits;
|
||||
|
||||
/// Vector of constant pointers to the same type.
|
||||
type ConstPtr;
|
||||
|
||||
/// Mask type used for manipulating this SIMD vector type.
|
||||
type Mask;
|
||||
|
||||
/// Returns `true` for each lane that is null.
|
||||
fn is_null(self) -> Self::Mask;
|
||||
|
||||
/// Changes constness without changing the type.
|
||||
fn as_const(self) -> Self::ConstPtr;
|
||||
|
||||
/// Cast pointers to raw bits.
|
||||
fn to_bits(self) -> Self::Bits;
|
||||
|
||||
/// Cast raw bits to pointers.
|
||||
fn from_bits(bits: Self::Bits) -> Self;
|
||||
}
|
||||
|
||||
impl<T, const LANES: usize> Sealed for Simd<*mut T, LANES> where LaneCount<LANES>: SupportedLaneCount
|
||||
{}
|
||||
|
||||
impl<T, const LANES: usize> SimdMutPtr for Simd<*mut T, LANES>
|
||||
where
|
||||
LaneCount<LANES>: SupportedLaneCount,
|
||||
{
|
||||
type Bits = Simd<usize, LANES>;
|
||||
type ConstPtr = Simd<*const T, LANES>;
|
||||
type Mask = Mask<isize, LANES>;
|
||||
|
||||
fn is_null(self) -> Self::Mask {
|
||||
Simd::splat(core::ptr::null_mut()).simd_eq(self)
|
||||
}
|
||||
|
||||
fn as_const(self) -> Self::ConstPtr {
|
||||
// Converting between pointers is safe
|
||||
unsafe { intrinsics::simd_as(self) }
|
||||
}
|
||||
|
||||
fn to_bits(self) -> Self::Bits {
|
||||
// Casting pointers to usize is safe
|
||||
unsafe { intrinsics::simd_as(self) }
|
||||
}
|
||||
|
||||
fn from_bits(bits: Self::Bits) -> Self {
|
||||
// Casting usize to pointers is safe
|
||||
unsafe { intrinsics::simd_as(bits) }
|
||||
}
|
||||
}
|
@ -71,3 +71,45 @@ fn simd_ne(self, other: Self) -> Self::Mask {
|
||||
}
|
||||
|
||||
impl_mask! { i8, i16, i32, i64, isize }
|
||||
|
||||
impl<T, const LANES: usize> SimdPartialEq for Simd<*const T, LANES>
|
||||
where
|
||||
LaneCount<LANES>: SupportedLaneCount,
|
||||
{
|
||||
type Mask = Mask<isize, LANES>;
|
||||
|
||||
#[inline]
|
||||
fn simd_eq(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_ne(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const LANES: usize> SimdPartialEq for Simd<*mut T, LANES>
|
||||
where
|
||||
LaneCount<LANES>: SupportedLaneCount,
|
||||
{
|
||||
type Mask = Mask<isize, LANES>;
|
||||
|
||||
#[inline]
|
||||
fn simd_eq(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_eq(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_ne(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_ne(self, other)) }
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
mod to_bytes;
|
||||
|
||||
mod alias;
|
||||
mod cast;
|
||||
mod elements;
|
||||
mod eq;
|
||||
mod fmt;
|
||||
@ -24,6 +25,7 @@ pub mod simd {
|
||||
pub(crate) use crate::core_simd::intrinsics;
|
||||
|
||||
pub use crate::core_simd::alias::*;
|
||||
pub use crate::core_simd::cast::*;
|
||||
pub use crate::core_simd::elements::*;
|
||||
pub use crate::core_simd::eq::*;
|
||||
pub use crate::core_simd::lane_count::{LaneCount, SupportedLaneCount};
|
||||
|
@ -211,3 +211,117 @@ fn simd_clamp(self, min: Self, max: Self) -> Self {
|
||||
}
|
||||
|
||||
impl_mask! { i8, i16, i32, i64, isize }
|
||||
|
||||
impl<T, const LANES: usize> SimdPartialOrd for Simd<*const T, LANES>
|
||||
where
|
||||
LaneCount<LANES>: SupportedLaneCount,
|
||||
{
|
||||
#[inline]
|
||||
fn simd_lt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_le(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_gt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_ge(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const LANES: usize> SimdOrd for Simd<*const T, LANES>
|
||||
where
|
||||
LaneCount<LANES>: SupportedLaneCount,
|
||||
{
|
||||
#[inline]
|
||||
fn simd_max(self, other: Self) -> Self {
|
||||
self.simd_lt(other).select(other, self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_min(self, other: Self) -> Self {
|
||||
self.simd_gt(other).select(other, self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_clamp(self, min: Self, max: Self) -> Self {
|
||||
assert!(
|
||||
min.simd_le(max).all(),
|
||||
"each lane in `min` must be less than or equal to the corresponding lane in `max`",
|
||||
);
|
||||
self.simd_max(min).simd_min(max)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const LANES: usize> SimdPartialOrd for Simd<*mut T, LANES>
|
||||
where
|
||||
LaneCount<LANES>: SupportedLaneCount,
|
||||
{
|
||||
#[inline]
|
||||
fn simd_lt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_lt(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_le(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_le(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_gt(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_gt(self, other)) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_ge(self, other: Self) -> Self::Mask {
|
||||
// Safety: `self` is a vector, and the result of the comparison
|
||||
// is always a valid mask.
|
||||
unsafe { Mask::from_int_unchecked(intrinsics::simd_ge(self, other)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const LANES: usize> SimdOrd for Simd<*mut T, LANES>
|
||||
where
|
||||
LaneCount<LANES>: SupportedLaneCount,
|
||||
{
|
||||
#[inline]
|
||||
fn simd_max(self, other: Self) -> Self {
|
||||
self.simd_lt(other).select(other, self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_min(self, other: Self) -> Self {
|
||||
self.simd_gt(other).select(other, self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn simd_clamp(self, min: Self, max: Self) -> Self {
|
||||
assert!(
|
||||
min.simd_le(max).all(),
|
||||
"each lane in `min` must be less than or equal to the corresponding lane in `max`",
|
||||
);
|
||||
self.simd_max(min).simd_min(max)
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
pub(crate) mod ptr;
|
||||
|
||||
use crate::simd::{
|
||||
intrinsics, LaneCount, Mask, MaskElement, SimdPartialOrd, SupportedLaneCount, Swizzle,
|
||||
intrinsics, LaneCount, Mask, MaskElement, SimdCast, SimdPartialOrd, SupportedLaneCount, Swizzle,
|
||||
};
|
||||
|
||||
/// A SIMD vector of `LANES` elements of type `T`. `Simd<T, N>` has the same shape as [`[T; N]`](array), but operates like `T`.
|
||||
@ -211,7 +211,10 @@ pub const fn from_slice(slice: &[T]) -> Self {
|
||||
#[must_use]
|
||||
#[inline]
|
||||
#[cfg(not(bootstrap))]
|
||||
pub fn cast<U: SimdElement>(self) -> Simd<U, LANES> {
|
||||
pub fn cast<U: SimdElement>(self) -> Simd<U, LANES>
|
||||
where
|
||||
T: SimdCast<U>,
|
||||
{
|
||||
// Safety: The input argument is a vector of a valid SIMD element type.
|
||||
unsafe { intrinsics::simd_as(self) }
|
||||
}
|
||||
@ -234,7 +237,7 @@ pub fn cast<U: SimdElement>(self) -> Simd<U, LANES> {
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub unsafe fn to_int_unchecked<I>(self) -> Simd<I, LANES>
|
||||
where
|
||||
T: core::convert::FloatToInt<I>,
|
||||
T: core::convert::FloatToInt<I> + SimdCast<I>,
|
||||
I: SimdElement,
|
||||
{
|
||||
// Safety: `self` is a vector, and `FloatToInt` ensures the type can be casted to
|
||||
@ -739,3 +742,13 @@ impl Sealed for f64 {}
|
||||
unsafe impl SimdElement for f64 {
|
||||
type Mask = i64;
|
||||
}
|
||||
|
||||
impl<T> Sealed for *const T {}
|
||||
unsafe impl<T> SimdElement for *const T {
|
||||
type Mask = isize;
|
||||
}
|
||||
|
||||
impl<T> Sealed for *mut T {}
|
||||
unsafe impl<T> SimdElement for *mut T {
|
||||
type Mask = isize;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user