1//! `x86_64`'s Streaming SIMD Extensions 2 (SSE2)
2
3use crate::core_arch::x86::*;
4
5#[cfg(test)]
6use stdarch_test::assert_instr;
7
8#[allow(improper_ctypes)]
9unsafe extern "C" {
10 #[link_name = "llvm.x86.sse2.cvtsd2si64"]
11 unsafefn cvtsd2si64(a: __m128d) -> i64;
12 #[link_name = "llvm.x86.sse2.cvttsd2si64"]
13 unsafefn cvttsd2si64(a: __m128d) -> i64;
14}
15
16/// Converts the lower double-precision (64-bit) floating-point element in a to
17/// a 64-bit integer.
18///
19/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsd_si64)
20#[inline]
21#[target_feature(enable = "sse2")]
22#[cfg_attr(test, assert_instr(cvtsd2si))]
23#[stable(feature = "simd_x86", since = "1.27.0")]
24pub fn _mm_cvtsd_si64(a: __m128d) -> i64 {
25 unsafe { cvtsd2si64(a) }
26}
27
28/// Alias for `_mm_cvtsd_si64`
29///
30/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsd_si64x)
31#[inline]
32#[target_feature(enable = "sse2")]
33#[cfg_attr(test, assert_instr(cvtsd2si))]
34#[stable(feature = "simd_x86", since = "1.27.0")]
35pub fn _mm_cvtsd_si64x(a: __m128d) -> i64 {
36 _mm_cvtsd_si64(a)
37}
38
39/// Converts the lower double-precision (64-bit) floating-point element in `a`
40/// to a 64-bit integer with truncation.
41///
42/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttsd_si64)
43#[inline]
44#[target_feature(enable = "sse2")]
45#[cfg_attr(test, assert_instr(cvttsd2si))]
46#[stable(feature = "simd_x86", since = "1.27.0")]
47pub fn _mm_cvttsd_si64(a: __m128d) -> i64 {
48 unsafe { cvttsd2si64(a) }
49}
50
51/// Alias for `_mm_cvttsd_si64`
52///
53/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttsd_si64x)
54#[inline]
55#[target_feature(enable = "sse2")]
56#[cfg_attr(test, assert_instr(cvttsd2si))]
57#[stable(feature = "simd_x86", since = "1.27.0")]
58pub fn _mm_cvttsd_si64x(a: __m128d) -> i64 {
59 _mm_cvttsd_si64(a)
60}
61
62/// Stores a 64-bit integer value in the specified memory location.
63/// To minimize caching, the data is flagged as non-temporal (unlikely to be
64/// used again soon).
65///
66/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_stream_si64)
67///
68/// # Safety of non-temporal stores
69///
70/// After using this intrinsic, but before any other access to the memory that this intrinsic
71/// mutates, a call to [`_mm_sfence`] must be performed by the thread that used the intrinsic. In
72/// particular, functions that call this intrinsic should generally call `_mm_sfence` before they
73/// return.
74///
75/// See [`_mm_sfence`] for details.
76#[inline]
77#[target_feature(enable = "sse2")]
78#[cfg_attr(test, assert_instr(movnti))]
79#[stable(feature = "simd_x86", since = "1.27.0")]
80pub unsafe fn _mm_stream_si64(mem_addr: *mut i64, a: i64) {
81 crate::arch::asm!(
82 vps!("movnti", ",{a}"),
83 p = in(reg) mem_addr,
84 a = in(reg) a,
85 options(nostack, preserves_flags),
86 );
87}
88
89/// Returns a vector whose lowest element is `a` and all higher elements are
90/// `0`.
91///
92/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi64_si128)
93#[inline]
94#[target_feature(enable = "sse2")]
95#[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(movq))]
96#[stable(feature = "simd_x86", since = "1.27.0")]
97pub fn _mm_cvtsi64_si128(a: i64) -> __m128i {
98 _mm_set_epi64x(e1:0, e0:a)
99}
100
101/// Returns a vector whose lowest element is `a` and all higher elements are
102/// `0`.
103///
104/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi64x_si128)
105#[inline]
106#[target_feature(enable = "sse2")]
107#[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(movq))]
108#[stable(feature = "simd_x86", since = "1.27.0")]
109pub fn _mm_cvtsi64x_si128(a: i64) -> __m128i {
110 _mm_cvtsi64_si128(a)
111}
112
113/// Returns the lowest element of `a`.
114///
115/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi128_si64)
116#[inline]
117#[target_feature(enable = "sse2")]
118#[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(movq))]
119#[stable(feature = "simd_x86", since = "1.27.0")]
120pub fn _mm_cvtsi128_si64(a: __m128i) -> i64 {
121 unsafe { simd_extract!(a.as_i64x2(), 0) }
122}
123
124/// Returns the lowest element of `a`.
125///
126/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi128_si64x)
127#[inline]
128#[target_feature(enable = "sse2")]
129#[cfg_attr(all(test, not(target_env = "msvc")), assert_instr(movq))]
130#[stable(feature = "simd_x86", since = "1.27.0")]
131pub fn _mm_cvtsi128_si64x(a: __m128i) -> i64 {
132 _mm_cvtsi128_si64(a)
133}
134
135/// Returns `a` with its lower element replaced by `b` after converting it to
136/// an `f64`.
137///
138/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi64_sd)
139#[inline]
140#[target_feature(enable = "sse2")]
141#[cfg_attr(test, assert_instr(cvtsi2sd))]
142#[stable(feature = "simd_x86", since = "1.27.0")]
143pub fn _mm_cvtsi64_sd(a: __m128d, b: i64) -> __m128d {
144 unsafe { simd_insert!(a, 0, b as f64) }
145}
146
147/// Returns `a` with its lower element replaced by `b` after converting it to
148/// an `f64`.
149///
150/// [Intel's documentation](https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi64x_sd)
151#[inline]
152#[target_feature(enable = "sse2")]
153#[cfg_attr(test, assert_instr(cvtsi2sd))]
154#[stable(feature = "simd_x86", since = "1.27.0")]
155pub fn _mm_cvtsi64x_sd(a: __m128d, b: i64) -> __m128d {
156 _mm_cvtsi64_sd(a, b)
157}
158
159#[cfg(test)]
160mod tests {
161 use crate::core_arch::arch::x86_64::*;
162 use std::boxed;
163 use std::ptr;
164 use stdarch_test::simd_test;
165
166 #[simd_test(enable = "sse2")]
167 unsafe fn test_mm_cvtsd_si64() {
168 let r = _mm_cvtsd_si64(_mm_setr_pd(-2.0, 5.0));
169 assert_eq!(r, -2_i64);
170
171 let r = _mm_cvtsd_si64(_mm_setr_pd(f64::MAX, f64::MIN));
172 assert_eq!(r, i64::MIN);
173 }
174
175 #[simd_test(enable = "sse2")]
176 unsafe fn test_mm_cvtsd_si64x() {
177 let r = _mm_cvtsd_si64x(_mm_setr_pd(f64::NAN, f64::NAN));
178 assert_eq!(r, i64::MIN);
179 }
180
181 #[simd_test(enable = "sse2")]
182 unsafe fn test_mm_cvttsd_si64() {
183 let a = _mm_setr_pd(-1.1, 2.2);
184 let r = _mm_cvttsd_si64(a);
185 assert_eq!(r, -1_i64);
186 }
187
188 #[simd_test(enable = "sse2")]
189 unsafe fn test_mm_cvttsd_si64x() {
190 let a = _mm_setr_pd(f64::NEG_INFINITY, f64::NAN);
191 let r = _mm_cvttsd_si64x(a);
192 assert_eq!(r, i64::MIN);
193 }
194
195 #[simd_test(enable = "sse2")]
196 // Miri cannot support this until it is clear how it fits in the Rust memory model
197 // (non-temporal store)
198 #[cfg_attr(miri, ignore)]
199 unsafe fn test_mm_stream_si64() {
200 let a: i64 = 7;
201 let mut mem = boxed::Box::<i64>::new(-1);
202 _mm_stream_si64(ptr::addr_of_mut!(*mem), a);
203 assert_eq!(a, *mem);
204 }
205
206 #[simd_test(enable = "sse2")]
207 unsafe fn test_mm_cvtsi64_si128() {
208 let r = _mm_cvtsi64_si128(5);
209 assert_eq_m128i(r, _mm_setr_epi64x(5, 0));
210 }
211
212 #[simd_test(enable = "sse2")]
213 unsafe fn test_mm_cvtsi128_si64() {
214 let r = _mm_cvtsi128_si64(_mm_setr_epi64x(5, 0));
215 assert_eq!(r, 5);
216 }
217
218 #[simd_test(enable = "sse2")]
219 unsafe fn test_mm_cvtsi64_sd() {
220 let a = _mm_set1_pd(3.5);
221 let r = _mm_cvtsi64_sd(a, 5);
222 assert_eq_m128d(r, _mm_setr_pd(5.0, 3.5));
223 }
224}
225