Skip to main content

pulp/x86/
v2.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 V2 {
8		pub sse: f!("sse"),
9		pub sse2: f!("sse2"),
10		pub fxsr: f!("fxsr"),
11		pub sse3: f!("sse3"),
12		pub ssse3: f!("ssse3"),
13		pub sse4_1: f!("sse4.1"),
14		pub sse4_2: f!("sse4.2"),
15		pub popcnt: f!("popcnt"),
16	}
17});
18
19impl Seal for V2 {}
20
21impl Deref for V2 {
22	type Target = V1;
23
24	#[inline(always)]
25	fn deref(&self) -> &Self::Target {
26		V1 {
27			sse: self.sse,
28			sse2: self.sse2,
29			fxsr: self.fxsr,
30		}
31		.to_ref()
32	}
33}
34
35impl V2 {
36	binop_128!(ssse3: sign, r#"Applies the sign of each element of `sign` to the corresponding lane in `a`.
37- If `sign` is zero, the corresponding element is zeroed.
38- If `sign` is positive, the corresponding element is returned as is.
39- If `sign` is negative, the corresponding element is negated."#, apply_sign, i8 x 16, i16 x 8, i32 x 4);
40
41	unop_128!(sse4_1: ceil, "Returns `ceil(a)` for each lane of `a`, rounding towards positive infinity.", f32 x 4, f64 x 2);
42
43	binop_128_nosign!(sse4_1: cmpeq, "Compares the elements in each lane of `a` and `b` for equality.", cmp_eq, m64 x 2 => m64, u64 x 2 => m64, i64 x 2 => m64);
44
45	binop_128!(sse4_2: cmpgt, "Compares the elements in each lane of `a` and `b` for equality.", cmp_gt, i64 x 2 => m64);
46
47	unop_128!(sse4_1: floor, "Rounds the elements of each lane of `a` to the nearest integer towards negative infinity.", f32 x 4, f64 x 2);
48
49	binop_128_nosign!(sse3: hadd, "[_mm_hadd_ps](core::arch::x86_64::_mm_hadd_ps)", horizontal_add_pack, f32 x 4, f64 x 2);
50
51	binop_128_nosign!(ssse3: hadd, "[_mm_hadd_ps](core::arch::x86_64::_mm_hadd_ps)", horizontal_add_pack, u16 x 8, i16 x 8, u32 x 4, i32 x 4);
52
53	binop_128_nosign!(sse3: hsub, "[_mm_hsub_ps](core::arch::x86_64::_mm_hsub_ps)", horizontal_sub_pack, f32 x 4, f64 x 2);
54
55	binop_128_nosign!(ssse3: hsub, "[_mm_hsub_ps](core::arch::x86_64::_mm_hsub_ps)", horizontal_sub_pack, u16 x 8, i16 x 8, u32 x 4, i32 x 4);
56
57	binop_128!(sse4_1: max, "Computes `max(a, b)`. for each lane in `a` and `b`.", i8 x 16, u16 x 8, u32 x 4, i32 x 4);
58
59	binop_128!(sse4_1: min, "Computes `max(a, b)`. for each lane in `a` and `b`.", i8 x 16, u16 x 8, u32 x 4, i32 x 4);
60
61	binop_128_nosign!(sse4_1: mullo, "Computes `a * b` for each lane in `a` and `b`, with wrapping overflow.", wrapping_mul, u32 x 4, i32 x 4);
62
63	binop_128!(sse3: addsub, "Alternatively subtracts and adds the elements of each lane of `a` and `b`.", subadd, f32 x 4, f64 x 2);
64
65	unop_128!(ssse3: abs, "Computes the unsigned absolute value of the elements of each lane of `a`.", unsigned_abs, i8 x 16, i16 x 8, i32 x 4);
66
67	/// Computes `abs(a)` for each lane of `a`.
68	#[inline(always)]
69	pub fn abs_f32x4(self, a: f32x4) -> f32x4 {
70		self.and_f32x4(a, cast!(self.splat_u32x4((1 << 31) - 1)))
71	}
72
73	/// Computes `abs(a)` for each lane of `a`.
74	#[inline(always)]
75	pub fn abs_f64x2(self, a: f64x2) -> f64x2 {
76		self.and_f64x2(a, cast!(self.splat_u64x2((1 << 63) - 1)))
77	}
78
79	/// Computes the approximate reciprocal of the elements of each lane of `a`.
80	#[inline(always)]
81	pub fn approx_reciprocal_f32x4(self, a: f32x4) -> f32x4 {
82		cast!(self.sse._mm_rcp_ps(cast!(a)))
83	}
84
85	/// Computes the approximate reciprocal of the square roots of the elements of each lane of `a`.
86	#[inline(always)]
87	pub fn approx_reciprocal_sqrt_f32x4(self, a: f32x4) -> f32x4 {
88		cast!(self.sse._mm_rsqrt_ps(cast!(a)))
89	}
90
91	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
92	#[inline(always)]
93	pub fn cmp_ge_i64x2(self, a: i64x2, b: i64x2) -> m64x2 {
94		self.not_m64x2(self.cmp_lt_i64x2(a, b))
95	}
96
97	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
98	#[inline(always)]
99	pub fn cmp_ge_u64x2(self, a: u64x2, b: u64x2) -> m64x2 {
100		self.not_m64x2(self.cmp_lt_u64x2(a, b))
101	}
102
103	/// Compares the elements in each lane of `a` and `b` for greater-than.
104	#[inline(always)]
105	pub fn cmp_gt_u64x2(self, a: u64x2, b: u64x2) -> m64x2 {
106		let k = self.splat_u64x2(0x8000000000000000);
107		self.cmp_gt_i64x2(cast!(self.xor_u64x2(a, k)), cast!(self.xor_u64x2(b, k)))
108	}
109
110	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
111	#[inline(always)]
112	pub fn cmp_le_i64x2(self, a: i64x2, b: i64x2) -> m64x2 {
113		self.not_m64x2(self.cmp_gt_i64x2(a, b))
114	}
115
116	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
117	#[inline(always)]
118	pub fn cmp_le_u64x2(self, a: u64x2, b: u64x2) -> m64x2 {
119		self.not_m64x2(self.cmp_gt_u64x2(a, b))
120	}
121
122	/// Compares the elements in each lane of `a` and `b` for less-than.
123	#[inline(always)]
124	pub fn cmp_lt_i64x2(self, a: i64x2, b: i64x2) -> m64x2 {
125		cast!(self.sse4_2._mm_cmpgt_epi64(cast!(b), cast!(a)))
126	}
127
128	/// Compares the elements in each lane of `a` and `b` for less-than.
129	#[inline(always)]
130	pub fn cmp_lt_u64x2(self, a: u64x2, b: u64x2) -> m64x2 {
131		let k = self.splat_u64x2(0x8000000000000000);
132		self.cmp_lt_i64x2(cast!(self.xor_u64x2(a, k)), cast!(self.xor_u64x2(b, k)))
133	}
134
135	/// Converts a `i16x8` to `i32x4`, elementwise, while truncating the extra elements.
136	#[inline(always)]
137	pub fn convert_i16x8_to_i32x4(self, a: i16x8) -> i32x4 {
138		cast!(self.sse4_1._mm_cvtepi16_epi32(cast!(a)))
139	}
140
141	/// Converts a `i16x8` to `i64x2`, elementwise, while truncating the extra elements.
142	#[inline(always)]
143	pub fn convert_i16x8_to_i64x2(self, a: i16x8) -> i64x2 {
144		cast!(self.sse4_1._mm_cvtepi16_epi64(cast!(a)))
145	}
146
147	/// Converts a `i16x8` to `u32x4`, elementwise, while truncating the extra elements.
148	#[inline(always)]
149	pub fn convert_i16x8_to_u32x4(self, a: i16x8) -> u32x4 {
150		cast!(self.sse4_1._mm_cvtepi16_epi32(cast!(a)))
151	}
152
153	/// Converts a `i16x8` to `u64x2`, elementwise, while truncating the extra elements.
154	#[inline(always)]
155	pub fn convert_i16x8_to_u64x2(self, a: i16x8) -> u64x2 {
156		cast!(self.sse4_1._mm_cvtepi16_epi64(cast!(a)))
157	}
158
159	/// Converts a `i32x4` to `i64x2`, elementwise, while truncating the extra elements.
160	#[inline(always)]
161	pub fn convert_i32x4_to_i64x2(self, a: i32x4) -> i64x2 {
162		cast!(self.sse4_1._mm_cvtepi32_epi64(cast!(a)))
163	}
164
165	/// Converts a `i32x4` to `u64x2`, elementwise, while truncating the extra elements.
166	#[inline(always)]
167	pub fn convert_i32x4_to_u64x2(self, a: i32x4) -> u64x2 {
168		cast!(self.sse4_1._mm_cvtepi32_epi64(cast!(a)))
169	}
170
171	/// Converts a `i8x16` to `i16x8`, elementwise, while truncating the extra elements.
172	#[inline(always)]
173	pub fn convert_i8x16_to_i16x8(self, a: i8x16) -> i16x8 {
174		cast!(self.sse4_1._mm_cvtepi8_epi16(cast!(a)))
175	}
176
177	/// Converts a `i8x16` to `i32x4`, elementwise, while truncating the extra elements.
178	#[inline(always)]
179	pub fn convert_i8x16_to_i32x4(self, a: i8x16) -> i32x4 {
180		cast!(self.sse4_1._mm_cvtepi8_epi32(cast!(a)))
181	}
182
183	/// Converts a `i8x16` to `i64x2`, elementwise, while truncating the extra elements.
184	#[inline(always)]
185	pub fn convert_i8x16_to_i64x2(self, a: i8x16) -> i64x2 {
186		cast!(self.sse4_1._mm_cvtepi8_epi64(cast!(a)))
187	}
188
189	/// Converts a `i8x16` to `u16x8`, elementwise, while truncating the extra elements.
190	#[inline(always)]
191	pub fn convert_i8x16_to_u16x8(self, a: i8x16) -> u16x8 {
192		cast!(self.sse4_1._mm_cvtepi8_epi16(cast!(a)))
193	}
194
195	/// Converts a `i8x16` to `u32x4`, elementwise, while truncating the extra elements.
196	#[inline(always)]
197	pub fn convert_i8x16_to_u32x4(self, a: i8x16) -> u32x4 {
198		cast!(self.sse4_1._mm_cvtepi8_epi32(cast!(a)))
199	}
200
201	/// Converts a `i8x16` to `u64x2`, elementwise, while truncating the extra elements.
202	#[inline(always)]
203	pub fn convert_i8x16_to_u64x2(self, a: i8x16) -> u64x2 {
204		cast!(self.sse4_1._mm_cvtepi8_epi64(cast!(a)))
205	}
206
207	/// Converts a `u16x8` to `i32x4`, elementwise, while truncating the extra elements.
208	#[inline(always)]
209	pub fn convert_u16x8_to_i32x4(self, a: u16x8) -> i32x4 {
210		cast!(self.sse4_1._mm_cvtepu16_epi32(cast!(a)))
211	}
212
213	/// Converts a `u16x8` to `i64x2`, elementwise, while truncating the extra elements.
214	#[inline(always)]
215	pub fn convert_u16x8_to_i64x2(self, a: u16x8) -> i64x2 {
216		cast!(self.sse4_1._mm_cvtepu16_epi64(cast!(a)))
217	}
218
219	/// Converts a `u16x8` to `u32x4`, elementwise, while truncating the extra elements.
220	#[inline(always)]
221	pub fn convert_u16x8_to_u32x4(self, a: u16x8) -> u32x4 {
222		cast!(self.sse4_1._mm_cvtepu16_epi32(cast!(a)))
223	}
224
225	/// Converts a `u16x8` to `u64x2`, elementwise, while truncating the extra elements.
226	#[inline(always)]
227	pub fn convert_u16x8_to_u64x2(self, a: u16x8) -> u64x2 {
228		cast!(self.sse4_1._mm_cvtepu16_epi64(cast!(a)))
229	}
230
231	/// Converts a `u32x4` to `i64x2`, elementwise, while truncating the extra elements.
232	#[inline(always)]
233	pub fn convert_u32x4_to_i64x2(self, a: u32x4) -> i64x2 {
234		cast!(self.sse4_1._mm_cvtepu32_epi64(cast!(a)))
235	}
236
237	/// Converts a `u32x4` to `u64x2`, elementwise, while truncating the extra elements.
238	#[inline(always)]
239	pub fn convert_u32x4_to_u64x2(self, a: u32x4) -> u64x2 {
240		cast!(self.sse4_1._mm_cvtepu32_epi64(cast!(a)))
241	}
242
243	/// Converts a `u8x16` to `i16x8`, elementwise, while truncating the extra elements.
244	#[inline(always)]
245	pub fn convert_u8x16_to_i16x8(self, a: u8x16) -> i16x8 {
246		cast!(self.sse4_1._mm_cvtepu8_epi16(cast!(a)))
247	}
248
249	/// Converts a `u8x16` to `i32x4`, elementwise, while truncating the extra elements.
250	#[inline(always)]
251	pub fn convert_u8x16_to_i32x4(self, a: u8x16) -> i32x4 {
252		cast!(self.sse4_1._mm_cvtepu8_epi32(cast!(a)))
253	}
254
255	/// Converts a `u8x16` to `i64x2`, elementwise, while truncating the extra elements.
256	#[inline(always)]
257	pub fn convert_u8x16_to_i64x2(self, a: u8x16) -> i64x2 {
258		cast!(self.sse4_1._mm_cvtepu8_epi64(cast!(a)))
259	}
260
261	/// Converts a `u8x16` to `i8x16`, elementwise.
262	#[inline(always)]
263	pub fn convert_u8x16_to_i8x16(self, a: u8x16) -> i8x16 {
264		cast!(a)
265	}
266
267	/// Converts a `u8x16` to `u16x8`, elementwise, while truncating the extra elements.
268	#[inline(always)]
269	pub fn convert_u8x16_to_u16x8(self, a: u8x16) -> u16x8 {
270		cast!(self.sse4_1._mm_cvtepu8_epi16(cast!(a)))
271	}
272
273	/// Converts a `u8x16` to `u32x4`, elementwise, while truncating the extra elements.
274	#[inline(always)]
275	pub fn convert_u8x16_to_u32x4(self, a: u8x16) -> u32x4 {
276		cast!(self.sse4_1._mm_cvtepu8_epi32(cast!(a)))
277	}
278
279	/// Converts a `u8x16` to `u64x2`, elementwise, while truncating the extra elements.
280	#[inline(always)]
281	pub fn convert_u8x16_to_u64x2(self, a: u8x16) -> u64x2 {
282		cast!(self.sse4_1._mm_cvtepu8_epi64(cast!(a)))
283	}
284
285	/// See [_mm_hadds_epi16].
286	///
287	/// [_mm_hadds_epi16]: core::arch::x86_64::_mm_hadds_epi16
288	#[inline(always)]
289	pub fn horizontal_saturating_add_pack_i16x8(self, a: i16x8, b: i16x8) -> i16x8 {
290		cast!(self.ssse3._mm_hadds_epi16(cast!(a), cast!(b)))
291	}
292
293	/// See [_mm_hsubs_epi16].
294	///
295	/// [_mm_hsubs_epi16]: core::arch::x86_64::_mm_hsubs_epi16
296	#[inline(always)]
297	pub fn horizontal_saturating_sub_pack_i16x8(self, a: i16x8, b: i16x8) -> i16x8 {
298		cast!(self.ssse3._mm_hsubs_epi16(cast!(a), cast!(b)))
299	}
300
301	/// See [_mm_maddubs_epi16].
302	///
303	/// [_mm_maddubs_epi16]: core::arch::x86_64::_mm_maddubs_epi16
304	#[inline(always)]
305	pub fn multiply_saturating_add_adjacent_i8x16(self, a: i8x16, b: i8x16) -> i16x8 {
306		cast!(self.ssse3._mm_maddubs_epi16(cast!(a), cast!(b)))
307	}
308
309	/// See [_mm_mpsadbw_epu8].
310	///
311	/// [_mm_mpsadbw_epu8]: core::arch::x86_64::_mm_mpsadbw_epu8
312	#[inline(always)]
313	pub fn multisum_of_absolute_differences_u8x16<const OFFSETS: i32>(
314		self,
315		a: u8x16,
316		b: u8x16,
317	) -> u16x8 {
318		cast!(self.sse4_1._mm_mpsadbw_epu8::<OFFSETS>(cast!(a), cast!(b)))
319	}
320
321	/// See [_mm_packus_epi32].
322	///
323	/// [_mm_packus_epi32]: core::arch::x86_64::_mm_packus_epi32
324	#[inline(always)]
325	pub fn pack_with_unsigned_saturation_i32x4(self, a: i32x4, b: i32x4) -> u16x8 {
326		cast!(self.sse4_1._mm_packus_epi32(cast!(a), cast!(b)))
327	}
328
329	/// Rounds the elements of each lane of `a` to the nearest integer. If two values are equally
330	/// close, the even value is returned.
331	#[inline(always)]
332	pub fn round_f32x4(self, a: f32x4) -> f32x4 {
333		const ROUNDING: i32 = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC;
334		cast!(self.sse4_1._mm_round_ps::<ROUNDING>(cast!(a)))
335	}
336
337	/// Rounds the elements of each lane of `a` to the nearest integer. If two values are equally
338	/// close, the even value is returned.
339	#[inline(always)]
340	pub fn round_f64x2(self, a: f64x2) -> f64x2 {
341		const ROUNDING: i32 = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC;
342		cast!(self.sse4_1._mm_round_pd::<ROUNDING>(cast!(a)))
343	}
344
345	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
346	/// bit in the mask is set, otherwise selecting elements from `if_false`.
347	#[inline(always)]
348	pub fn select_const_f32x4<const MASK4: i32>(self, if_true: f32x4, if_false: f32x4) -> f32x4 {
349		cast!(self.select_const_u32x4::<MASK4>(cast!(if_true), cast!(if_false)))
350	}
351
352	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
353	/// bit in the mask is set, otherwise selecting elements from `if_false`.
354	#[inline(always)]
355	pub fn select_const_f64x2<const MASK2: i32>(self, if_true: f64x2, if_false: f64x2) -> f64x2 {
356		cast!(self.select_const_u64x2::<MASK2>(cast!(if_true), cast!(if_false)))
357	}
358
359	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
360	/// bit in the mask is set, otherwise selecting elements from `if_false`.
361	#[inline(always)]
362	pub fn select_const_i32x4<const MASK4: i32>(self, if_true: i32x4, if_false: i32x4) -> i32x4 {
363		cast!(self.select_const_u32x4::<MASK4>(cast!(if_true), cast!(if_false)))
364	}
365
366	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
367	/// bit in the mask is set, otherwise selecting elements from `if_false`.
368	#[inline(always)]
369	pub fn select_const_i64x2<const MASK2: i32>(self, if_true: i64x2, if_false: i64x2) -> i64x2 {
370		cast!(self.select_const_u64x2::<MASK2>(cast!(if_true), cast!(if_false)))
371	}
372
373	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
374	/// bit in the mask is set, otherwise selecting elements from `if_false`.
375	#[inline(always)]
376	pub fn select_const_u32x4<const MASK4: i32>(self, if_true: u32x4, if_false: u32x4) -> u32x4 {
377		cast!(
378			self.sse4_1
379				._mm_blend_ps::<MASK4>(cast!(if_false), cast!(if_true)),
380		)
381	}
382
383	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
384	/// bit in the mask is set, otherwise selecting elements from `if_false`.
385	#[inline(always)]
386	pub fn select_const_u64x2<const MASK2: i32>(self, if_true: u64x2, if_false: u64x2) -> u64x2 {
387		cast!(
388			self.sse4_1
389				._mm_blend_pd::<MASK2>(cast!(if_false), cast!(if_true)),
390		)
391	}
392
393	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
394	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
395	#[inline(always)]
396	pub fn select_f32x4(self, mask: m32x4, if_true: f32x4, if_false: f32x4) -> f32x4 {
397		cast!(
398			self.sse4_1
399				._mm_blendv_ps(cast!(if_false), cast!(if_true), cast!(mask)),
400		)
401	}
402
403	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
404	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
405	#[inline(always)]
406	pub fn select_f64x2(self, mask: m64x2, if_true: f64x2, if_false: f64x2) -> f64x2 {
407		cast!(
408			self.sse4_1
409				._mm_blendv_pd(cast!(if_false), cast!(if_true), cast!(mask)),
410		)
411	}
412
413	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
414	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
415	#[inline(always)]
416	pub fn select_i16x8(self, mask: m16x8, if_true: i16x8, if_false: i16x8) -> i16x8 {
417		cast!(self.select_u16x8(mask, cast!(if_true), cast!(if_false)))
418	}
419
420	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
421	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
422	#[inline(always)]
423	pub fn select_i32x4(self, mask: m32x4, if_true: i32x4, if_false: i32x4) -> i32x4 {
424		cast!(self.select_u32x4(mask, cast!(if_true), cast!(if_false)))
425	}
426
427	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
428	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
429	#[inline(always)]
430	pub fn select_i64x2(self, mask: m64x2, if_true: i64x2, if_false: i64x2) -> i64x2 {
431		cast!(self.select_u64x2(mask, cast!(if_true), cast!(if_false)))
432	}
433
434	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
435	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
436	#[inline(always)]
437	pub fn select_i8x16(self, mask: m8x16, if_true: i8x16, if_false: i8x16) -> i8x16 {
438		cast!(self.select_u8x16(mask, cast!(if_true), cast!(if_false)))
439	}
440
441	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
442	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
443	#[inline(always)]
444	pub fn select_u16x8(self, mask: m16x8, if_true: u16x8, if_false: u16x8) -> u16x8 {
445		cast!(
446			self.sse4_1
447				._mm_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
448		)
449	}
450
451	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
452	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
453	#[inline(always)]
454	pub fn select_u32x4(self, mask: m32x4, if_true: u32x4, if_false: u32x4) -> u32x4 {
455		cast!(
456			self.sse4_1
457				._mm_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
458		)
459	}
460
461	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
462	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
463	#[inline(always)]
464	pub fn select_u64x2(self, mask: m64x2, if_true: u64x2, if_false: u64x2) -> u64x2 {
465		cast!(
466			self.sse4_1
467				._mm_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
468		)
469	}
470
471	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
472	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
473	#[inline(always)]
474	pub fn select_u8x16(self, mask: m8x16, if_true: u8x16, if_false: u8x16) -> u8x16 {
475		cast!(
476			self.sse4_1
477				._mm_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
478		)
479	}
480
481	/// Rounds the elements of each lane of `a` to the nearest integer towards zero.
482	#[inline(always)]
483	pub fn truncate_f32x4(self, a: f32x4) -> f32x4 {
484		const ROUNDING: i32 = _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC;
485		cast!(self.sse4_1._mm_round_ps::<ROUNDING>(cast!(a)))
486	}
487
488	/// Rounds the elements of each lane of `a` to the nearest integer towards zero.
489	#[inline(always)]
490	pub fn truncate_f64x2(self, a: f64x2) -> f64x2 {
491		const ROUNDING: i32 = _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC;
492		cast!(self.sse4_1._mm_round_pd::<ROUNDING>(cast!(a)))
493	}
494
495	/// Multiplies the elements of each lane of `a` and `b`, and returns separately the low and
496	/// high bits of the result.
497	#[inline(always)]
498	pub fn widening_mul_i32x4(self, a: i32x4, b: i32x4) -> (u32x4, i32x4) {
499		let a = cast!(a);
500		let b = cast!(b);
501		let sse = self.sse2;
502
503		// a0b0_lo a0b0_hi a2b2_lo a2b2_hi
504		let ab_evens = self.sse4_1._mm_mul_epi32(a, b);
505		// a1b1_lo a1b1_hi a3b3_lo a3b3_hi
506		let ab_odds = self
507			.sse4_1
508			._mm_mul_epi32(sse._mm_srli_epi64::<32>(a), sse._mm_srli_epi64::<32>(b));
509
510		let ab_lo = self.sse4_1._mm_blend_ps::<0b1010>(
511			// a0b0_lo xxxxxxx a2b2_lo xxxxxxx
512			cast!(ab_evens),
513			// xxxxxxx a1b1_lo xxxxxxx a3b3_lo
514			cast!(sse._mm_slli_epi64::<32>(ab_odds)),
515		);
516		let ab_hi = self.sse4_1._mm_blend_ps::<0b1010>(
517			// a0b0_hi xxxxxxx a2b2_hi xxxxxxx
518			cast!(sse._mm_srli_epi64::<32>(ab_evens)),
519			// xxxxxxx a1b1_hi xxxxxxx a3b3_hi
520			cast!(ab_odds),
521		);
522
523		(cast!(ab_lo), cast!(ab_hi))
524	}
525
526	/// Multiplies the elements of each lane of `a` and `b`, and returns separately the low and
527	/// high bits of the result.
528	#[inline(always)]
529	pub fn widening_mul_u32x4(self, a: u32x4, b: u32x4) -> (u32x4, u32x4) {
530		let a = cast!(a);
531		let b = cast!(b);
532		let sse = self.sse2;
533
534		// a0b0_lo a0b0_hi a2b2_lo a2b2_hi
535		let ab_evens = sse._mm_mul_epu32(a, b);
536		// a1b1_lo a1b1_hi a3b3_lo a3b3_hi
537		let ab_odds = sse._mm_mul_epu32(sse._mm_srli_epi64::<32>(a), sse._mm_srli_epi64::<32>(b));
538
539		let ab_lo = self.sse4_1._mm_blend_ps::<0b1010>(
540			// a0b0_lo xxxxxxx a2b2_lo xxxxxxx
541			cast!(ab_evens),
542			// xxxxxxx a1b1_lo xxxxxxx a3b3_lo
543			cast!(sse._mm_slli_epi64::<32>(ab_odds)),
544		);
545		let ab_hi = self.sse4_1._mm_blend_ps::<0b1010>(
546			// a0b0_hi xxxxxxx a2b2_hi xxxxxxx
547			cast!(sse._mm_srli_epi64::<32>(ab_evens)),
548			// xxxxxxx a1b1_hi xxxxxxx a3b3_hi
549			cast!(ab_odds),
550		);
551
552		(cast!(ab_lo), cast!(ab_hi))
553	}
554}
555
556macro_rules! impl_simd_binop {
557	($func: ident, $op: ident, $ty: ident, $out: ty, $factor: literal) => {
558		paste! {
559			#[inline(always)]
560			fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
561				self.[<$op _ $ty x $factor>](a, b)
562			}
563		}
564	};
565	($func: ident, $op: ident, $($ty: ident x $factor: literal => $out: ty),*) => {
566		$(impl_simd_binop!($func, $op, $ty, $out, $factor);)*
567	};
568	($func: ident, $op: ident, $($ty: ident x $factor: literal),*) => {
569		$(impl_simd_binop!($func, $op, $ty, $ty, $factor);)*
570	};
571	($func: ident, $($ty: ident x $factor: literal => $out: ty),*) => {
572		$(impl_simd_binop!($func, $func, $ty, $out, $factor);)*
573	};
574	($func: ident, $($ty: ident x $factor: literal),*) => {
575		$(impl_simd_binop!($func, $func, $ty, $ty, $factor);)*
576	};
577}
578
579macro_rules! impl_simd_unop {
580	($func: ident, $op: ident, $ty: ident, $out: ty, $factor: literal) => {
581		paste! {
582			#[inline(always)]
583			fn [<$func _ $ty s>](self, a: Self::[<$ty s>]) -> Self::[<$out s>] {
584				self.[<$op _ $ty x $factor>](a)
585			}
586		}
587	};
588	($func: ident, $($ty: ident x $factor: literal),*) => {
589		$(impl_simd_unop!($func, $func, $ty, $ty, $factor);)*
590	};
591}
592
593macro_rules! impl_scalar_binop {
594	($func: ident, $ty: ident, $out: ty, impl) => {
595		paste! {
596			#[inline(always)]
597			fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
598				Scalar128b.[<$func _ $ty s>](a, b)
599			}
600		}
601	};
602	($func: ident, $($ty: ident => $out: ty),*) => {
603		$(impl_scalar_binop!($func, $ty, $out, impl);)*
604	};
605	($func: ident, $($ty: ident),*) => {
606		$(impl_scalar_binop!($func, $ty, $ty, impl);)*
607	};
608}
609
610macro_rules! splat {
611	($ty: ty, $factor: literal) => {
612		paste! {
613			#[inline(always)]
614			fn [<splat_ $ty s>](self, value: $ty) -> Self::[<$ty s>] {
615				self.[<splat_ $ty x $factor>](value)
616			}
617		}
618	};
619	($($ty: ident x $factor: literal),*) => {
620		$(splat!($ty, $factor);)*
621	};
622}
623
624impl Simd for V2 {
625	type c32s = f32x4;
626	type c64s = f64x2;
627	type f32s = f32x4;
628	type f64s = f64x2;
629	type i16s = i16x8;
630	type i32s = i32x4;
631	type i64s = i64x2;
632	type i8s = i8x16;
633	type m16s = m16x8;
634	type m32s = m32x4;
635	type m64s = m64x2;
636	type m8s = m8x16;
637	type u16s = u16x8;
638	type u32s = u32x4;
639	type u64s = u64x2;
640	type u8s = u8x16;
641
642	const REGISTER_COUNT: usize = 16;
643
644	impl_simd_binop!(add, f32 x 4, f64 x 2);
645
646	impl_simd_binop!(add, 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);
647
648	impl_simd_binop!(sub, f32 x 4, f64 x 2);
649
650	impl_simd_binop!(sub, 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);
651
652	impl_simd_binop!(mul, f32 x 4, f64 x 2);
653
654	impl_simd_binop!(mul, wrapping_mul, u16 x 8, i16 x 8, u32 x 4, i32 x 4);
655
656	impl_scalar_binop!(mul, u64, i64, c32, c64);
657
658	impl_simd_binop!(and, 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, f32 x 4, f64 x 2);
659
660	impl_simd_binop!(or, 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, f32 x 4, f64 x 2);
661
662	impl_simd_binop!(xor, 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, f32 x 4, f64 x 2);
663
664	impl_simd_binop!(div, f32 x 4, f64 x 2);
665
666	impl_simd_binop!(equal, cmp_eq, u8 x 16 => m8, u16 x 8 => m16, u32 x 4 => m32, u64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
667
668	impl_simd_binop!(greater_than, cmp_gt, u8 x 16 => m8, i8 x 16 => m8, u16 x 8 => m16, i16 x 8 => m16, u32 x 4 => m32, i32 x 4 => m32, u64 x 2 => m64, i64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
669
670	impl_simd_binop!(greater_than_or_equal, cmp_ge, u8 x 16 => m8, i8 x 16 => m8, u16 x 8 => m16, i16 x 8 => m16, u32 x 4 => m32, i32 x 4 => m32, u64 x 2 => m64, i64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
671
672	impl_simd_binop!(less_than, cmp_lt, u8 x 16 => m8, i8 x 16 => m8, u16 x 8 => m16, i16 x 8 => m16, u32 x 4 => m32, i32 x 4 => m32, u64 x 2 => m64, i64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
673
674	impl_simd_binop!(less_than_or_equal, cmp_le, u8 x 16 => m8, i8 x 16 => m8, u16 x 8 => m16, i16 x 8 => m16, u32 x 4 => m32, i32 x 4 => m32, u64 x 2 => m64, i64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
675
676	impl_scalar_binop!(conj_mul, c32, c64);
677
678	splat!(u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, u64 x 2, i64 x 2, f32 x 4, f64 x 2);
679
680	impl_simd_binop!(max, u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, f32 x 4, f64 x 2);
681
682	impl_scalar_binop!(max, u64, i64);
683
684	impl_simd_binop!(min, u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, f32 x 4, f64 x 2);
685
686	impl_scalar_binop!(min, u64, i64);
687
688	impl_simd_unop!(not, m8 x 16, u8 x 16, m16 x 8, u16 x 8, m32 x 4, u32 x 4, m64 x 2, u64 x 2);
689
690	fn abs2_c32s(self, a: Self::c32s) -> Self::c32s {
691		let sqr = self.mul_f32s(a, a);
692		let sqr_rev = self
693			.sse
694			._mm_shuffle_ps::<0b10_11_00_01>(cast!(sqr), cast!(sqr));
695		self.add_f32s(sqr, cast!(sqr_rev))
696	}
697
698	fn abs2_c64s(self, a: Self::c64s) -> Self::c64s {
699		let sqr = self.mul_f64s(a, a);
700		let sqr_rev = self.sse2._mm_shuffle_pd::<0b0101>(cast!(sqr), cast!(sqr));
701		self.add_f64s(sqr, cast!(sqr_rev))
702	}
703
704	fn abs_max_c32s(self, a: Self::c32s) -> Self::c32s {
705		let max = self.abs_f32s(a);
706		let max_rev = self.sse._mm_shuffle_ps::<0b10_11_00_01>(cast!(a), cast!(a));
707		self.max_f32s(max, cast!(max_rev))
708	}
709
710	fn abs_max_c64s(self, a: Self::c64s) -> Self::c64s {
711		let max = self.abs_f64s(a);
712		let max_rev = self.sse2._mm_shuffle_pd::<0b0101>(cast!(max), cast!(max));
713		self.max_f64s(max, cast!(max_rev))
714	}
715
716	#[inline(always)]
717	fn add_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
718		self.add_f32s(a, b)
719	}
720
721	#[inline(always)]
722	fn add_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
723		self.add_f64s(a, b)
724	}
725
726	#[inline(always)]
727	fn equal_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::m32s {
728		self.equal_f32s(a, b)
729	}
730
731	#[inline(always)]
732	fn equal_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::m64s {
733		self.equal_f64s(a, b)
734	}
735
736	#[inline(always)]
737	fn conj_c32s(self, a: Self::c32s) -> Self::c32s {
738		self.xor_f32s(a, self.splat_c32s(c32 { re: 0.0, im: -0.0 }))
739	}
740
741	#[inline(always)]
742	fn conj_c64s(self, a: Self::c64s) -> Self::c64s {
743		self.xor_f64s(a, self.splat_c64s(c64 { re: 0.0, im: -0.0 }))
744	}
745
746	#[inline(always)]
747	fn conj_mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
748		Scalar128b.conj_mul_add_c32s(a, b, c)
749	}
750
751	#[inline(always)]
752	fn conj_mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
753		Scalar128b.conj_mul_add_c64s(a, b, c)
754	}
755
756	/// # Safety
757	///
758	/// See the trait-level safety documentation.
759	#[inline(always)]
760	unsafe fn mask_load_ptr_c32s(self, mask: MemMask<Self::m32s>, ptr: *const c32) -> Self::c32s {
761		cast!(self.mask_load_ptr_u32s(mask, ptr as _))
762	}
763
764	/// # Safety
765	///
766	/// See the trait-level safety documentation.
767	#[inline(always)]
768	unsafe fn mask_load_ptr_c64s(self, mask: MemMask<Self::m64s>, ptr: *const c64) -> Self::c64s {
769		cast!(self.mask_load_ptr_u64s(mask, ptr as _))
770	}
771
772	/// # Safety
773	///
774	/// See the trait-level safety documentation.
775	#[inline(always)]
776	unsafe fn mask_load_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *const u8) -> Self::u8s {
777		Scalar128b.mask_load_ptr_u8s(mask, ptr)
778	}
779
780	/// # Safety
781	///
782	/// See the trait-level safety documentation.
783	#[inline(always)]
784	unsafe fn mask_load_ptr_u16s(self, mask: MemMask<Self::m16s>, ptr: *const u16) -> Self::u16s {
785		Scalar128b.mask_load_ptr_u16s(mask, ptr)
786	}
787
788	/// # Safety
789	///
790	/// See the trait-level safety documentation.
791	#[inline(always)]
792	unsafe fn mask_load_ptr_u32s(self, mask: MemMask<Self::m32s>, ptr: *const u32) -> Self::u32s {
793		Scalar128b.mask_load_ptr_u32s(mask, ptr)
794	}
795
796	/// # Safety
797	///
798	/// See the trait-level safety documentation.
799	#[inline(always)]
800	unsafe fn mask_load_ptr_u64s(self, mask: MemMask<Self::m64s>, ptr: *const u64) -> Self::u64s {
801		cast!(self.mask_load_ptr_u32s(
802			MemMask {
803				mask: cast!(mask.mask),
804				#[cfg(target_arch = "x86_64")]
805				load: mask.load,
806				#[cfg(target_arch = "x86_64")]
807				store: mask.store
808			},
809			ptr as _
810		))
811	}
812
813	/// # Safety
814	///
815	/// See the trait-level safety documentation.
816	#[inline(always)]
817	unsafe fn mask_store_ptr_c32s(
818		self,
819		mask: MemMask<Self::m32s>,
820		ptr: *mut c32,
821		values: Self::c32s,
822	) {
823		self.mask_store_ptr_u32s(mask, ptr as _, cast!(values))
824	}
825
826	/// # Safety
827	///
828	/// See the trait-level safety documentation.
829	#[inline(always)]
830	unsafe fn mask_store_ptr_c64s(
831		self,
832		mask: MemMask<Self::m64s>,
833		ptr: *mut c64,
834		values: Self::c64s,
835	) {
836		self.mask_store_ptr_u64s(mask, ptr as _, cast!(values))
837	}
838
839	/// # Safety
840	///
841	/// See the trait-level safety documentation.
842	#[inline(always)]
843	unsafe fn mask_store_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *mut u8, values: Self::u8s) {
844		Scalar128b.mask_store_ptr_u8s(mask, ptr, values);
845	}
846
847	/// # Safety
848	///
849	/// See the trait-level safety documentation.
850	#[inline(always)]
851	unsafe fn mask_store_ptr_u16s(
852		self,
853		mask: MemMask<Self::m16s>,
854		ptr: *mut u16,
855		values: Self::u16s,
856	) {
857		Scalar128b.mask_store_ptr_u16s(mask, ptr, values);
858	}
859
860	/// # Safety
861	///
862	/// See the trait-level safety documentation.
863	#[inline(always)]
864	unsafe fn mask_store_ptr_u32s(
865		self,
866		mask: MemMask<Self::m32s>,
867		ptr: *mut u32,
868		values: Self::u32s,
869	) {
870		Scalar128b.mask_store_ptr_u32s(mask, ptr, values);
871	}
872
873	/// # Safety
874	///
875	/// See the trait-level safety documentation.
876	#[inline(always)]
877	unsafe fn mask_store_ptr_u64s(
878		self,
879		mask: MemMask<Self::m64s>,
880		ptr: *mut u64,
881		values: Self::u64s,
882	) {
883		self.mask_store_ptr_u32s(
884			MemMask {
885				mask: cast!(mask.mask),
886				#[cfg(target_arch = "x86_64")]
887				load: mask.load,
888				#[cfg(target_arch = "x86_64")]
889				store: mask.store,
890			},
891			ptr as _,
892			cast!(values),
893		)
894	}
895
896	#[inline(always)]
897	fn mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
898		Scalar128b.mul_add_c32s(a, b, c)
899	}
900
901	#[inline(always)]
902	fn mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
903		Scalar128b.mul_add_c64s(a, b, c)
904	}
905
906	#[inline(always)]
907	fn mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
908		self.mul_add_f32s(a, b, c)
909	}
910
911	#[inline(always)]
912	fn mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
913		self.mul_add_f64s(a, b, c)
914	}
915
916	#[inline(always)]
917	fn mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
918		Scalar128b.mul_add_f32s(a, b, c)
919	}
920
921	#[inline(always)]
922	fn mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
923		Scalar128b.mul_add_f64s(a, b, c)
924	}
925
926	#[inline(always)]
927	fn negate_mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
928		self.negate_mul_add_f32s(a, b, c)
929	}
930
931	#[inline(always)]
932	fn negate_mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
933		self.negate_mul_add_f64s(a, b, c)
934	}
935
936	#[inline(always)]
937	fn negate_mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
938		Scalar128b.negate_mul_add_f32s(a, b, c)
939	}
940
941	#[inline(always)]
942	fn negate_mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
943		Scalar128b.negate_mul_add_f64s(a, b, c)
944	}
945
946	#[inline(always)]
947	fn neg_c32s(self, a: Self::c32s) -> Self::c32s {
948		self.xor_f32s(a, self.splat_f32s(-0.0))
949	}
950
951	#[inline(always)]
952	fn neg_c64s(self, a: Self::c64s) -> Self::c64s {
953		self.xor_f64s(a, self.splat_f64s(-0.0))
954	}
955
956	#[inline(always)]
957	fn reduce_max_c32s(self, a: Self::c32s) -> c32 {
958		self.reduce_max_c32x2(a)
959	}
960
961	#[inline(always)]
962	fn reduce_max_c64s(self, a: Self::c64s) -> c64 {
963		self.reduce_max_c64x1(a)
964	}
965
966	#[inline(always)]
967	fn reduce_max_f32s(self, a: Self::f32s) -> f32 {
968		self.reduce_max_f32x4(a)
969	}
970
971	#[inline(always)]
972	fn reduce_max_f64s(self, a: Self::f64s) -> f64 {
973		self.reduce_max_f64x2(a)
974	}
975
976	#[inline(always)]
977	fn reduce_min_c32s(self, a: Self::c32s) -> c32 {
978		self.reduce_min_c32x2(a)
979	}
980
981	#[inline(always)]
982	fn reduce_min_c64s(self, a: Self::c64s) -> c64 {
983		self.reduce_min_c64x1(a)
984	}
985
986	#[inline(always)]
987	fn reduce_min_f32s(self, a: Self::f32s) -> f32 {
988		self.reduce_min_f32x4(a)
989	}
990
991	#[inline(always)]
992	fn reduce_min_f64s(self, a: Self::f64s) -> f64 {
993		self.reduce_min_f64x2(a)
994	}
995
996	#[inline(always)]
997	fn reduce_product_f32s(self, a: Self::f32s) -> f32 {
998		self.reduce_product_f32x4(a)
999	}
1000
1001	#[inline(always)]
1002	fn reduce_product_f64s(self, a: Self::f64s) -> f64 {
1003		self.reduce_product_f64x2(a)
1004	}
1005
1006	#[inline(always)]
1007	fn reduce_sum_c32s(self, a: Self::c32s) -> c32 {
1008		self.reduce_sum_c32x2(a)
1009	}
1010
1011	#[inline(always)]
1012	fn reduce_sum_c64s(self, a: Self::c64s) -> c64 {
1013		self.reduce_sum_c64x1(a)
1014	}
1015
1016	#[inline(always)]
1017	fn reduce_sum_f32s(self, a: Self::f32s) -> f32 {
1018		self.reduce_sum_f32x4(a)
1019	}
1020
1021	#[inline(always)]
1022	fn reduce_sum_f64s(self, a: Self::f64s) -> f64 {
1023		self.reduce_sum_f64x2(a)
1024	}
1025
1026	#[inline(always)]
1027	fn rotate_right_c32s(self, a: Self::c32s, amount: usize) -> Self::c32s {
1028		Scalar128b.rotate_right_c32s(a, amount)
1029	}
1030
1031	#[inline(always)]
1032	fn rotate_right_c64s(self, a: Self::c64s, amount: usize) -> Self::c64s {
1033		Scalar128b.rotate_right_c64s(a, amount)
1034	}
1035
1036	#[inline(always)]
1037	fn rotate_right_u32s(self, a: Self::u32s, amount: usize) -> Self::u32s {
1038		Scalar128b.rotate_right_u32s(a, amount)
1039	}
1040
1041	#[inline(always)]
1042	fn rotate_right_u64s(self, a: Self::u64s, amount: usize) -> Self::u64s {
1043		Scalar128b.rotate_right_u64s(a, amount)
1044	}
1045
1046	#[inline(always)]
1047	fn select_u32s(
1048		self,
1049		mask: Self::m32s,
1050		if_true: Self::u32s,
1051		if_false: Self::u32s,
1052	) -> Self::u32s {
1053		let mask: __m128 = cast!(mask);
1054		let if_true: __m128 = cast!(if_true);
1055		let if_false: __m128 = cast!(if_false);
1056
1057		cast!(self.sse4_1._mm_blendv_ps(if_false, if_true, mask))
1058	}
1059
1060	#[inline(always)]
1061	fn select_u64s(
1062		self,
1063		mask: Self::m64s,
1064		if_true: Self::u64s,
1065		if_false: Self::u64s,
1066	) -> Self::u64s {
1067		let mask: __m128d = cast!(mask);
1068		let if_true: __m128d = cast!(if_true);
1069		let if_false: __m128d = cast!(if_false);
1070
1071		cast!(self.sse4_1._mm_blendv_pd(if_false, if_true, mask))
1072	}
1073
1074	#[inline(always)]
1075	fn splat_c32s(self, value: c32) -> Self::c32s {
1076		cast!(self.splat_f64s(cast!(value)))
1077	}
1078
1079	#[inline(always)]
1080	fn splat_c64s(self, value: c64) -> Self::c64s {
1081		Scalar128b.splat_c64s(value)
1082	}
1083
1084	#[inline(always)]
1085	fn sub_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
1086		self.sub_f32s(a, b)
1087	}
1088
1089	#[inline(always)]
1090	fn sub_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
1091		self.sub_f64s(a, b)
1092	}
1093
1094	#[inline(always)]
1095	fn swap_re_im_c32s(self, a: Self::c32s) -> Self::c32s {
1096		Scalar128b.swap_re_im_c32s(a)
1097	}
1098
1099	#[inline(always)]
1100	fn swap_re_im_c64s(self, a: Self::c64s) -> Self::c64s {
1101		Scalar128b.swap_re_im_c64s(a)
1102	}
1103
1104	#[inline(always)]
1105	fn vectorize<Op: WithSimd>(self, op: Op) -> Op::Output {
1106		struct Impl<Op> {
1107			this: V2,
1108			op: Op,
1109		}
1110		impl<Op: WithSimd> crate::NullaryFnOnce for Impl<Op> {
1111			type Output = Op::Output;
1112
1113			#[inline(always)]
1114			fn call(self) -> Self::Output {
1115				self.op.with_simd(self.this)
1116			}
1117		}
1118		self.vectorize(Impl { this: self, op })
1119	}
1120
1121	#[inline(always)]
1122	fn widening_mul_u32s(self, a: Self::u32s, b: Self::u32s) -> (Self::u32s, Self::u32s) {
1123		self.widening_mul_u32x4(a, b)
1124	}
1125
1126	#[inline(always)]
1127	fn wrapping_dyn_shl_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1128		Scalar128b.wrapping_dyn_shl_u32s(a, amount)
1129	}
1130
1131	#[inline(always)]
1132	fn wrapping_dyn_shr_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1133		Scalar128b.wrapping_dyn_shr_u32s(a, amount)
1134	}
1135
1136	#[inline(always)]
1137	fn sqrt_f32s(self, a: Self::f32s) -> Self::f32s {
1138		self.sqrt_f32x4(a)
1139	}
1140
1141	#[inline(always)]
1142	fn sqrt_f64s(self, a: Self::f64s) -> Self::f64s {
1143		self.sqrt_f64x2(a)
1144	}
1145}