Merge portable-simd#232 - ./feat/typecast
Add Simd::cast Add core_simd/tests/cast.rs
This commit is contained in:
commit
7072c2278e
@ -39,6 +39,9 @@
|
||||
|
||||
/// fptoui/fptosi/uitofp/sitofp
|
||||
pub(crate) fn simd_cast<T, U>(x: T) -> U;
|
||||
/// follows Rust's `T as U` semantics, including saturating float casts
|
||||
/// which amounts to the same as `simd_cast` for many cases
|
||||
pub(crate) fn simd_as<T, U>(x: T) -> U;
|
||||
|
||||
/// neg/fneg
|
||||
pub(crate) fn simd_neg<T>(x: T) -> T;
|
||||
|
@ -75,6 +75,35 @@ pub const fn from_slice(slice: &[T]) -> Self {
|
||||
Self(array)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
/// or vice versa.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![feature(portable_simd)]
|
||||
/// # #[cfg(feature = "std")] use core_simd::Simd;
|
||||
/// # #[cfg(not(feature = "std"))] use core::simd::Simd;
|
||||
/// let floats: Simd<f32, 4> = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]);
|
||||
/// let ints = floats.cast::<i32>();
|
||||
/// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0]));
|
||||
///
|
||||
/// // Formally equivalent, but `Simd::cast` can optimize better.
|
||||
/// assert_eq!(ints, Simd::from_array(floats.to_array().map(|x| x as i32)));
|
||||
///
|
||||
/// // The float conversion does not round-trip.
|
||||
/// let floats_again = ints.cast();
|
||||
/// assert_ne!(floats, floats_again);
|
||||
/// assert_eq!(floats_again, Simd::from_array([1.0, -4.0, 2147483647.0, 0.0]));
|
||||
/// ```
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub fn cast<U: SimdElement>(self) -> Simd<U, LANES> {
|
||||
unsafe { intrinsics::simd_as(self) }
|
||||
}
|
||||
|
||||
/// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
|
||||
/// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
|
||||
///
|
||||
|
37
crates/core_simd/tests/cast.rs
Normal file
37
crates/core_simd/tests/cast.rs
Normal file
@ -0,0 +1,37 @@
|
||||
#![feature(portable_simd)]
|
||||
macro_rules! cast_types {
|
||||
($start:ident, $($target:ident),*) => {
|
||||
mod $start {
|
||||
use core_simd::simd::Simd;
|
||||
type Vector<const N: usize> = Simd<$start, N>;
|
||||
$(
|
||||
mod $target {
|
||||
use super::*;
|
||||
test_helpers::test_lanes! {
|
||||
fn cast_as<const N: usize>() {
|
||||
test_helpers::test_unary_elementwise(
|
||||
&Vector::<N>::cast::<$target>,
|
||||
&|x| x as $target,
|
||||
&|_| true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// The hypothesis is that widening conversions aren't terribly interesting.
|
||||
cast_types!(f32, f64, i8, u8, usize, isize);
|
||||
cast_types!(f64, f32, i8, u8, usize, isize);
|
||||
cast_types!(i8, u8, f32);
|
||||
cast_types!(u8, i8, f32);
|
||||
cast_types!(i16, u16, i8, u8, f32);
|
||||
cast_types!(u16, i16, i8, u8, f32);
|
||||
cast_types!(i32, u32, i8, u8, f32, f64);
|
||||
cast_types!(u32, i32, i8, u8, f32, f64);
|
||||
cast_types!(i64, u64, i8, u8, isize, usize, f32, f64);
|
||||
cast_types!(u64, i64, i8, u8, isize, usize, f32, f64);
|
||||
cast_types!(isize, usize, i8, u8, f32, f64);
|
||||
cast_types!(usize, isize, i8, u8, f32, f64);
|
Loading…
Reference in New Issue
Block a user