core/stdarch/crates/core_arch/src/
macros.rs1#[allow(unused)]
4macro_rules! static_assert {
5 ($e:expr) => {
6 const {
7 assert!($e);
8 }
9 };
10 ($e:expr, $msg:expr) => {
11 const {
12 assert!($e, $msg);
13 }
14 };
15}
16
17#[allow(unused_macros)]
18macro_rules! static_assert_uimm_bits {
19 ($imm:ident, $bits:expr) => {
20 #[allow(unused_comparisons)]
22 {
23 static_assert!(
24 0 <= $imm && $imm < (1 << $bits),
25 concat!(
26 stringify!($imm),
27 " doesn't fit in ",
28 stringify!($bits),
29 " bits",
30 )
31 )
32 }
33 };
34}
35
36#[allow(unused_macros)]
37macro_rules! static_assert_simm_bits {
38 ($imm:ident, $bits:expr) => {
39 static_assert!(
40 (-1 << ($bits - 1)) - 1 <= $imm && $imm < (1 << ($bits - 1)),
41 concat!(
42 stringify!($imm),
43 " doesn't fit in ",
44 stringify!($bits),
45 " bits",
46 )
47 )
48 };
49}
50
51#[allow(unused)]
52macro_rules! types {
53 (
54 #![$stability_first:meta]
55 $(
56 #![$stability_more:meta]
57 )*
58
59 $(
60 $(#[$doc:meta])*
61 $(stability: [$stability_already: meta])*
62 pub struct $name:ident($len:literal x $v:vis $elem_type:ty);
63 )*
64 ) => (types! {
65 $(
66 #![$stability_more]
67 )*
68
69 $(
70 $(#[$doc])*
71 $(stability: [$stability_already])*
72 stability: [$stability_first]
73 pub struct $name($len x $v $elem_type);
74 )*
75 });
76
77 (
78 $(
79 $(#[$doc:meta])*
80 $(stability: [$stability: meta])+
81 pub struct $name:ident($len:literal x $v:vis $elem_type:ty);
82 )*
83 ) => ($(
84 $(#[$doc])*
85 $(#[$stability])+
86 #[derive(Copy, Clone)]
87 #[allow(non_camel_case_types)]
88 #[repr(simd)]
89 #[allow(clippy::missing_inline_in_public_items)]
90 pub struct $name($v [$elem_type; $len]);
91
92 impl $name {
93 #[inline(always)]
95 $v fn splat(value: $elem_type) -> $name {
96 unsafe { $crate::intrinsics::simd::simd_splat(value) }
97 }
98
99 $v const fn as_array(&self) -> &[$elem_type; $len] {
101 unsafe { &*(self as *const Self as *const [$elem_type; $len]) }
108
109 }
110
111 #[inline]
113 $v fn as_mut_array(&mut self) -> &mut [$elem_type; $len] {
114 unsafe { &mut *(self as *mut Self as *mut [$elem_type; $len]) }
121 }
122 }
123
124 $(#[$stability])+
125 impl crate::fmt::Debug for $name {
126 #[inline]
127 fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result {
128 crate::core_arch::simd::debug_simd_finish(f, stringify!($name), self.as_array())
129 }
130 }
131
132 $(#[$stability])+
133 impl crate::convert::From<crate::core_arch::simd::Simd<$elem_type, $len>> for $name {
134 #[inline(always)]
135 fn from(simd: crate::core_arch::simd::Simd<$elem_type, $len>) -> Self {
136 unsafe { crate::mem::transmute(simd) }
137 }
138 }
139
140 $(#[$stability])+
141 impl crate::convert::From<$name> for crate::core_arch::simd::Simd<$elem_type, $len> {
142 #[inline(always)]
143 fn from(simd: $name) -> Self {
144 unsafe { crate::mem::transmute(simd) }
145 }
146 }
147 )*);
148}
149
150#[allow(unused)]
151#[repr(simd)]
152pub(crate) struct SimdShuffleIdx<const LEN: usize>(pub(crate) [u32; LEN]);
153
154#[allow(unused)]
155macro_rules! simd_shuffle {
156 ($x:expr, $y:expr, $idx:expr $(,)?) => {{
157 $crate::intrinsics::simd::simd_shuffle(
158 $x,
159 $y,
160 const { $crate::core_arch::macros::SimdShuffleIdx($idx) },
161 )
162 }};
163}
164
165#[allow(unused)]
166macro_rules! simd_insert {
167 ($x:expr, $idx:expr, $val:expr $(,)?) => {{ $crate::intrinsics::simd::simd_insert($x, const { $idx }, $val) }};
168}
169
170#[allow(unused)]
171macro_rules! simd_extract {
172 ($x:expr, $idx:expr $(,)?) => {{ $crate::intrinsics::simd::simd_extract($x, const { $idx }) }};
173 ($x:expr, $idx:expr, $ty:ty $(,)?) => {{ $crate::intrinsics::simd::simd_extract::<_, $ty>($x, const { $idx }) }};
174}
175
176#[allow(unused)]
177macro_rules! simd_masked_load {
178 ($align:expr, $mask:expr, $ptr:expr, $default:expr) => {
179 $crate::intrinsics::simd::simd_masked_load::<_, _, _, { $align }>($mask, $ptr, $default)
180 };
181}
182
183#[allow(unused)]
184macro_rules! simd_masked_store {
185 ($align:expr, $mask:expr, $ptr:expr, $default:expr) => {
186 $crate::intrinsics::simd::simd_masked_store::<_, _, _, { $align }>($mask, $ptr, $default)
187 };
188}
189
190pub(crate) const fn identity<const N: usize>() -> [u32; N] {
192 let mut out = [0u32; N];
193 let mut i = 0usize;
194 while i < N {
195 out[i] = i as u32;
196 i += 1;
197 }
198 out
199}
200
201pub(crate) const fn even<const N: usize>() -> [u32; N] {
203 let mut out = [0u32; N];
204 let mut i = 0usize;
205 while i < N {
206 out[i] = (2 * i) as u32;
207 i += 1;
208 }
209 out
210}
211
212pub(crate) const fn odd<const N: usize>() -> [u32; N] {
214 let mut out = [0u32; N];
215 let mut i = 0usize;
216 while i < N {
217 out[i] = (2 * i + 1) as u32;
218 i += 1;
219 }
220 out
221}
222
223pub(crate) const fn deinterleave_mask<const LANES: usize, const N: usize, const K: usize>()
225-> [u32; LANES] {
226 let mut out = [0u32; LANES];
227 let mut i = 0usize;
228 while i < LANES {
229 out[i] = (i * N + K) as u32;
230 i += 1;
231 }
232 out
233}
234
235#[allow(unused)]
236macro_rules! deinterleaving_load {
237 ($elem:ty, $lanes:literal, 2, $ptr:expr) => {{
238 use $crate::core_arch::macros::deinterleave_mask;
239 use $crate::core_arch::simd::Simd;
240 use $crate::mem::transmute;
241
242 type V = Simd<$elem, $lanes>;
243 type W = Simd<$elem, { $lanes * 2 }>;
244
245 let w: W = $crate::ptr::read_unaligned($ptr as *const W);
246
247 let v0: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 2, 0>());
248 let v1: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 2, 1>());
249
250 transmute((v0, v1))
251 }};
252
253 ($elem:ty, $lanes:literal, 3, $ptr:expr) => {{
254 use $crate::core_arch::macros::deinterleave_mask;
255 use $crate::core_arch::simd::Simd;
256 use $crate::mem::{MaybeUninit, transmute};
257
258 type V = Simd<$elem, $lanes>;
259 type W = Simd<$elem, { $lanes * 3 }>;
260
261 let mut mem = MaybeUninit::<W>::uninit();
264 $crate::ptr::copy_nonoverlapping(
265 $ptr.cast::<$elem>(),
266 mem.as_mut_ptr().cast::<$elem>(),
267 $lanes * 3,
268 );
269 let w = mem.assume_init();
270
271 let v0: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 3, 0>());
272 let v1: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 3, 1>());
273 let v2: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 3, 2>());
274
275 transmute((v0, v1, v2))
276 }};
277
278 ($elem:ty, $lanes:literal, 4, $ptr:expr) => {{
279 use $crate::core_arch::macros::deinterleave_mask;
280 use $crate::core_arch::simd::Simd;
281 use $crate::mem::transmute;
282
283 type V = Simd<$elem, $lanes>;
284 type W = Simd<$elem, { $lanes * 4 }>;
285
286 let w: W = $crate::ptr::read_unaligned($ptr as *const W);
287
288 let v0: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 4, 0>());
289 let v1: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 4, 1>());
290 let v2: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 4, 2>());
291 let v3: V = simd_shuffle!(w, w, deinterleave_mask::<$lanes, 4, 3>());
292
293 transmute((v0, v1, v2, v3))
294 }};
295}
296
297#[allow(unused)]
298pub(crate) use deinterleaving_load;
299
300pub(crate) const fn interleave_mask<const LANES: usize, const N: usize, const K: usize>()
301-> [u32; LANES] {
302 let mut out = [0u32; LANES];
303 let mut j = 0usize;
304 while j < LANES {
305 out[j] = ((j % K) * N + j / K) as u32;
306 j += 1;
307 }
308 out
309}
310
311#[allow(unused)]
312macro_rules! interleaving_store {
313 ($elem:ty, $lanes:literal, 2, $ptr:expr, $v:expr) => {{
314 use $crate::core_arch::macros::interleave_mask;
315 use $crate::core_arch::simd::Simd;
316
317 type W = Simd<$elem, { $lanes * 2 }>;
318 let w: W = simd_shuffle!($v.0, $v.1, interleave_mask::<{ $lanes * 2 }, $lanes, 2>());
319 $crate::ptr::write_unaligned($ptr as *mut W, w);
320 }};
321
322 ($elem:ty, $lanes:literal, 3, $ptr:expr, $v:expr) => {{
324 use $crate::core_arch::macros::{identity, interleave_mask};
325 use $crate::core_arch::simd::Simd;
326
327 let v0v1: Simd<$elem, { $lanes * 2 }> =
328 simd_shuffle!($v.0, $v.1, identity::<{ $lanes * 2 }>());
329 let v2v2: Simd<$elem, { $lanes * 2 }> =
330 simd_shuffle!($v.2, $v.2, identity::<{ $lanes * 2 }>());
331
332 type W = Simd<$elem, { $lanes * 3 }>;
333
334 let w: W = simd_shuffle!(v0v1, v2v2, interleave_mask::<{ $lanes * 3 }, $lanes, 3>());
337 $crate::ptr::copy_nonoverlapping(
338 (&w as *const W).cast::<$elem>(),
339 $ptr.cast::<$elem>(),
340 $lanes * 3,
341 );
342 }};
343
344 ($elem:ty, $lanes:literal, 4, $ptr:expr, $v:expr) => {{
346 use $crate::core_arch::macros::{identity, interleave_mask};
347 use $crate::core_arch::simd::Simd;
348
349 let v0v1: Simd<$elem, { $lanes * 2 }> =
350 simd_shuffle!($v.0, $v.1, identity::<{ $lanes * 2 }>());
351 let v2v3: Simd<$elem, { $lanes * 2 }> =
352 simd_shuffle!($v.2, $v.3, identity::<{ $lanes * 2 }>());
353
354 type W = Simd<$elem, { $lanes * 4 }>;
355 let w: W = simd_shuffle!(v0v1, v2v3, interleave_mask::<{ $lanes * 4 }, $lanes, 4>());
356 $crate::ptr::write_unaligned($ptr as *mut W, w);
357 }};
358}
359
360#[allow(unused)]
361pub(crate) use interleaving_store;