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