vrl/vec8f.rs
1use std::{
2 fmt::Debug,
3 mem::MaybeUninit,
4 ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
5};
6
7use crate::{
8 common::SIMDVector,
9 macros::{vec_impl_sum_prod, vec_overload_operator},
10 Vec4f,
11};
12
13#[cfg(avx)]
14use crate::intrinsics::*;
15
16#[cfg(no_avx)]
17use derive_more::{Add, Div, Mul, Sub};
18
19/// Represents a packed vector of 8 single-precision floating-point values.
20///
21/// On platforms with AVX support [`Vec8f`] is a [`__m256`] wrapper. Otherwise it is a pair of
22/// [`Vec4f`] values.
23#[derive(Clone, Copy)]
24#[cfg_attr(no_avx, derive(Add, Sub, Mul, Div), mul(forward), div(forward))]
25#[cfg_attr(avx, repr(transparent))]
26#[cfg_attr(no_avx, repr(C))] // [repr(C)] guarantees fields ordering and paddinglessness.
27pub struct Vec8f {
28 #[cfg(avx)]
29 ymm: __m256,
30
31 #[cfg(no_avx)]
32 _low: Vec4f,
33 #[cfg(no_avx)]
34 _high: Vec4f,
35}
36
37impl Vec8f {
38 /// Initializes elements of returned vector with given values.
39 ///
40 /// # Example
41 /// ```
42 /// # use vrl::Vec8f;
43 /// assert_eq!(
44 /// Vec8f::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0),
45 /// [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0].into()
46 /// );
47 /// ```
48 #[inline(always)]
49 #[allow(clippy::too_many_arguments)]
50 pub fn new(v0: f32, v1: f32, v2: f32, v3: f32, v4: f32, v5: f32, v6: f32, v7: f32) -> Self {
51 #[cfg(avx)]
52 {
53 unsafe { _mm256_setr_ps(v0, v1, v2, v3, v4, v5, v6, v7) }.into()
54 }
55
56 #[cfg(no_avx)]
57 {
58 (Vec4f::new(v0, v1, v2, v3), Vec4f::new(v4, v5, v6, v7)).into()
59 }
60 }
61
62 /// Joins two [`Vec4f`] into a single [`Vec8f`]. The first four elements of returned vector are
63 /// elements of `a` and the last four elements are elements of `b`.
64 ///
65 /// See also [`split`](Self::split).
66 ///
67 /// # Exmaple
68 /// ```
69 /// # use vrl::{Vec4f, Vec8f};
70 /// let a = Vec4f::new(1.0, 2.0, 3.0, 4.0);
71 /// let b = Vec4f::new(5.0, 6.0, 7.0, 8.0);
72 /// let joined = Vec8f::join(a, b);
73 /// assert_eq!(a, joined.low());
74 /// assert_eq!(b, joined.high());
75 /// assert_eq!(joined.split(), (a, b));
76 /// ```
77 #[inline(always)]
78 pub fn join(a: Vec4f, b: Vec4f) -> Self {
79 #[cfg(avx)]
80 {
81 unsafe { _mm256_set_m128(b.into(), a.into()) }.into()
82 }
83
84 #[cfg(no_avx)]
85 {
86 Self { _low: a, _high: b }
87 }
88 }
89
90 /// Loads vector from array pointer by `addr`.
91 /// `addr` is not required to be aligned.
92 ///
93 /// # Safety
94 /// `addr` must be a valid pointer.
95 ///
96 /// # Example
97 /// ```
98 /// # use vrl::Vec8f;
99 /// let array = [42.0; 8];
100 /// let vec = unsafe { Vec8f::load_ptr(&array) };
101 /// ```
102 #[inline(always)]
103 pub unsafe fn load_ptr(addr: *const [f32; 8]) -> Self {
104 #[cfg(avx)]
105 {
106 _mm256_loadu_ps(addr as *const f32).into()
107 }
108
109 #[cfg(no_avx)]
110 {
111 let addr = addr as *const [f32; 4];
112 (Vec4f::load_ptr(addr), Vec4f::load_ptr(addr.add(1))).into()
113 }
114 }
115
116 /// Loads vector from aligned array pointed by `addr`.
117 ///
118 /// # Safety
119 /// Like [`load_ptr`], requires `addr` to be valid.
120 /// Unlike [`load_ptr`], requires `addr` to be divisible by `32`, i.e. to be a `32`-bytes aligned address.
121 ///
122 /// [`load_ptr`]: Self::load_ptr
123 ///
124 /// # Examples
125 /// ```
126 /// # use vrl::Vec8f;
127 /// #[repr(align(32))]
128 /// struct AlignedArray([f32; 8]);
129 ///
130 /// let array = AlignedArray([42.0; 8]);
131 /// let vec = unsafe { Vec8f::load_ptr_aligned(&array.0) };
132 /// assert_eq!(vec, Vec8f::broadcast(42.0));
133 /// ```
134 /// In the following example `zeros` is aligned as `u16`, i.e. 2-bytes aligned.
135 /// Therefore `zeros.as_ptr().byte_add(1)` is an odd address and hence not divisible by `32`.
136 /// ```should_panic
137 /// # use vrl::Vec8f;
138 /// let zeros = unsafe { std::mem::zeroed::<[u16; 20]>() };
139 /// unsafe { Vec8f::load_ptr_aligned(zeros.as_ptr().byte_add(1) as *const [f32; 8]) };
140 /// ```
141 #[inline(always)]
142 pub unsafe fn load_ptr_aligned(addr: *const [f32; 8]) -> Self {
143 #[cfg(avx)]
144 {
145 _mm256_load_ps(addr as *const f32).into()
146 }
147
148 #[cfg(no_avx)]
149 {
150 let addr = addr as *const [f32; 4];
151 (
152 Vec4f::load_ptr_aligned(addr),
153 Vec4f::load_ptr_aligned(addr.add(1)),
154 )
155 .into()
156 }
157 }
158
159 /// Loads values of returned vector from given data.
160 ///
161 /// # Exmaple
162 /// ```
163 /// # use vrl::Vec8f;
164 /// assert_eq!(
165 /// Vec8f::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0),
166 /// Vec8f::load(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0])
167 /// );
168 /// ```
169 #[inline(always)]
170 pub fn load(data: &[f32; 8]) -> Self {
171 unsafe { Self::load_ptr(data) }
172 }
173
174 /// Checks that data contains exactly eight elements and loads them into vector.
175 ///
176 /// # Panics
177 /// Panics if `data.len()` isn't `8`.
178 ///
179 /// # Examples
180 /// ```
181 /// # use vrl::Vec8f;
182 /// assert_eq!(
183 /// Vec8f::load_checked(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]),
184 /// Vec8f::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0)
185 /// );
186 /// ```
187 /// ```should_panic
188 /// # use vrl::Vec8f;
189 /// Vec8f::load_checked(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]);
190 /// ```
191 /// ```should_panic
192 /// # use vrl::Vec8f;
193 /// Vec8f::load_checked(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]);
194 /// ```
195 #[inline(always)]
196 pub fn load_checked(data: &[f32]) -> Self {
197 Self::load(
198 data.try_into()
199 .expect("data must contain exactly 8 elements"),
200 )
201 }
202
203 /// Loads the first eight element of `data` into vector.
204 ///
205 /// # Panics
206 /// Panics if `data` contains less than eight elements.
207 ///
208 /// # Exmaples
209 /// ```
210 /// # use vrl::Vec8f;
211 /// assert_eq!(
212 /// Vec8f::load_prefix(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]),
213 /// Vec8f::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0)
214 /// );
215 /// ```
216 ///
217 /// ```should_panic
218 /// # use vrl::Vec8f;
219 /// Vec8f::load_prefix(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]);
220 /// ```
221 #[inline(always)]
222 pub fn load_prefix(data: &[f32]) -> Self {
223 if data.len() < 8 {
224 panic!("data must contain at least 8 elements");
225 }
226 unsafe { Self::load_ptr(data.as_ptr() as *const [f32; 8]) }
227 }
228
229 /// Loads first 8 elements of `data` if available otherwise initializes first elements of
230 /// returned vector with values of `data` and rest elements with zeros.
231 ///
232 /// # Exmaple
233 /// ```
234 /// # use vrl::Vec8f;
235 /// let values = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
236 /// assert_eq!(
237 /// Vec8f::load_partial(&values),
238 /// Vec8f::from(&values[..8].try_into().unwrap())
239 /// );
240 /// assert_eq!(
241 /// Vec8f::load_partial(&values[..5]),
242 /// Vec8f::new(1.0, 2.0, 3.0, 4.0, 5.0, 0.0, 0.0, 0.0) // note zeros here
243 /// );
244 /// ```
245 #[inline]
246 pub fn load_partial(data: &[f32]) -> Self {
247 match data.len() {
248 8.. => unsafe { Self::load_ptr(data.as_ptr() as *const [f32; 8]) },
249 4.. => Self::join(
250 unsafe { Vec4f::load_ptr(data.as_ptr() as *const [f32; 4]) },
251 Vec4f::load_partial(data.split_at(4).1),
252 ),
253 0.. => Self::join(Vec4f::load_partial(data), Vec4f::default()),
254 }
255 }
256
257 /// Returns vector with all its elements initialized with a given `value`, i.e. broadcasts
258 /// `value` to all elements of returned vector.
259 ///
260 /// # Example
261 /// ```
262 /// # use vrl::Vec8f;
263 /// assert_eq!(
264 /// Vec8f::broadcast(42.0),
265 /// [42.0; 8].into()
266 /// );
267 /// ```
268 #[inline(always)]
269 pub fn broadcast(value: f32) -> Self {
270 #[cfg(avx)]
271 {
272 unsafe { _mm256_set1_ps(value) }.into()
273 }
274
275 #[cfg(no_avx)]
276 {
277 let half = Vec4f::broadcast(value);
278 (half, half).into()
279 }
280 }
281
282 /// Stores vector into array at given address.
283 ///
284 /// # Safety
285 /// `addr` must be a valid pointer.
286 #[inline(always)]
287 pub unsafe fn store_ptr(&self, addr: *mut [f32; 8]) {
288 #[cfg(avx)]
289 {
290 _mm256_storeu_ps(addr as *mut f32, self.ymm);
291 }
292
293 #[cfg(no_avx)]
294 {
295 let addr = addr as *mut [f32; 4];
296 self.low().store_ptr(addr);
297 self.high().store_ptr(addr.add(1));
298 }
299 }
300
301 /// Stores vector into aligned array at given address.
302 ///
303 /// # Safety
304 /// Like [`store_ptr`], requires `addr` to be valid.
305 /// Unlike [`store_ptr`], requires `addr` to be divisible by `32`, i.e. to be a 32-bytes aligned address.
306 ///
307 /// [`store_ptr`]: Self::store_ptr
308 #[inline(always)]
309 pub unsafe fn store_ptr_aligned(&self, addr: *mut [f32; 8]) {
310 #[cfg(avx)]
311 {
312 _mm256_store_ps(addr as *mut f32, self.ymm);
313 }
314
315 #[cfg(no_avx)]
316 {
317 let addr = addr as *mut [f32; 4];
318 self.low().store_ptr_aligned(addr);
319 self.high().store_ptr_aligned(addr.add(1));
320 }
321 }
322
323 /// Stores vector into aligned array at given address in uncached memory (non-temporal store).
324 /// This may be more efficient than [`store_ptr_aligned`] if it is unlikely that stored data will
325 /// stay in cache until it is read again, for instance, when storing large blocks of memory.
326 ///
327 /// # Safety
328 /// Has same requirements as [`store_ptr_aligned`]: `addr` must be valid and
329 /// divisible by `32`, i.e. to be a 32-bytes aligned address.
330 ///
331 /// [`store_ptr_aligned`]: Self::store_ptr_aligned
332 #[inline(always)]
333 pub unsafe fn store_ptr_non_temporal(&self, addr: *mut [f32; 8]) {
334 #[cfg(avx)]
335 {
336 _mm256_stream_ps(addr as *mut f32, self.ymm)
337 }
338
339 #[cfg(no_avx)]
340 {
341 let addr = addr as *mut [f32; 4];
342 self.low().store_ptr_non_temporal(addr);
343 self.high().store_ptr_non_temporal(addr.add(1));
344 }
345 }
346
347 /// Stores vector into given `array`.
348 #[inline(always)]
349 pub fn store(&self, array: &mut [f32; 8]) {
350 unsafe { self.store_ptr(array) }
351 }
352
353 /// Checkes that `slice` contains exactly eight elements and store elements of vector there.
354 ///
355 /// # Panics
356 /// Panics if `slice.len()` isn't `8`.
357 ///
358 /// # Examples
359 /// ```
360 /// # use vrl::Vec8f;
361 /// let mut data = [-1.0; 8];
362 /// Vec8f::default().store_checked(&mut data);
363 /// assert_eq!(data, [0.0; 8]);
364 /// ```
365 /// ```should_panic
366 /// # use vrl::Vec8f;
367 /// let mut data = [-1.0; 7];
368 /// Vec8f::default().store_checked(&mut data);
369 /// ```
370 /// ```should_panic
371 /// # use vrl::Vec8f;
372 /// let mut data = [-1.0; 9];
373 /// Vec8f::default().store_checked(&mut data);
374 /// ```
375 #[inline]
376 pub fn store_checked(&self, slice: &mut [f32]) {
377 self.store(
378 slice
379 .try_into()
380 .expect("slice must contain at least 8 elements"),
381 )
382 }
383
384 /// Stores elements of vector into the first eight elements of `slice`.
385 ///
386 /// # Panics
387 /// Panics if `slice` contains less then eight elements.
388 ///
389 /// # Exmaples
390 /// ```
391 /// # use vrl::Vec8f;
392 /// let mut data = [-1.0; 9];
393 /// Vec8f::broadcast(2.0).store_prefix(&mut data);
394 /// assert_eq!(data, [2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, -1.0]);
395 /// ```
396 /// ```should_panic
397 /// # use vrl::Vec8f;
398 /// let mut data = [-1.0; 7];
399 /// Vec8f::default().store_prefix(&mut data);
400 /// ```
401 #[inline(always)]
402 pub fn store_prefix(&self, slice: &mut [f32]) {
403 if slice.len() < 8 {
404 panic!("slice.len() must at least 8");
405 }
406 unsafe { self.store_ptr(slice.as_ptr() as *mut [f32; 8]) };
407 }
408
409 /// Stores `min(8, slice.len())` elements of vector into prefix of `slice`.
410 ///
411 /// # Examples
412 /// ```
413 /// # use vrl::Vec8f;
414 /// let mut data = [0.0; 7];
415 /// Vec8f::broadcast(1.0).store_partial(&mut data);
416 /// assert_eq!(data, [1.0; 7]);
417 /// ```
418 /// ```
419 /// # use vrl::Vec8f;
420 /// let mut data = [0.0; 9];
421 /// Vec8f::broadcast(1.0).store_partial(&mut data);
422 /// assert_eq!(data, [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0]); // note last zero
423 /// ```
424 #[inline]
425 pub fn store_partial(&self, slice: &mut [f32]) {
426 match slice.len() {
427 8.. => unsafe { self.store_ptr(slice.as_mut_ptr() as *mut [f32; 8]) },
428 4.. => {
429 unsafe { self.low().store_ptr(slice.as_mut_ptr() as *mut [f32; 4]) };
430 self.high().store_partial(slice.split_at_mut(4).1)
431 }
432 0.. => self.low().store_partial(slice),
433 }
434 }
435
436 /// Calculates the sum of all elements of vector.
437 ///
438 /// # Exmaple
439 /// ```
440 /// # use vrl::Vec8f;
441 /// let vec = Vec8f::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0);
442 /// assert_eq!(vec.sum(), 36.0);
443 /// ```
444 #[inline(always)]
445 pub fn sum(self) -> f32 {
446 (self.low() + self.high()).sum()
447 }
448
449 /// Returns the first four elements of vector.
450 ///
451 /// # Exmaple
452 /// ```
453 /// # use vrl::{Vec4f, Vec8f};
454 /// let vec8 = Vec8f::new(1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0);
455 /// assert_eq!(vec8.low(), Vec4f::broadcast(1.0));
456 /// ```
457 #[inline(always)]
458 pub fn low(self) -> Vec4f {
459 #[cfg(avx)]
460 {
461 unsafe { _mm256_castps256_ps128(self.ymm) }.into()
462 }
463
464 #[cfg(no_avx)]
465 {
466 self._low
467 }
468 }
469
470 /// Returns the last four elements of vector.
471 ///
472 /// # Exmaple
473 /// ```
474 /// # use vrl::{Vec4f, Vec8f};
475 /// let vec8 = Vec8f::new(1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0);
476 /// assert_eq!(vec8.high(), Vec4f::broadcast(2.0));
477 /// ```
478 #[inline(always)]
479 pub fn high(self) -> Vec4f {
480 #[cfg(avx)]
481 {
482 unsafe { _mm256_extractf128_ps(self.ymm, 1) }.into()
483 }
484
485 #[cfg(no_avx)]
486 {
487 self._high
488 }
489 }
490
491 /// Splits vector into low and high halfs.
492 ///
493 /// See also [`join`](Self::join).
494 ///
495 /// # Example
496 /// ```
497 /// # use::vrl::{Vec4f, Vec8f};
498 /// let vec = Vec8f::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0);
499 /// let (low, high) = vec.split();
500 /// assert_eq!(low, vec.low());
501 /// assert_eq!(high, vec.high());
502 /// assert_eq!(Vec8f::join(low, high), vec);
503 /// ```
504 #[inline(always)]
505 pub fn split(self) -> (Vec4f, Vec4f) {
506 (self.low(), self.high())
507 }
508}
509
510impl SIMDVector for Vec8f {
511 #[cfg(avx)]
512 type Underlying = __m256;
513 #[cfg(no_avx)]
514 type Underlying = (Vec4f, Vec4f);
515
516 type Element = f32;
517 const ELEMENTS: usize = 8;
518}
519
520impl Default for Vec8f {
521 /// Initializes all elements of returned vector with zero.
522 ///
523 /// # Example
524 /// ```
525 /// # use vrl::Vec8f;
526 /// assert_eq!(Vec8f::default(), Vec8f::broadcast(0.0));
527 /// ```
528 #[inline(always)]
529 fn default() -> Self {
530 #[cfg(avx)]
531 {
532 unsafe { _mm256_setzero_ps() }.into()
533 }
534
535 #[cfg(no_avx)]
536 {
537 (Vec4f::default(), Vec4f::default()).into()
538 }
539 }
540}
541
542impl Neg for Vec8f {
543 type Output = Self;
544
545 /// Flips sign bit of each element including non-finite ones.
546 #[inline(always)]
547 fn neg(self) -> Self::Output {
548 #[cfg(avx)]
549 {
550 unsafe { _mm256_xor_ps(self.ymm, _mm256_set1_ps(-0f32)) }.into()
551 }
552
553 #[cfg(no_avx)]
554 {
555 (-self.low(), -self.high()).into()
556 }
557 }
558}
559
560vec_overload_operator!(Vec8f, Add, add, _mm256_add_ps, avx);
561vec_overload_operator!(Vec8f, Sub, sub, _mm256_sub_ps, avx);
562vec_overload_operator!(Vec8f, Mul, mul, _mm256_mul_ps, avx);
563vec_overload_operator!(Vec8f, Div, div, _mm256_div_ps, avx);
564vec_impl_sum_prod!(Vec8f);
565
566#[cfg(avx)]
567impl From<__m256> for Vec8f {
568 /// Wraps given `value` into [`Vec8f`].
569 #[inline(always)]
570 fn from(value: __m256) -> Self {
571 Self { ymm: value }
572 }
573}
574
575#[cfg(avx)]
576impl From<Vec8f> for __m256 {
577 /// Unwraps given vector into raw [`__m256`] value.
578 #[inline(always)]
579 fn from(value: Vec8f) -> Self {
580 value.ymm
581 }
582}
583
584impl From<&[f32; 8]> for Vec8f {
585 /// Does same as [`load`](Self::load).
586 #[inline(always)]
587 fn from(value: &[f32; 8]) -> Self {
588 Self::load(value)
589 }
590}
591
592impl From<[f32; 8]> for Vec8f {
593 #[inline(always)]
594 fn from(value: [f32; 8]) -> Self {
595 (&value).into()
596 }
597}
598
599impl From<Vec8f> for [f32; 8] {
600 #[inline(always)]
601 fn from(value: Vec8f) -> Self {
602 let mut result = MaybeUninit::<Self>::uninit();
603 unsafe {
604 value.store_ptr(result.as_mut_ptr());
605 result.assume_init()
606 }
607 }
608}
609
610impl From<&Vec8f> for [f32; 8] {
611 #[inline(always)]
612 fn from(value: &Vec8f) -> Self {
613 unsafe { *(value as *const Vec8f as *const [f32; 8]) }
614 }
615}
616
617impl From<(Vec4f, Vec4f)> for Vec8f {
618 /// Does same as [`join`](Self::join).
619 #[inline(always)]
620 fn from((low, high): (Vec4f, Vec4f)) -> Self {
621 Self::join(low, high)
622 }
623}
624
625impl From<Vec8f> for (Vec4f, Vec4f) {
626 /// Does same as [`split`](Vec8f::split).
627 #[inline(always)]
628 fn from(vec: Vec8f) -> (Vec4f, Vec4f) {
629 vec.split()
630 }
631}
632
633impl PartialEq for Vec8f {
634 /// Checks whether all elements of vectors are equal.
635 ///
636 /// __Note__: when [`NaN`](`f32::NAN`) is an element of one of the operands the result is always `false`.
637 ///
638 /// # Examples
639 /// ```
640 /// # use vrl::Vec8f;
641 /// let a = Vec8f::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0);
642 /// assert_eq!(a, a);
643 /// ```
644 ///
645 /// ```
646 /// # use vrl::Vec8f;
647 /// let a = Vec8f::broadcast(f32::NAN);
648 /// assert_ne!(a, a);
649 /// ```
650 #[inline(always)]
651 fn eq(&self, other: &Self) -> bool {
652 #[cfg(avx)]
653 {
654 unsafe {
655 let cmp_result = _mm256_cmp_ps::<0>(self.ymm, other.ymm);
656 _mm256_testz_ps(cmp_result, cmp_result) == 0
657 }
658 }
659
660 #[cfg(no_avx)]
661 {
662 self.split() == other.split()
663 }
664 }
665}
666
667impl Debug for Vec8f {
668 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
669 let mut debug_tuple = f.debug_tuple("Vec8f");
670 for value in <[f32; 8]>::from(self) {
671 debug_tuple.field(&value);
672 }
673 debug_tuple.finish()
674 }
675}
676
677#[cfg(test)]
678mod tests {
679 use crate::Vec8f;
680
681 #[test]
682 #[inline(never)] // in order to find the function in disassembled binary
683 fn it_works() {
684 let a = Vec8f::broadcast(1.0);
685 assert_eq!(<[f32; 8]>::from(a), [1.0; 8]);
686 assert_eq!(a, [1.0; 8].into());
687
688 let b = 2.0 * a;
689 assert_ne!(a, b);
690
691 let mut c = b / 2.0;
692 assert_eq!(a, c);
693
694 c += Vec8f::from(&[1.0, 0.0, 2.0, 0.0, 3.0, 0.0, 4.0, 0.0]);
695 let d = -c;
696
697 const EXPECTED_D: [f32; 8] = [-2.0, -1.0, -3.0, -1.0, -4.0, -1.0, -5.0, -1.0];
698 assert_eq!(d, EXPECTED_D.into());
699 assert_eq!(<[f32; 8]>::from(d), EXPECTED_D);
700 }
701
702 #[test]
703 fn test_load_partial() {
704 const VALUES: &[f32] = &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0];
705 for i in 0..8 {
706 let vec_values = <[f32; 8]>::from(Vec8f::load_partial(&VALUES[..i]));
707 assert_eq!(vec_values[..i], VALUES[..i]);
708 assert!(vec_values[i..].iter().all(|x| *x == 0.0));
709 }
710 assert_eq!(
711 Vec8f::load_partial(VALUES),
712 Vec8f::from(&VALUES[..8].try_into().unwrap())
713 );
714 }
715
716 #[cfg(avx)]
717 #[test]
718 fn test_m256_conv() {
719 use crate::{intrinsics::__m256, Vec4f};
720 let vec = Vec8f::join(Vec4f::broadcast(1.0), Vec4f::broadcast(2.0));
721 assert_eq!(vec, __m256::from(vec).into());
722 }
723}