|
1 | 1 | use crate::intrinsics;
|
2 | 2 | use crate::masks::*;
|
3 |
| -use crate::vector::ptr::SimdConstPtr; |
| 3 | +use crate::vector::ptr::{SimdConstPtr, SimdMutPtr}; |
4 | 4 | use crate::vector::*;
|
5 | 5 |
|
6 | 6 | /// A representation of a vector as an "array" with indices, implementing
|
|
83 | 83 | // SAFETY: The ptrs have been bounds-masked to prevent memory-unsafe reads insha'allah
|
84 | 84 | unsafe { intrinsics::simd_gather(or, ptrs, mask) }
|
85 | 85 | }
|
| 86 | + |
| 87 | + /// SIMD scatter: write a SIMD vector's values into a slice, using potentially discontiguous indices. |
| 88 | + /// Out-of-bounds indices are not written. |
| 89 | + /// ``` |
| 90 | + /// # use core_simd::*; |
| 91 | + /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; |
| 92 | + /// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 5]); |
| 93 | + /// let vals = SimdI32::from_array([-5, -4, -3, -2]); |
| 94 | + /// |
| 95 | + /// vals.scatter(&mut vec, idxs); |
| 96 | + /// assert_eq!(vec, vec![-3, 11, 12, -4, 14, -2, 16, 17, 18]); |
| 97 | + /// ``` |
| 98 | + #[inline] |
| 99 | + fn scatter(self, slice: &mut [Self::Scalar], idxs: SimdUsize<LANES>) { |
| 100 | + self.scatter_select(slice, MaskSize::splat(true), idxs) |
| 101 | + } |
| 102 | + |
| 103 | + /// SIMD scatter: write a SIMD vector's values into a slice, using potentially discontiguous indices. |
| 104 | + /// Out-of-bounds or masked indices are not written. |
| 105 | + /// ``` |
| 106 | + /// # use core_simd::*; |
| 107 | + /// let mut vec: Vec<i32> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; |
| 108 | + /// let idxs = SimdUsize::<4>::from_array([9, 3, 0, 5]); |
| 109 | + /// let vals = SimdI32::from_array([-5, -4, -3, -2]); |
| 110 | + /// let mask = MaskSize::from_array([true, true, true, false]); // Note the mask of the last lane. |
| 111 | + /// |
| 112 | + /// vals.scatter_select(&mut vec, mask, idxs); |
| 113 | + /// assert_eq!(vec, vec![-3, 11, 12, -4, 14, 15, 16, 17, 18]); |
| 114 | + /// ``` |
| 115 | + #[inline] |
| 116 | + fn scatter_select( |
| 117 | + self, |
| 118 | + slice: &mut [Self::Scalar], |
| 119 | + mask: MaskSize<LANES>, |
| 120 | + idxs: SimdUsize<LANES>, |
| 121 | + ) { |
| 122 | + // We must construct our scatter mask before we derive a pointer! |
| 123 | + let mask = (mask & idxs.lanes_lt(SimdUsize::splat(slice.len()))).to_int(); |
| 124 | + // SAFETY: This block works with *mut T derived from &mut 'a [T], |
| 125 | + // which means it is delicate in Rust's borrowing model, circa 2021: |
| 126 | + // &mut 'a [T] asserts uniqueness, so deriving &'a [T] invalidates live *mut Ts! |
| 127 | + // Even though this block is largely safe methods, it must be almost exactly this way |
| 128 | + // to prevent invalidating the raw ptrs while they're live. |
| 129 | + // Thus, entering this block requires all values to use being already ready: |
| 130 | + // 0. idxs we want to write to, which are used to construct the mask. |
| 131 | + // 1. mask, which depends on an initial &'a [T] and the idxs. |
| 132 | + // 2. actual values to scatter (self). |
| 133 | + // 3. &mut [T] which will become our base ptr. |
| 134 | + unsafe { |
| 135 | + // Now Entering ☢️ *mut T Zone |
| 136 | + let base_ptr = SimdMutPtr::splat(slice.as_mut_ptr()); |
| 137 | + // Ferris forgive me, I have done pointer arithmetic here. |
| 138 | + let ptrs = base_ptr.wrapping_add(idxs); |
| 139 | + // The ptrs have been bounds-masked to prevent memory-unsafe writes insha'allah |
| 140 | + intrinsics::simd_scatter(self, ptrs, mask) |
| 141 | + // Cleared ☢️ *mut T Zone |
| 142 | + } |
| 143 | + } |
86 | 144 | }
|
87 | 145 |
|
88 | 146 | macro_rules! impl_simdarray_for {
|
|
0 commit comments