]> git.lizzy.rs Git - rust.git/blob - library/portable-simd/crates/std_float/src/lib.rs
Rollup merge of #101425 - compiler-errors:point-at-ty-param, r=spastorino
[rust.git] / library / portable-simd / crates / std_float / src / lib.rs
1 #![cfg_attr(feature = "as_crate", no_std)] // We are std!
2 #![cfg_attr(feature = "as_crate", feature(platform_intrinsics), feature(portable_simd))]
3 #[cfg(not(feature = "as_crate"))]
4 use core::simd;
5 #[cfg(feature = "as_crate")]
6 use core_simd::simd;
7
8 use simd::{LaneCount, Simd, SupportedLaneCount};
9
10 #[cfg(feature = "as_crate")]
11 mod experimental {
12     pub trait Sealed {}
13 }
14
15 #[cfg(feature = "as_crate")]
16 use experimental as sealed;
17
18 use crate::sealed::Sealed;
19
20 // "platform intrinsics" are essentially "codegen intrinsics"
21 // each of these may be scalarized and lowered to a libm call
22 extern "platform-intrinsic" {
23     // ceil
24     fn simd_ceil<T>(x: T) -> T;
25
26     // floor
27     fn simd_floor<T>(x: T) -> T;
28
29     // round
30     fn simd_round<T>(x: T) -> T;
31
32     // trunc
33     fn simd_trunc<T>(x: T) -> T;
34
35     // fsqrt
36     fn simd_fsqrt<T>(x: T) -> T;
37
38     // fma
39     fn simd_fma<T>(x: T, y: T, z: T) -> T;
40 }
41
42 /// This trait provides a possibly-temporary implementation of float functions
43 /// that may, in the absence of hardware support, canonicalize to calling an
44 /// operating system's `math.h` dynamically-loaded library (also known as a
45 /// shared object). As these conditionally require runtime support, they
46 /// should only appear in binaries built assuming OS support: `std`.
47 ///
48 /// However, there is no reason SIMD types, in general, need OS support,
49 /// as for many architectures an embedded binary may simply configure that
50 /// support itself. This means these types must be visible in `core`
51 /// but have these functions available in `std`.
52 ///
53 /// [`f32`] and [`f64`] achieve a similar trick by using "lang items", but
54 /// due to compiler limitations, it is harder to implement this approach for
55 /// abstract data types like [`Simd`]. From that need, this trait is born.
56 ///
57 /// It is possible this trait will be replaced in some manner in the future,
58 /// when either the compiler or its supporting runtime functions are improved.
59 /// For now this trait is available to permit experimentation with SIMD float
60 /// operations that may lack hardware support, such as `mul_add`.
61 pub trait StdFloat: Sealed + Sized {
62     /// Fused multiply-add.  Computes `(self * a) + b` with only one rounding error,
63     /// yielding a more accurate result than an unfused multiply-add.
64     ///
65     /// Using `mul_add` *may* be more performant than an unfused multiply-add if the target
66     /// architecture has a dedicated `fma` CPU instruction.  However, this is not always
67     /// true, and will be heavily dependent on designing algorithms with specific target
68     /// hardware in mind.
69     #[inline]
70     #[must_use = "method returns a new vector and does not mutate the original value"]
71     fn mul_add(self, a: Self, b: Self) -> Self {
72         unsafe { simd_fma(self, a, b) }
73     }
74
75     /// Produces a vector where every lane has the square root value
76     /// of the equivalently-indexed lane in `self`
77     #[inline]
78     #[must_use = "method returns a new vector and does not mutate the original value"]
79     fn sqrt(self) -> Self {
80         unsafe { simd_fsqrt(self) }
81     }
82
83     /// Returns the smallest integer greater than or equal to each lane.
84     #[must_use = "method returns a new vector and does not mutate the original value"]
85     #[inline]
86     fn ceil(self) -> Self {
87         unsafe { simd_ceil(self) }
88     }
89
90     /// Returns the largest integer value less than or equal to each lane.
91     #[must_use = "method returns a new vector and does not mutate the original value"]
92     #[inline]
93     fn floor(self) -> Self {
94         unsafe { simd_floor(self) }
95     }
96
97     /// Rounds to the nearest integer value. Ties round toward zero.
98     #[must_use = "method returns a new vector and does not mutate the original value"]
99     #[inline]
100     fn round(self) -> Self {
101         unsafe { simd_round(self) }
102     }
103
104     /// Returns the floating point's integer value, with its fractional part removed.
105     #[must_use = "method returns a new vector and does not mutate the original value"]
106     #[inline]
107     fn trunc(self) -> Self {
108         unsafe { simd_trunc(self) }
109     }
110
111     /// Returns the floating point's fractional value, with its integer part removed.
112     #[must_use = "method returns a new vector and does not mutate the original value"]
113     fn fract(self) -> Self;
114 }
115
116 impl<const N: usize> Sealed for Simd<f32, N> where LaneCount<N>: SupportedLaneCount {}
117 impl<const N: usize> Sealed for Simd<f64, N> where LaneCount<N>: SupportedLaneCount {}
118
119 // We can safely just use all the defaults.
120 impl<const N: usize> StdFloat for Simd<f32, N>
121 where
122     LaneCount<N>: SupportedLaneCount,
123 {
124     /// Returns the floating point's fractional value, with its integer part removed.
125     #[must_use = "method returns a new vector and does not mutate the original value"]
126     #[inline]
127     fn fract(self) -> Self {
128         self - self.trunc()
129     }
130 }
131
132 impl<const N: usize> StdFloat for Simd<f64, N>
133 where
134     LaneCount<N>: SupportedLaneCount,
135 {
136     /// Returns the floating point's fractional value, with its integer part removed.
137     #[must_use = "method returns a new vector and does not mutate the original value"]
138     #[inline]
139     fn fract(self) -> Self {
140         self - self.trunc()
141     }
142 }
143
144 #[cfg(test)]
145 mod tests {
146     use super::*;
147     use simd::*;
148
149     #[test]
150     fn everything_works() {
151         let x = f32x4::from_array([0.1, 0.5, 0.6, -1.5]);
152         let x2 = x + x;
153         let _xc = x.ceil();
154         let _xf = x.floor();
155         let _xr = x.round();
156         let _xt = x.trunc();
157         let _xfma = x.mul_add(x, x);
158         let _xsqrt = x.sqrt();
159         let _ = x2.abs() * x2;
160     }
161 }