Skip to main content

pulp/x86/
v1.rs

1use super::*;
2
3// https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
4simd_type!({
5	/// SSE instruction set.
6	#[allow(missing_docs)]
7	pub struct V1 {
8		pub sse: f!("sse"),
9		pub sse2: f!("sse2"),
10		pub fxsr: f!("fxsr"),
11	}
12});
13
14impl Seal for V1 {}
15
16impl V1 {
17	binop_128_nosign!(sse: add, "Computes `a + b` for each lane of `a` and `b`.", f32 x 4);
18
19	binop_128_nosign!(sse2: add, "Adds the elements of each lane of `a` and `b`.", f64 x 2);
20
21	binop_128_nosign!(sse2: add, "Adds the elements of each lane of `a` and `b`, with wrapping on overflow.", wrapping_add, u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, u64 x 2, i64 x 2);
22
23	binop_128!(sse: and, "Returns `a & b` for each bit in `a` and `b`.", f32 x 4);
24
25	binop_128!(sse2: and, "Returns `a & b` for each bit in `a` and `b`.", f64 x 2);
26
27	binop_128_full!(sse2: and, "Returns `a & b` for each bit in `a` and `b`.", m8 x 16, u8 x 16, i8 x 16, m16 x 8, u16 x 8, i16 x 8, m32 x 4, u32 x 4, i32 x 4, m64 x 2, u64 x 2, i64 x 2);
28
29	binop_128!(sse: andnot, "Returns `!a & b` for each bit in `a` and `b`.", f32 x 4);
30
31	binop_128!(sse2: andnot, "Returns `!a & b` for each bit in `a` and `b`.", f64 x 2);
32
33	binop_128_full!(sse2: andnot, "Returns `!a & b` for each bit in `a` and `b`.", m8 x 16, u8 x 16, i8 x 16, m16 x 8, u16 x 8, i16 x 8, m32 x 4, u32 x 4, i32 x 4, m64 x 2, u64 x 2, i64 x 2);
34
35	binop_128!(sse2: avg, "Computes `average(a, b)` for each lane of `a` and `b`.", average, u8 x 16, u16 x 8);
36
37	binop_128_nosign!(sse: cmpeq, "Compares the elements in each lane of `a` and `b` for equality.", cmp_eq, f32 x 4 => m32);
38
39	binop_128_nosign!(sse2: cmpeq, "Compares the elements in each lane of `a` and `b` for equality.", cmp_eq, m8 x 16 => m8, u8 x 16 => m8, i8 x 16 => m8, m16 x 8 => m16, u16 x 8 => m16, i16 x 8 => m16, m32 x 4 => m32, u32 x 4 => m32, i32 x 4 => m32, f64 x 2 => m64);
40
41	binop_128!(sse: cmpge, "Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.", cmp_ge, f32 x 4 => m32);
42
43	binop_128!(sse2: cmpge, "Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.", cmp_ge, f64 x 2 => m64);
44
45	binop_128!(sse: cmpgt, "Compares the elements in each lane of `a` and `b` for greater-than.", cmp_gt, f32 x 4 => m32);
46
47	binop_128!(sse2: cmpgt, "Compares the elements in each lane of `a` and `b` for equality.", cmp_gt, i8 x 16 => m8, i16 x 8 => m16, i32 x 4 => m32, f64 x 2 => m64);
48
49	binop_128!(sse: cmplt, "Compares the elements in each lane of `a` and `b` for greater-than.", cmp_lt, f32 x 4 => m32);
50
51	binop_128!(sse2: cmplt, "Compares the elements in each lane of `a` and `b` for less-than.", cmp_lt, i8 x 16 => m8, i16 x 8 => m16, i32 x 4 => m32, f64 x 2 => m64);
52
53	binop_128!(sse: cmple, "Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.", cmp_le, f32 x 4 => m32);
54
55	binop_128!(sse2: cmple, "Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.", cmp_le, f64 x 2 => m64);
56
57	binop_128!(sse: cmpneq, "Compares the elements in each lane of `a` and `b` for inequality.", cmp_not_eq, f32 x 4 => m32);
58
59	binop_128!(sse2: cmpneq, "Compares the elements in each lane of `a` and `b` for inequality.", cmp_not_eq, f64 x 2 => m64);
60
61	binop_128!(sse: cmpnge, "Compares the elements in each lane of `a` and `b` for not-greater-than-or-equal.", cmp_not_ge, f32 x 4 => m32);
62
63	binop_128!(sse2: cmpnge, "Compares the elements in each lane of `a` and `b` for not-greater-than-or-equal.", cmp_not_ge, f64 x 2 => m64);
64
65	binop_128!(sse: cmpngt, "Compares the elements in each lane of `a` and `b` for not-greater-than.", cmp_not_gt, f32 x 4 => m32);
66
67	binop_128!(sse2: cmpngt, "Compares the elements in each lane of `a` and `b` for not-greater-than.", cmp_not_gt, f64 x 2 => m64);
68
69	binop_128!(sse: cmpnle, "Compares the elements in each lane of `a` and `b` for not-less-than-or-equal.", cmp_not_le, f32 x 4 => m32);
70
71	binop_128!(sse2: cmpnle, "Compares the elements in each lane of `a` and `b` for not-less-than-or-equal.", cmp_not_le, f64 x 2 => m64);
72
73	binop_128!(sse: cmpnlt, "Compares the elements in each lane of `a` and `b` for not-less-than.", cmp_not_lt, f32 x 4 => m32);
74
75	binop_128!(sse2: cmpnlt, "Compares the elements in each lane of `a` and `b` for not-less-than.", cmp_not_lt, f64 x 2 => m64);
76
77	binop_128!(sse: div, "Divides the elements of each lane of `a` and `b`.", f32 x 4);
78
79	binop_128!(sse2: div, "Divides the elements of each lane of `a` and `b`.", f64 x 2);
80
81	binop_128!(sse: max, "Computes `max(a, b)`. for each lane in `a` and `b`.", f32 x 4);
82
83	binop_128!(sse2: max, "Computes `max(a, b)`. for each lane in `a` and `b`.", u8 x 16, i16 x 8, f64 x 2);
84
85	binop_128!(sse: min, "Computes `max(a, b)`. for each lane in `a` and `b`.", f32 x 4);
86
87	binop_128!(sse2: min, "Computes `max(a, b)`. for each lane in `a` and `b`.", u8 x 16, i16 x 8, f64 x 2);
88
89	binop_128!(sse: mul, "Computes `a * b` for each lane in `a` and `b`.", f32 x 4);
90
91	binop_128!(sse2: mul, "Computes `a * b` for each lane in `a` and `b`.", f64 x 2);
92
93	binop_128_nosign!(sse2: mullo, "Computes `a * b` for each lane in `a` and `b`, with wrapping overflow.", wrapping_mul, u16 x 8, i16 x 8);
94
95	binop_128!(sse: or, "Returns `a | b` for each bit in `a` and `b`.", f32 x 4);
96
97	binop_128!(sse2: or, "Returns `a | b` for each bit in `a` and `b`.", f64 x 2);
98
99	binop_128_full!(sse2: or, "Returns `a | b` for each bit in `a` and `b`.", m8 x 16, u8 x 16, i8 x 16, m16 x 8, u16 x 8, i16 x 8, m32 x 4, u32 x 4, i32 x 4, m64 x 2, u64 x 2, i64 x 2);
100
101	binop_128!(sse2: adds, "Adds the elements of each lane of `a` and `b`, with saturation.", saturating_add, u8 x 16, i8 x 16, u16 x 8, i16 x 8);
102
103	binop_128!(sse2: subs, "Subtracts the elements of each lane of `a` and `b`, with saturation.", saturating_sub, u8 x 16, i8 x 16, u16 x 8, i16 x 8);
104
105	binop_128_nosign!(sse: sub, "Subtracts the elements of each lane of `a` and `b`.", f32 x 4);
106
107	binop_128_nosign!(sse2: sub, "Subtracts the elements of each lane of `a` and `b`.", f64 x 2);
108
109	binop_128_nosign!(sse2: sub, "Subtracts the elements of each lane of `a` and `b`, with wrapping overflow.", wrapping_sub, u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, u64 x 2, i64 x 2);
110
111	binop_128!(sse: xor, "Returns `a ^ b` for each bit in `a` and `b`.", f32 x 4);
112
113	binop_128!(sse2: xor, "Returns `a ^ b` for each bit in `a` and `b`.", f64 x 2);
114
115	binop_128_full!(sse2: xor, "Returns `a ^ b` for each bit in `a` and `b`.", m8 x 16, u8 x 16, i8 x 16, m16 x 8, u16 x 8, i16 x 8, m32 x 4, u32 x 4, i32 x 4, m64 x 2, u64 x 2, i64 x 2);
116
117	/// Computes `abs(a)` for each lane of `a`.
118	#[inline(always)]
119	pub fn abs_f32x4(self, a: f32x4) -> f32x4 {
120		self.and_f32x4(a, cast!(self.splat_u32x4((1 << 31) - 1)))
121	}
122
123	/// Computes `abs(a)` for each lane of `a`.
124	#[inline(always)]
125	pub fn abs_f64x2(self, a: f64x2) -> f64x2 {
126		self.and_f64x2(a, cast!(self.splat_u64x2((1 << 63) - 1)))
127	}
128
129	/// Computes the approximate reciprocal of the elements of each lane of `a`.
130	#[inline(always)]
131	pub fn approx_reciprocal_f32x4(self, a: f32x4) -> f32x4 {
132		cast!(self.sse._mm_rcp_ps(cast!(a)))
133	}
134
135	/// Computes the approximate reciprocal of the square roots of the elements of each lane of `a`.
136	#[inline(always)]
137	pub fn approx_reciprocal_sqrt_f32x4(self, a: f32x4) -> f32x4 {
138		cast!(self.sse._mm_rsqrt_ps(cast!(a)))
139	}
140
141	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
142	#[inline(always)]
143	pub fn cmp_ge_i16x8(self, a: i16x8, b: i16x8) -> m16x8 {
144		self.not_m16x8(self.cmp_lt_i16x8(a, b))
145	}
146
147	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
148	#[inline(always)]
149	pub fn cmp_ge_i32x4(self, a: i32x4, b: i32x4) -> m32x4 {
150		self.not_m32x4(self.cmp_lt_i32x4(a, b))
151	}
152
153	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
154	#[inline(always)]
155	pub fn cmp_ge_i8x16(self, a: i8x16, b: i8x16) -> m8x16 {
156		self.not_m8x16(self.cmp_lt_i8x16(a, b))
157	}
158
159	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
160	#[inline(always)]
161	pub fn cmp_ge_u16x8(self, a: u16x8, b: u16x8) -> m16x8 {
162		self.not_m16x8(self.cmp_lt_u16x8(a, b))
163	}
164
165	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
166	#[inline(always)]
167	pub fn cmp_ge_u32x4(self, a: u32x4, b: u32x4) -> m32x4 {
168		self.not_m32x4(self.cmp_lt_u32x4(a, b))
169	}
170
171	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
172	#[inline(always)]
173	pub fn cmp_ge_u8x16(self, a: u8x16, b: u8x16) -> m8x16 {
174		self.not_m8x16(self.cmp_lt_u8x16(a, b))
175	}
176
177	/// Compares the elements in each lane of `a` and `b` for greater-than.
178	#[inline(always)]
179	pub fn cmp_gt_u16x8(self, a: u16x8, b: u16x8) -> m16x8 {
180		let k = self.splat_u16x8(0x8000);
181		self.cmp_gt_i16x8(cast!(self.xor_u16x8(a, k)), cast!(self.xor_u16x8(b, k)))
182	}
183
184	/// Compares the elements in each lane of `a` and `b` for greater-than.
185	#[inline(always)]
186	pub fn cmp_gt_u32x4(self, a: u32x4, b: u32x4) -> m32x4 {
187		let k = self.splat_u32x4(0x80000000);
188		self.cmp_gt_i32x4(cast!(self.xor_u32x4(a, k)), cast!(self.xor_u32x4(b, k)))
189	}
190
191	/// Compares the elements in each lane of `a` and `b` for greater-than.
192	#[inline(always)]
193	pub fn cmp_gt_u8x16(self, a: u8x16, b: u8x16) -> m8x16 {
194		let k = self.splat_u8x16(0x80);
195		self.cmp_gt_i8x16(cast!(self.xor_u8x16(a, k)), cast!(self.xor_u8x16(b, k)))
196	}
197
198	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
199	#[inline(always)]
200	pub fn cmp_le_i16x8(self, a: i16x8, b: i16x8) -> m16x8 {
201		self.not_m16x8(self.cmp_gt_i16x8(a, b))
202	}
203
204	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
205	#[inline(always)]
206	pub fn cmp_le_i32x4(self, a: i32x4, b: i32x4) -> m32x4 {
207		self.not_m32x4(self.cmp_gt_i32x4(a, b))
208	}
209
210	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
211	#[inline(always)]
212	pub fn cmp_le_i8x16(self, a: i8x16, b: i8x16) -> m8x16 {
213		self.not_m8x16(self.cmp_gt_i8x16(a, b))
214	}
215
216	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
217	#[inline(always)]
218	pub fn cmp_le_u16x8(self, a: u16x8, b: u16x8) -> m16x8 {
219		self.not_m16x8(self.cmp_gt_u16x8(a, b))
220	}
221
222	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
223	#[inline(always)]
224	pub fn cmp_le_u32x4(self, a: u32x4, b: u32x4) -> m32x4 {
225		self.not_m32x4(self.cmp_gt_u32x4(a, b))
226	}
227
228	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
229	#[inline(always)]
230	pub fn cmp_le_u8x16(self, a: u8x16, b: u8x16) -> m8x16 {
231		self.not_m8x16(self.cmp_gt_u8x16(a, b))
232	}
233
234	/// Compares the elements in each lane of `a` and `b` for less-than.
235	#[inline(always)]
236	pub fn cmp_lt_u16x8(self, a: u16x8, b: u16x8) -> m16x8 {
237		let k = self.splat_u16x8(0x8000);
238		self.cmp_lt_i16x8(cast!(self.xor_u16x8(a, k)), cast!(self.xor_u16x8(b, k)))
239	}
240
241	/// Compares the elements in each lane of `a` and `b` for less-than.
242	#[inline(always)]
243	pub fn cmp_lt_u32x4(self, a: u32x4, b: u32x4) -> m32x4 {
244		let k = self.splat_u32x4(0x80000000);
245		self.cmp_lt_i32x4(cast!(self.xor_u32x4(a, k)), cast!(self.xor_u32x4(b, k)))
246	}
247
248	/// Compares the elements in each lane of `a` and `b` for less-than.
249	#[inline(always)]
250	pub fn cmp_lt_u8x16(self, a: u8x16, b: u8x16) -> m8x16 {
251		let k = self.splat_u8x16(0x80);
252		self.cmp_lt_i8x16(cast!(self.xor_u8x16(a, k)), cast!(self.xor_u8x16(b, k)))
253	}
254
255	/// Converts a `f32x4` to `f64x2`, elementwise, while truncating the extra elements.
256	#[inline(always)]
257	pub fn convert_f32x4_to_f64x2(self, a: f32x4) -> f64x2 {
258		cast!(self.sse2._mm_cvtps_pd(cast!(a)))
259	}
260
261	/// Converts a `f32x4` to `i32x4`, elementwise.
262	#[inline(always)]
263	pub fn convert_f32x4_to_i32x4(self, a: f32x4) -> i32x4 {
264		cast!(self.sse2._mm_cvttps_epi32(cast!(a)))
265	}
266
267	/// Converts a `f64x2` to `f32x4`, elementwise, filling the remaining elements with zeros.
268	#[inline(always)]
269	pub fn convert_f64x2_to_f32x4(self, a: f64x2) -> f32x4 {
270		cast!(self.sse2._mm_cvtpd_ps(cast!(a)))
271	}
272
273	/// Converts a `f64x2` to `i32x4`, elementwise.
274	#[inline(always)]
275	pub fn convert_f64x2_to_i32x4(self, a: f64x2) -> i32x4 {
276		cast!(self.sse2._mm_cvttpd_epi32(cast!(a)))
277	}
278
279	/// Converts a `i16x8` to `u16x8`, elementwise.
280	#[inline(always)]
281	pub fn convert_i16x8_to_u16x8(self, a: i16x8) -> u16x8 {
282		cast!(a)
283	}
284
285	/// Converts a `i32x4` to `f32x4`, elementwise.
286	#[inline(always)]
287	pub fn convert_i32x4_to_f32x4(self, a: i32x4) -> f32x4 {
288		cast!(self.sse2._mm_cvtepi32_ps(cast!(a)))
289	}
290
291	/// Converts a `i32x4` to `f64x2`, elementwise, while truncating the extra elements.
292	#[inline(always)]
293	pub fn convert_i32x4_to_f64x2(self, a: i32x4) -> f64x2 {
294		cast!(self.sse2._mm_cvtepi32_pd(cast!(a)))
295	}
296
297	/// Converts a `i32x4` to `u32x4`, elementwise.
298	#[inline(always)]
299	pub fn convert_i32x4_to_u32x4(self, a: i32x4) -> u32x4 {
300		cast!(a)
301	}
302
303	/// Converts a `i8x16` to `u8x16`, elementwise.
304	#[inline(always)]
305	pub fn convert_i8x16_to_u8x16(self, a: i8x16) -> u8x16 {
306		cast!(a)
307	}
308
309	/// Converts a `u16x8` to `i16x8`, elementwise.
310	#[inline(always)]
311	pub fn convert_u16x8_to_i16x8(self, a: u16x8) -> i16x8 {
312		cast!(a)
313	}
314
315	/// Converts a `u32x4` to `i32x4`, elementwise.
316	#[inline(always)]
317	pub fn convert_u32x4_to_i32x4(self, a: u32x4) -> i32x4 {
318		cast!(a)
319	}
320
321	/// Converts a `u8x16` to `i8x16`, elementwise.
322	#[inline(always)]
323	pub fn convert_u8x16_to_i8x16(self, a: u8x16) -> i8x16 {
324		cast!(a)
325	}
326
327	/// Checks if the elements in each lane of `a` are NaN.
328	#[inline(always)]
329	pub fn is_nan_f32x4(self, a: f32x4) -> m32x4 {
330		cast!(self.sse._mm_cmpunord_ps(cast!(a), cast!(a)))
331	}
332
333	/// Checks if the elements in each lane of `a` are NaN.
334	#[inline(always)]
335	pub fn is_nan_f64x2(self, a: f64x2) -> m64x2 {
336		cast!(self.sse2._mm_cmpunord_pd(cast!(a), cast!(a)))
337	}
338
339	/// Checks if the elements in each lane of `a` are not NaN.
340	#[inline(always)]
341	pub fn is_not_nan_f32x4(self, a: f32x4) -> m32x4 {
342		cast!(self.sse._mm_cmpord_ps(cast!(a), cast!(a)))
343	}
344
345	/// Checks if the elements in each lane of `a` are not NaN.
346	#[inline(always)]
347	pub fn is_not_nan_f64x2(self, a: f64x2) -> m64x2 {
348		cast!(self.sse2._mm_cmpord_pd(cast!(a), cast!(a)))
349	}
350
351	/// See [_mm_madd_epi16].
352	///
353	/// [_mm_madd_epi16]: core::arch::x86_64::_mm_madd_epi16
354	#[inline(always)]
355	pub fn multiply_wrapping_add_adjacent_i16x8(self, a: i16x8, b: i16x8) -> i32x4 {
356		cast!(self.sse2._mm_madd_epi16(cast!(a), cast!(b)))
357	}
358
359	/// Returns `!a` for each bit in a.
360	#[inline(always)]
361	pub fn not_i16x8(self, a: i16x8) -> i16x8 {
362		self.xor_i16x8(a, self.splat_i16x8(!0))
363	}
364
365	/// Returns `!a` for each bit in a.
366	#[inline(always)]
367	pub fn not_i32x4(self, a: i32x4) -> i32x4 {
368		self.xor_i32x4(a, self.splat_i32x4(!0))
369	}
370
371	/// Returns `!a` for each bit in a.
372	#[inline(always)]
373	pub fn not_i64x2(self, a: i64x2) -> i64x2 {
374		self.xor_i64x2(a, self.splat_i64x2(!0))
375	}
376
377	/// Returns `!a` for each bit in a.
378	#[inline(always)]
379	pub fn not_i8x16(self, a: i8x16) -> i8x16 {
380		self.xor_i8x16(a, self.splat_i8x16(!0))
381	}
382
383	/// Returns `!a` for each bit in a.
384	#[inline(always)]
385	pub fn not_m16x8(self, a: m16x8) -> m16x8 {
386		self.xor_m16x8(a, self.splat_m16x8(m16::new(true)))
387	}
388
389	/// Returns `!a` for each bit in a.
390	#[inline(always)]
391	pub fn not_m32x4(self, a: m32x4) -> m32x4 {
392		self.xor_m32x4(a, self.splat_m32x4(m32::new(true)))
393	}
394
395	/// Returns `!a` for each bit in a.
396	#[inline(always)]
397	pub fn not_m64x2(self, a: m64x2) -> m64x2 {
398		self.xor_m64x2(a, self.splat_m64x2(m64::new(true)))
399	}
400
401	/// Returns `!a` for each bit in a.
402	#[inline(always)]
403	pub fn not_m8x16(self, a: m8x16) -> m8x16 {
404		self.xor_m8x16(a, self.splat_m8x16(m8::new(true)))
405	}
406
407	/// Returns `!a` for each bit in a.
408	#[inline(always)]
409	pub fn not_u16x8(self, a: u16x8) -> u16x8 {
410		self.xor_u16x8(a, self.splat_u16x8(!0))
411	}
412
413	/// Returns `!a` for each bit in a.
414	#[inline(always)]
415	pub fn not_u32x4(self, a: u32x4) -> u32x4 {
416		self.xor_u32x4(a, self.splat_u32x4(!0))
417	}
418
419	/// Returns `!a` for each bit in a.
420	#[inline(always)]
421	pub fn not_u64x2(self, a: u64x2) -> u64x2 {
422		self.xor_u64x2(a, self.splat_u64x2(!0))
423	}
424
425	/// Returns `!a` for each bit in a.
426	#[inline(always)]
427	pub fn not_u8x16(self, a: u8x16) -> u8x16 {
428		self.xor_u8x16(a, self.splat_u8x16(!0))
429	}
430
431	/// See [_mm_packs_epi16].
432	///
433	/// [_mm_packs_epi16]: core::arch::x86_64::_mm_packs_epi16
434	#[inline(always)]
435	pub fn pack_with_signed_saturation_i16x8(self, a: i16x8, b: i16x8) -> i8x16 {
436		cast!(self.sse2._mm_packs_epi16(cast!(a), cast!(b)))
437	}
438
439	/// See [_mm_packs_epi32].
440	///
441	/// [_mm_packs_epi32]: core::arch::x86_64::_mm_packs_epi32
442	#[inline(always)]
443	pub fn pack_with_signed_saturation_i32x4(self, a: i32x4, b: i32x4) -> i16x8 {
444		cast!(self.sse2._mm_packs_epi32(cast!(a), cast!(b)))
445	}
446
447	/// See [_mm_packus_epi16].
448	///
449	/// [_mm_packus_epi16]: core::arch::x86_64::_mm_packus_epi16
450	#[inline(always)]
451	pub fn pack_with_unsigned_saturation_i16x8(self, a: i16x8, b: i16x8) -> u8x16 {
452		cast!(self.sse2._mm_packus_epi16(cast!(a), cast!(b)))
453	}
454
455	#[inline(always)]
456	pub fn reduce_max_c32x2(self, a: f32x4) -> c32 {
457		// a0 a1 a2 a3
458		let a: __m128 = cast!(a);
459		// a2 a3 a2 a3
460		let hi = self.sse._mm_movehl_ps(a, a);
461
462		// a0+a2 a1+a3 _ _
463		let r0 = self.sse._mm_max_ps(a, hi);
464
465		cast!(self.sse2._mm_cvtsd_f64(cast!(r0)))
466	}
467
468	#[inline(always)]
469	pub fn reduce_max_c64x1(self, a: f64x2) -> c64 {
470		cast!(a)
471	}
472
473	#[inline(always)]
474	pub fn reduce_max_f32x4(self, a: f32x4) -> f32 {
475		let a: __m128 = cast!(a);
476		let hi = self.sse._mm_movehl_ps(a, a);
477		let r0 = self.sse._mm_max_ps(a, hi);
478		let r0_shuffled = self.sse._mm_shuffle_ps::<0b0001>(r0, r0);
479		let r = self.sse._mm_max_ss(r0, r0_shuffled);
480		self.sse._mm_cvtss_f32(r)
481	}
482
483	#[inline(always)]
484	pub fn reduce_max_f64x2(self, a: f64x2) -> f64 {
485		let a: __m128d = cast!(a);
486		let hi = cast!(self.sse._mm_movehl_ps(cast!(a), cast!(a)));
487		let r = self.sse2._mm_max_sd(a, hi);
488		self.sse2._mm_cvtsd_f64(r)
489	}
490
491	#[inline(always)]
492	pub fn reduce_min_c32x2(self, a: f32x4) -> c32 {
493		// a0 a1 a2 a3
494		let a: __m128 = cast!(a);
495		// a2 a3 a2 a3
496		let hi = self.sse._mm_movehl_ps(a, a);
497
498		// a0+a2 a1+a3 _ _
499		let r0 = self.sse._mm_min_ps(a, hi);
500
501		cast!(self.sse2._mm_cvtsd_f64(cast!(r0)))
502	}
503
504	#[inline(always)]
505	pub fn reduce_min_c64x1(self, a: f64x2) -> c64 {
506		cast!(a)
507	}
508
509	#[inline(always)]
510	pub fn reduce_min_f32x4(self, a: f32x4) -> f32 {
511		let a: __m128 = cast!(a);
512		let hi = self.sse._mm_movehl_ps(a, a);
513		let r0 = self.sse._mm_min_ps(a, hi);
514		let r0_shuffled = self.sse._mm_shuffle_ps::<0b0001>(r0, r0);
515		let r = self.sse._mm_min_ss(r0, r0_shuffled);
516		self.sse._mm_cvtss_f32(r)
517	}
518
519	#[inline(always)]
520	pub fn reduce_min_f64x2(self, a: f64x2) -> f64 {
521		let a: __m128d = cast!(a);
522		let hi = cast!(self.sse._mm_movehl_ps(cast!(a), cast!(a)));
523		let r = self.sse2._mm_min_sd(a, hi);
524		self.sse2._mm_cvtsd_f64(r)
525	}
526
527	#[inline(always)]
528	pub fn reduce_product_f32x4(self, a: f32x4) -> f32 {
529		let a: __m128 = cast!(a);
530		let hi = self.sse._mm_movehl_ps(a, a);
531		let r0 = self.sse._mm_mul_ps(a, hi);
532		let r0_shuffled = self.sse._mm_shuffle_ps::<0b0001>(r0, r0);
533		let r = self.sse._mm_mul_ss(r0, r0_shuffled);
534		self.sse._mm_cvtss_f32(r)
535	}
536
537	#[inline(always)]
538	pub fn reduce_product_f64x2(self, a: f64x2) -> f64 {
539		let a: __m128d = cast!(a);
540		let hi = cast!(self.sse._mm_movehl_ps(cast!(a), cast!(a)));
541		let r = self.sse2._mm_mul_sd(a, hi);
542		self.sse2._mm_cvtsd_f64(r)
543	}
544
545	#[inline(always)]
546	pub fn reduce_sum_c32x2(self, a: f32x4) -> c32 {
547		// a0 a1 a2 a3
548		let a: __m128 = cast!(a);
549		// a2 a3 a2 a3
550		let hi = self.sse._mm_movehl_ps(a, a);
551
552		// a0+a2 a1+a3 _ _
553		let r0 = self.sse._mm_add_ps(a, hi);
554
555		cast!(self.sse2._mm_cvtsd_f64(cast!(r0)))
556	}
557
558	#[inline(always)]
559	pub fn reduce_sum_c64x1(self, a: f64x2) -> c64 {
560		cast!(a)
561	}
562
563	#[inline(always)]
564	pub fn reduce_sum_f32x4(self, a: f32x4) -> f32 {
565		// a0 a1 a2 a3
566		let a: __m128 = cast!(a);
567		// a2 a3 a2 a3
568		let hi = self.sse._mm_movehl_ps(a, a);
569
570		// a0+a2 a1+a3 _ _
571		let r0 = self.sse._mm_add_ps(a, hi);
572		// a1+a3 a2+a1 _ _
573		let r0_shuffled = self.sse._mm_shuffle_ps::<0b0001>(r0, r0);
574
575		let r = self.sse._mm_add_ss(r0, r0_shuffled);
576
577		self.sse._mm_cvtss_f32(r)
578	}
579
580	#[inline(always)]
581	pub fn reduce_sum_f64x2(self, a: f64x2) -> f64 {
582		let a: __m128d = cast!(a);
583		let hi = cast!(self.sse._mm_movehl_ps(cast!(a), cast!(a)));
584		let r = self.sse2._mm_add_sd(a, hi);
585		self.sse2._mm_cvtsd_f64(r)
586	}
587
588	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
589	/// Shifting by a value greater than the bit width of the type sets the result to zero.
590	#[inline(always)]
591	pub fn shl_const_i16x8<const AMOUNT: i32>(self, a: i16x8) -> i16x8 {
592		cast!(self.sse2._mm_slli_epi16::<AMOUNT>(cast!(a)))
593	}
594
595	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
596	/// Shifting by a value greater than the bit width of the type sets the result to zero.
597	#[inline(always)]
598	pub fn shl_const_i32x4<const AMOUNT: i32>(self, a: i32x4) -> i32x4 {
599		cast!(self.sse2._mm_slli_epi32::<AMOUNT>(cast!(a)))
600	}
601
602	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
603	/// Shifting by a value greater than the bit width of the type sets the result to zero.
604	#[inline(always)]
605	pub fn shl_const_i64x2<const AMOUNT: i32>(self, a: i64x2) -> i64x2 {
606		cast!(self.sse2._mm_slli_epi64::<AMOUNT>(cast!(a)))
607	}
608
609	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
610	/// Shifting by a value greater than the bit width of the type sets the result to zero.
611	#[inline(always)]
612	pub fn shl_const_u16x8<const AMOUNT: i32>(self, a: u16x8) -> u16x8 {
613		cast!(self.sse2._mm_slli_epi16::<AMOUNT>(cast!(a)))
614	}
615
616	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
617	/// Shifting by a value greater than the bit width of the type sets the result to zero.
618	#[inline(always)]
619	pub fn shl_const_u32x4<const AMOUNT: i32>(self, a: u32x4) -> u32x4 {
620		cast!(self.sse2._mm_slli_epi32::<AMOUNT>(cast!(a)))
621	}
622
623	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
624	/// Shifting by a value greater than the bit width of the type sets the result to zero.
625	#[inline(always)]
626	pub fn shl_const_u64x2<const AMOUNT: i32>(self, a: u64x2) -> u64x2 {
627		cast!(self.sse2._mm_slli_epi64::<AMOUNT>(cast!(a)))
628	}
629
630	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
631	/// shifting in zeros.
632	/// Shifting by a value greater than the bit width of the type sets the result to zero.
633	#[inline(always)]
634	pub fn shl_i16x8(self, a: i16x8, amount: u64x2) -> i16x8 {
635		cast!(self.sse2._mm_sll_epi16(cast!(a), cast!(amount)))
636	}
637
638	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
639	/// shifting in zeros.
640	/// Shifting by a value greater than the bit width of the type sets the result to zero.
641	#[inline(always)]
642	pub fn shl_i32x4(self, a: i32x4, amount: u64x2) -> i32x4 {
643		cast!(self.sse2._mm_sll_epi32(cast!(a), cast!(amount)))
644	}
645
646	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
647	/// shifting in zeros.
648	/// Shifting by a value greater than the bit width of the type sets the result to zero.
649	#[inline(always)]
650	pub fn shl_i64x2(self, a: i64x2, amount: u64x2) -> u64x2 {
651		cast!(self.sse2._mm_sll_epi64(cast!(a), cast!(amount)))
652	}
653
654	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
655	/// shifting in zeros.
656	/// Shifting by a value greater than the bit width of the type sets the result to zero.
657	#[inline(always)]
658	pub fn shl_u16x8(self, a: u16x8, amount: u64x2) -> u16x8 {
659		cast!(self.sse2._mm_sll_epi16(cast!(a), cast!(amount)))
660	}
661
662	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
663	/// shifting in zeros.
664	/// Shifting by a value greater than the bit width of the type sets the result to zero.
665	#[inline(always)]
666	pub fn shl_u32x4(self, a: u32x4, amount: u64x2) -> u32x4 {
667		cast!(self.sse2._mm_sll_epi32(cast!(a), cast!(amount)))
668	}
669
670	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
671	/// shifting in zeros.
672	/// Shifting by a value greater than the bit width of the type sets the result to zero.
673	#[inline(always)]
674	pub fn shl_u64x2(self, a: u64x2, amount: u64x2) -> u64x2 {
675		cast!(self.sse2._mm_sll_epi64(cast!(a), cast!(amount)))
676	}
677
678	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in sign bits.
679	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
680	/// sign bit is not set, and to `-1` if the sign bit is set.
681	#[inline(always)]
682	pub fn shr_const_i16x8<const AMOUNT: i32>(self, a: i16x8) -> i16x8 {
683		cast!(self.sse2._mm_srai_epi16::<AMOUNT>(cast!(a)))
684	}
685
686	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in sign bits.
687	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
688	/// sign bit is not set, and to `-1` if the sign bit is set.
689	#[inline(always)]
690	pub fn shr_const_i32x4<const AMOUNT: i32>(self, a: i32x4) -> i32x4 {
691		cast!(self.sse2._mm_srai_epi32::<AMOUNT>(cast!(a)))
692	}
693
694	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in zeros.
695	/// Shifting by a value greater than the bit width of the type sets the result to zero.
696	#[inline(always)]
697	pub fn shr_const_u16x8<const AMOUNT: i32>(self, a: u16x8) -> u16x8 {
698		cast!(self.sse2._mm_srli_epi16::<AMOUNT>(cast!(a)))
699	}
700
701	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in zeros.
702	/// Shifting by a value greater than the bit width of the type sets the result to zero.
703	#[inline(always)]
704	pub fn shr_const_u32x4<const AMOUNT: i32>(self, a: u32x4) -> u32x4 {
705		cast!(self.sse2._mm_srli_epi32::<AMOUNT>(cast!(a)))
706	}
707
708	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in zeros.
709	/// Shifting by a value greater than the bit width of the type sets the result to zero.
710	#[inline(always)]
711	pub fn shr_const_u64x2<const AMOUNT: i32>(self, a: u64x2) -> u64x2 {
712		cast!(self.sse2._mm_srli_epi64::<AMOUNT>(cast!(a)))
713	}
714
715	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
716	/// shifting in zeros.
717	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
718	/// sign bit is not set, and to `-1` if the sign bit is set.
719	#[inline(always)]
720	pub fn shr_i16x8(self, a: i16x8, amount: u64x2) -> i16x8 {
721		cast!(self.sse2._mm_sra_epi16(cast!(a), cast!(amount)))
722	}
723
724	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
725	/// shifting in zeros.
726	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
727	/// sign bit is not set, and to `-1` if the sign bit is set.
728	#[inline(always)]
729	pub fn shr_i32x4(self, a: i32x4, amount: u64x2) -> i32x4 {
730		cast!(self.sse2._mm_sra_epi32(cast!(a), cast!(amount)))
731	}
732
733	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
734	/// shifting in zeros.
735	/// Shifting by a value greater than the bit width of the type sets the result to zero.
736	#[inline(always)]
737	pub fn shr_u16x8(self, a: u16x8, amount: u64x2) -> u16x8 {
738		cast!(self.sse2._mm_srl_epi16(cast!(a), cast!(amount)))
739	}
740
741	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
742	/// shifting in zeros.
743	/// Shifting by a value greater than the bit width of the type sets the result to zero.
744	#[inline(always)]
745	pub fn shr_u32x4(self, a: u32x4, amount: u64x2) -> u32x4 {
746		cast!(self.sse2._mm_srl_epi32(cast!(a), cast!(amount)))
747	}
748
749	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
750	/// shifting in zeros.
751	/// Shifting by a value greater than the bit width of the type sets the result to zero.
752	#[inline(always)]
753	pub fn shr_u64x2(self, a: u64x2, amount: u64x2) -> u64x2 {
754		cast!(self.sse2._mm_srl_epi64(cast!(a), cast!(amount)))
755	}
756
757	/// Returns a SIMD vector with all lanes set to the given value.
758	#[inline(always)]
759	pub fn splat_f32x4(self, value: f32) -> f32x4 {
760		cast!(self.sse._mm_set1_ps(value))
761	}
762
763	/// Returns a SIMD vector with all lanes set to the given value.
764	#[inline(always)]
765	pub fn splat_f64x2(self, value: f64) -> f64x2 {
766		cast!(self.sse2._mm_set1_pd(value))
767	}
768
769	/// Returns a SIMD vector with all lanes set to the given value.
770	#[inline(always)]
771	pub fn splat_i16x8(self, value: i16) -> i16x8 {
772		cast!(self.sse2._mm_set1_epi16(value))
773	}
774
775	/// Returns a SIMD vector with all lanes set to the given value.
776	#[inline(always)]
777	pub fn splat_i32x4(self, value: i32) -> i32x4 {
778		cast!(self.sse2._mm_set1_epi32(value))
779	}
780
781	/// Returns a SIMD vector with all lanes set to the given value.
782	#[inline(always)]
783	pub fn splat_i64x2(self, value: i64) -> i64x2 {
784		cast!(self.sse2._mm_set1_epi64x(value))
785	}
786
787	/// Returns a SIMD vector with all lanes set to the given value.
788	#[inline(always)]
789	pub fn splat_i8x16(self, value: i8) -> i8x16 {
790		cast!(self.sse2._mm_set1_epi8(value))
791	}
792
793	/// Returns a SIMD vector with all lanes set to the given value.
794	#[inline(always)]
795	pub fn splat_m16x8(self, value: m16) -> m16x8 {
796		cast!(self.sse2._mm_set1_epi16(value.0 as i16))
797	}
798
799	/// Returns a SIMD vector with all lanes set to the given value.
800	#[inline(always)]
801	pub fn splat_m32x4(self, value: m32) -> m32x4 {
802		cast!(self.sse2._mm_set1_epi32(value.0 as i32))
803	}
804
805	/// Returns a SIMD vector with all lanes set to the given value.
806	#[inline(always)]
807	pub fn splat_m64x2(self, value: m64) -> m64x2 {
808		cast!(self.sse2._mm_set1_epi64x(value.0 as i64))
809	}
810
811	/// Returns a SIMD vector with all lanes set to the given value.
812	#[inline(always)]
813	pub fn splat_m8x16(self, value: m8) -> m8x16 {
814		cast!(self.sse2._mm_set1_epi8(value.0 as i8))
815	}
816
817	/// Returns a SIMD vector with all lanes set to the given value.
818	#[inline(always)]
819	pub fn splat_u16x8(self, value: u16) -> u16x8 {
820		cast!(self.sse2._mm_set1_epi16(value as i16))
821	}
822
823	/// Returns a SIMD vector with all lanes set to the given value.
824	#[inline(always)]
825	pub fn splat_u32x4(self, value: u32) -> u32x4 {
826		cast!(self.sse2._mm_set1_epi32(value as i32))
827	}
828
829	/// Returns a SIMD vector with all lanes set to the given value.
830	#[inline(always)]
831	pub fn splat_u64x2(self, value: u64) -> u64x2 {
832		cast!(self.sse2._mm_set1_epi64x(value as i64))
833	}
834
835	/// Returns a SIMD vector with all lanes set to the given value.
836	#[inline(always)]
837	pub fn splat_u8x16(self, value: u8) -> u8x16 {
838		cast!(self.sse2._mm_set1_epi8(value as i8))
839	}
840
841	/// Computes the square roots of the elements of each lane of `a`.
842	#[inline(always)]
843	pub fn sqrt_f32x4(self, a: f32x4) -> f32x4 {
844		cast!(self.sse._mm_sqrt_ps(cast!(a)))
845	}
846
847	/// Computes the square roots of the elements of each lane of `a`.
848	#[inline(always)]
849	pub fn sqrt_f64x2(self, a: f64x2) -> f64x2 {
850		cast!(self.sse2._mm_sqrt_pd(cast!(a)))
851	}
852
853	/// See [_mm_sad_epu8].
854	///
855	/// [_mm_sad_epu8]: core::arch::x86_64::_mm_sad_epu8
856	#[inline(always)]
857	pub fn sum_of_absolute_differences_u8x16(self, a: u8x16, b: u8x16) -> u64x2 {
858		cast!(self.sse2._mm_sad_epu8(cast!(a), cast!(b)))
859	}
860
861	/// Multiplies the elements of each lane of `a` and `b`, and returns separately the low and
862	/// high bits of the result.
863	#[inline(always)]
864	pub fn widening_mul_i16x8(self, a: i16x8, b: i16x8) -> (u16x8, i16x8) {
865		(
866			cast!(self.sse2._mm_mullo_epi16(cast!(a), cast!(b))),
867			cast!(self.sse2._mm_mulhi_epi16(cast!(a), cast!(b))),
868		)
869	}
870
871	/// Multiplies the elements of each lane of `a` and `b`, and returns separately the low and
872	/// high bits of the result.
873	#[inline(always)]
874	pub fn widening_mul_u16x8(self, a: u16x8, b: u16x8) -> (u16x8, u16x8) {
875		(
876			cast!(self.sse2._mm_mullo_epi16(cast!(a), cast!(b))),
877			cast!(self.sse2._mm_mulhi_epu16(cast!(a), cast!(b))),
878		)
879	}
880}