]> git.proxmox.com Git - rustc.git/blame - vendor/packed_simd/src/api/ptr/gather_scatter.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / vendor / packed_simd / src / api / ptr / gather_scatter.rs
CommitLineData
f20569fa
XL
1//! Implements masked gather and scatters for vectors of pointers
2
3macro_rules! impl_ptr_read {
4 ([$elem_ty:ty; $elem_count:expr]: $id:ident, $mask_ty:ident
5 | $test_tt:tt) => {
6 impl<T> $id<T>
7 where
8 [T; $elem_count]: sealed::SimdArray,
9 {
10 /// Reads selected vector elements from memory.
11 ///
12 /// Instantiates a new vector by reading the values from `self` for
13 /// those lanes whose `mask` is `true`, and using the elements of
14 /// `value` otherwise.
15 ///
16 /// No memory is accessed for those lanes of `self` whose `mask` is
17 /// `false`.
18 ///
19 /// # Safety
20 ///
21 /// This method is unsafe because it dereferences raw pointers. The
22 /// pointers must be aligned to `mem::align_of::<T>()`.
23 #[inline]
24 pub unsafe fn read<M>(
25 self, mask: Simd<[M; $elem_count]>,
26 value: Simd<[T; $elem_count]>,
27 ) -> Simd<[T; $elem_count]>
28 where
29 M: sealed::Mask,
30 [M; $elem_count]: sealed::SimdArray,
31 {
32 use crate::llvm::simd_gather;
33 Simd(simd_gather(value.0, self.0, mask.0))
34 }
35 }
36
37 test_if! {
38 $test_tt:
39 paste::item! {
40 mod [<$id _read>] {
41 use super::*;
42 #[test]
43 fn read() {
44 let mut v = [0_i32; $elem_count];
45 for i in 0..$elem_count {
46 v[i] = i as i32;
47 }
48
49 let mut ptr = $id::<i32>::null();
50
51 for i in 0..$elem_count {
52 ptr = ptr.replace(i, unsafe {
53 crate::mem::transmute(&v[i] as *const i32)
54 });
55 }
56
57 // all mask elements are true:
58 let mask = $mask_ty::splat(true);
59 let def = Simd::<[i32; $elem_count]>::splat(42_i32);
60 let r: Simd<[i32; $elem_count]> = unsafe {
61 ptr.read(mask, def)
62 };
63 assert_eq!(
64 r,
65 Simd::<[i32; $elem_count]>::from_slice_unaligned(
66 &v
67 )
68 );
69
70 let mut mask = mask;
71 for i in 0..$elem_count {
72 if i % 2 != 0 {
73 mask = mask.replace(i, false);
74 }
75 }
76
77 // even mask elements are true, odd ones are false:
78 let r: Simd<[i32; $elem_count]> = unsafe {
79 ptr.read(mask, def)
80 };
81 let mut e = v;
82 for i in 0..$elem_count {
83 if i % 2 != 0 {
84 e[i] = 42;
85 }
86 }
87 assert_eq!(
88 r,
89 Simd::<[i32; $elem_count]>::from_slice_unaligned(
90 &e
91 )
92 );
93
94 // all mask elements are false:
95 let mask = $mask_ty::splat(false);
96 let def = Simd::<[i32; $elem_count]>::splat(42_i32);
97 let r: Simd<[i32; $elem_count]> = unsafe {
98 ptr.read(mask, def) }
99 ;
100 assert_eq!(r, def);
101 }
102 }
103 }
104 }
105 };
106}
107
108macro_rules! impl_ptr_write {
109 ([$elem_ty:ty; $elem_count:expr]: $id:ident, $mask_ty:ident
110 | $test_tt:tt) => {
111 impl<T> $id<T>
112 where
113 [T; $elem_count]: sealed::SimdArray,
114 {
115 /// Writes selected vector elements to memory.
116 ///
117 /// Writes the lanes of `values` for which the mask is `true` to
118 /// their corresponding memory addresses in `self`.
119 ///
120 /// No memory is accessed for those lanes of `self` whose `mask` is
121 /// `false`.
122 ///
123 /// Overlapping memory addresses of `self` are written to in order
124 /// from the lest-significant to the most-significant element.
125 ///
126 /// # Safety
127 ///
128 /// This method is unsafe because it dereferences raw pointers. The
129 /// pointers must be aligned to `mem::align_of::<T>()`.
130 #[inline]
131 pub unsafe fn write<M>(
132 self, mask: Simd<[M; $elem_count]>,
133 value: Simd<[T; $elem_count]>,
134 ) where
135 M: sealed::Mask,
136 [M; $elem_count]: sealed::SimdArray,
137 {
138 // FIXME:
139 // https://github.com/rust-lang-nursery/packed_simd/issues/85
140 #[cfg(not(target_arch = "mips"))]
141 {
142 use crate::llvm::simd_scatter;
143 simd_scatter(value.0, self.0, mask.0)
144 }
145 #[cfg(target_arch = "mips")]
146 {
147 let m_ptr =
148 &mask as *const Simd<[M; $elem_count]> as *const M;
149 for i in 0..$elem_count {
150 let m = ptr::read(m_ptr.add(i));
151 if m.test() {
152 let t_ptr = &self
153 as *const Simd<[*mut T; $elem_count]>
154 as *mut *mut T;
155 let v_ptr = &value as *const Simd<[T; $elem_count]>
156 as *const T;
157 ptr::write(
158 ptr::read(t_ptr.add(i)),
159 ptr::read(v_ptr.add(i)),
160 );
161 }
162 }
163 }
164 }
165 }
166
167 test_if! {
168 $test_tt:
169 paste::item! {
170 mod [<$id _write>] {
171 use super::*;
172 #[test]
173 fn write() {
174 // fourty_two = [42, 42, 42, ...]
175 let fourty_two
176 = Simd::<[i32; $elem_count]>::splat(42_i32);
177
178 // This test will write to this array
179 let mut arr = [0_i32; $elem_count];
180 for i in 0..$elem_count {
181 arr[i] = i as i32;
182 }
183 // arr = [0, 1, 2, ...]
184
185 let mut ptr = $id::<i32>::null();
186 for i in 0..$elem_count {
187 ptr = ptr.replace(i, unsafe {
188 crate::mem::transmute(arr.as_ptr().add(i))
189 });
190 }
191 // ptr = [&arr[0], &arr[1], ...]
192
193 // write `fourty_two` to all elements of `v`
194 {
195 let backup = arr;
196 unsafe {
197 ptr.write($mask_ty::splat(true), fourty_two)
198 };
199 assert_eq!(arr, [42_i32; $elem_count]);
200 arr = backup; // arr = [0, 1, 2, ...]
201 }
202
203 // write 42 to even elements of arr:
204 {
205 // set odd elements of the mask to false
206 let mut mask = $mask_ty::splat(true);
207 for i in 0..$elem_count {
208 if i % 2 != 0 {
209 mask = mask.replace(i, false);
210 }
211 }
212 // mask = [true, false, true, false, ...]
213
214 // expected result r = [42, 1, 42, 3, 42, 5, ...]
215 let mut r = arr;
216 for i in 0..$elem_count {
217 if i % 2 == 0 {
218 r[i] = 42;
219 }
220 }
221
222 let backup = arr;
223 unsafe { ptr.write(mask, fourty_two) };
224 assert_eq!(arr, r);
225 arr = backup; // arr = [0, 1, 2, 3, ...]
226 }
227
228 // write 42 to no elements of arr
229 {
230 let backup = arr;
231 unsafe {
232 ptr.write($mask_ty::splat(false), fourty_two)
233 };
234 assert_eq!(arr, backup);
235 }
236 }
237 }
238 }
239 }
240 };
241}