]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | //! Implements masked gather and scatters for vectors of pointers |
2 | ||
3 | macro_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 | ||
108 | macro_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 | } |