1
1
use super :: sealed:: Sealed ;
2
2
use crate :: simd:: {
3
- intrinsics, LaneCount , Mask , Simd , SimdElement , SimdPartialEq , SimdPartialOrd ,
3
+ intrinsics, LaneCount , Mask , Simd , SimdCast , SimdElement , SimdPartialEq , SimdPartialOrd ,
4
4
SupportedLaneCount ,
5
5
} ;
6
6
@@ -15,6 +15,53 @@ pub trait SimdFloat: Copy + Sealed {
15
15
/// Bit representation of this SIMD vector type.
16
16
type Bits ;
17
17
18
+ /// A SIMD vector with a different element type.
19
+ type Cast < T : SimdElement > ;
20
+
21
+ /// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
22
+ ///
23
+ /// This follows the semantics of Rust's `as` conversion for floats (truncating or saturating
24
+ /// at the limits) for each element.
25
+ ///
26
+ /// # Example
27
+ /// ```
28
+ /// # #![feature(portable_simd)]
29
+ /// # #[cfg(feature = "as_crate")] use core_simd::simd;
30
+ /// # #[cfg(not(feature = "as_crate"))] use core::simd;
31
+ /// # use simd::{SimdFloat, SimdInt, Simd};
32
+ /// let floats: Simd<f32, 4> = Simd::from_array([1.9, -4.5, f32::INFINITY, f32::NAN]);
33
+ /// let ints = floats.cast::<i32>();
34
+ /// assert_eq!(ints, Simd::from_array([1, -4, i32::MAX, 0]));
35
+ ///
36
+ /// // Formally equivalent, but `Simd::cast` can optimize better.
37
+ /// assert_eq!(ints, Simd::from_array(floats.to_array().map(|x| x as i32)));
38
+ ///
39
+ /// // The float conversion does not round-trip.
40
+ /// let floats_again = ints.cast();
41
+ /// assert_ne!(floats, floats_again);
42
+ /// assert_eq!(floats_again, Simd::from_array([1.0, -4.0, 2147483647.0, 0.0]));
43
+ /// ```
44
+ #[ must_use]
45
+ fn cast < T : SimdCast > ( self ) -> Self :: Cast < T > ;
46
+
47
+ /// Rounds toward zero and converts to the same-width integer type, assuming that
48
+ /// the value is finite and fits in that type.
49
+ ///
50
+ /// # Safety
51
+ /// The value must:
52
+ ///
53
+ /// * Not be NaN
54
+ /// * Not be infinite
55
+ /// * Be representable in the return type, after truncating off its fractional part
56
+ ///
57
+ /// If these requirements are infeasible or costly, consider using the safe function [cast],
58
+ /// which saturates on conversion.
59
+ ///
60
+ /// [cast]: Simd::cast
61
+ unsafe fn to_int_unchecked < I : SimdCast > ( self ) -> Self :: Cast < I >
62
+ where
63
+ Self :: Scalar : core:: convert:: FloatToInt < I > ;
64
+
18
65
/// Raw transmutation to an unsigned integer vector type with the
19
66
/// same size and number of lanes.
20
67
#[ must_use = "method returns a new vector and does not mutate the original value" ]
@@ -206,6 +253,24 @@ macro_rules! impl_trait {
206
253
type Mask = Mask <<$mask_ty as SimdElement >:: Mask , LANES >;
207
254
type Scalar = $ty;
208
255
type Bits = Simd <$bits_ty, LANES >;
256
+ type Cast <T : SimdElement > = Simd <T , LANES >;
257
+
258
+ #[ inline]
259
+ fn cast<T : SimdCast >( self ) -> Self :: Cast <T >
260
+ {
261
+ // Safety: supported types are guaranteed by SimdCast
262
+ unsafe { intrinsics:: simd_as( self ) }
263
+ }
264
+
265
+ #[ inline]
266
+ #[ cfg_attr( miri, track_caller) ] // even without panics, this helps for Miri backtraces
267
+ unsafe fn to_int_unchecked<I : SimdCast >( self ) -> Self :: Cast <I >
268
+ where
269
+ Self :: Scalar : core:: convert:: FloatToInt <I >,
270
+ {
271
+ // Safety: supported types are guaranteed by SimdCast, the caller is responsible for the extra invariants
272
+ unsafe { intrinsics:: simd_cast( self ) }
273
+ }
209
274
210
275
#[ inline]
211
276
fn to_bits( self ) -> Simd <$bits_ty, LANES > {
0 commit comments