Skip to main content

core/stdarch/crates/core_arch/src/loongarch64/
simd.rs

1//! LoongArch64 SIMD helpers
2
3use self as ls;
4use crate::intrinsics::simd as is;
5
6// Internal extension trait for concrete `Simd<T, N>` types.
7//
8// Provides a small set of helper functionality (`Elem` and `splat`)
9// so generic and macro-based code can operate on different SIMD
10// vector types in a uniform way.
11pub(super) const trait SimdExt: Sized {
12    type Elem;
13
14    unsafe fn splat(v: i64) -> Self;
15}
16
17#[rustfmt::skip] // FIXME: https://github.com/rust-lang/stdarch/pull/2133#issuecomment-4524350350
18macro_rules! impl_simd_ext {
19    ($v:ident, $e:ty) => {
20        #[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
21        impl const SimdExt for crate::core_arch::simd::$v {
22            type Elem = $e;
23
24            #[inline(always)]
25            unsafe fn splat(v: i64) -> Self {
26                is::simd_splat(v as Self::Elem)
27            }
28        }
29    };
30}
31
32impl_simd_ext!(i8x16, i8);
33impl_simd_ext!(i8x32, i8);
34impl_simd_ext!(u8x16, u8);
35impl_simd_ext!(u8x32, u8);
36impl_simd_ext!(i16x8, i16);
37impl_simd_ext!(i16x16, i16);
38impl_simd_ext!(u16x8, u16);
39impl_simd_ext!(u16x16, u16);
40impl_simd_ext!(i32x4, i32);
41impl_simd_ext!(i32x8, i32);
42impl_simd_ext!(u32x4, u32);
43impl_simd_ext!(u32x8, u32);
44impl_simd_ext!(i64x2, i64);
45impl_simd_ext!(i64x4, i64);
46impl_simd_ext!(u64x2, u64);
47impl_simd_ext!(u64x4, u64);
48
49#[inline(always)]
50#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
51pub(super) const unsafe fn simd_abs<T: Copy + const SimdExt>(a: T) -> T {
52    let m: T = is::simd_lt(a, ls::simd_splat(0));
53    is::simd_select(m, is::simd_neg(a), a)
54}
55
56#[inline(always)]
57#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
58pub(super) const unsafe fn simd_absd<T: Copy>(a: T, b: T) -> T {
59    let m: T = is::simd_gt(a, b);
60    is::simd_select(m, is::simd_sub(a, b), is::simd_sub(b, a))
61}
62
63#[inline(always)]
64#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
65pub(super) const unsafe fn simd_adda<T: Copy + const SimdExt>(a: T, b: T) -> T {
66    is::simd_add(ls::simd_abs(a), ls::simd_abs(b))
67}
68
69#[inline(always)]
70#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
71pub(super) const unsafe fn simd_andn<T: Copy + const SimdExt>(a: T, b: T) -> T {
72    is::simd_and(ls::simd_not(a), b)
73}
74
75#[inline(always)]
76#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
77pub(super) const unsafe fn simd_bitclr<T: Copy + const SimdExt>(a: T, b: T) -> T {
78    ls::simd_andn(ls::simd_shl(ls::simd_splat(1), b), a)
79}
80
81#[inline(always)]
82#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
83pub(super) const unsafe fn simd_bitrev<T: Copy + const SimdExt>(a: T, b: T) -> T {
84    is::simd_xor(ls::simd_shl(ls::simd_splat(1), b), a)
85}
86
87#[inline(always)]
88#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
89pub(super) const unsafe fn simd_bitset<T: Copy + const SimdExt>(a: T, b: T) -> T {
90    is::simd_or(ls::simd_shl(ls::simd_splat(1), b), a)
91}
92
93#[inline(always)]
94#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
95pub(super) const unsafe fn simd_fmsub<T: Copy>(a: T, b: T, c: T) -> T {
96    is::simd_fma(a, b, is::simd_neg(c))
97}
98
99#[inline(always)]
100#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
101pub(super) const unsafe fn simd_fnmadd<T: Copy>(a: T, b: T, c: T) -> T {
102    is::simd_neg(is::simd_fma(a, b, c))
103}
104
105#[inline(always)]
106#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
107pub(super) const unsafe fn simd_fnmsub<T: Copy>(a: T, b: T, c: T) -> T {
108    is::simd_neg(ls::simd_fmsub(a, b, c))
109}
110
111#[inline(always)]
112#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
113pub(super) const unsafe fn simd_madd<T: Copy>(a: T, b: T, c: T) -> T {
114    is::simd_add(a, is::simd_mul(b, c))
115}
116
117#[inline(always)]
118#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
119pub(super) const unsafe fn simd_msub<T: Copy>(a: T, b: T, c: T) -> T {
120    is::simd_sub(a, is::simd_mul(b, c))
121}
122
123#[inline(always)]
124#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
125pub(super) const unsafe fn simd_nor<T: Copy + const SimdExt>(a: T, b: T) -> T {
126    ls::simd_not(is::simd_or(a, b))
127}
128
129#[inline(always)]
130#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
131pub(super) const unsafe fn simd_not<T: Copy + const SimdExt>(a: T) -> T {
132    is::simd_xor(a, ls::simd_splat(!0))
133}
134
135#[inline(always)]
136#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
137pub(super) const unsafe fn simd_orn<T: Copy + const SimdExt>(a: T, b: T) -> T {
138    is::simd_or(a, ls::simd_not(b))
139}
140
141#[inline(always)]
142#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
143pub(super) const unsafe fn simd_shl<T: Copy + const SimdExt>(a: T, b: T) -> T {
144    let m = (size_of::<T::Elem>() * 8 - 1) as i64;
145    is::simd_shl(a, is::simd_and(b, ls::simd_splat(m)))
146}
147
148#[inline(always)]
149#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
150pub(super) const unsafe fn simd_shr<T: Copy + const SimdExt>(a: T, b: T) -> T {
151    let m = (size_of::<T::Elem>() * 8 - 1) as i64;
152    is::simd_shr(a, is::simd_and(b, ls::simd_splat(m)))
153}
154
155#[inline(always)]
156#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
157pub(super) const unsafe fn simd_splat<T: Copy + const SimdExt>(a: i64) -> T {
158    T::splat(a)
159}
160
161macro_rules! impl_vv {
162    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ty) => {
163        #[inline]
164        #[target_feature(enable = $ft)]
165        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
166        pub fn $name(a: $oty) -> $oty {
167            unsafe {
168                let a: $ity = transmute(a);
169                let r: $ity = $op(a);
170                transmute(r)
171            }
172        }
173    };
174}
175
176pub(super) use impl_vv;
177
178macro_rules! impl_gv {
179    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident, $gty:ty) => {
180        #[inline]
181        #[target_feature(enable = $ft)]
182        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
183        pub fn $name(a: $gty) -> $oty {
184            unsafe {
185                let r: $ity = $op(a.into());
186                transmute(r)
187            }
188        }
189    };
190}
191
192pub(super) use impl_gv;
193
194macro_rules! impl_sv {
195    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident, $ibs:expr) => {
196        #[inline]
197        #[target_feature(enable = $ft)]
198        #[rustc_legacy_const_generics(0)]
199        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
200        pub fn $name<const IMM: i32>() -> $oty {
201            static_assert_simm_bits!(IMM, $ibs);
202            unsafe {
203                let r: $ity = $op(IMM.into());
204                transmute(r)
205            }
206        }
207    };
208}
209
210pub(super) use impl_sv;
211
212macro_rules! impl_vvv {
213    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ty) => {
214        #[inline]
215        #[target_feature(enable = $ft)]
216        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
217        pub fn $name(a: $oty, b: $oty) -> $oty {
218            unsafe {
219                let a: $ity = transmute(a);
220                let b: $ity = transmute(b);
221                let r: $ity = $op(a, b);
222                transmute(r)
223            }
224        }
225    };
226}
227
228pub(super) use impl_vvv;
229
230macro_rules! impl_vuv {
231    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident) => {
232        #[inline]
233        #[target_feature(enable = $ft)]
234        #[rustc_legacy_const_generics(1)]
235        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
236        pub fn $name<const IMM: u32>(a: $oty) -> $oty {
237            static_assert_uimm_bits!(IMM, (size_of::<<$ity as SimdExt>::Elem>() * 8).ilog2());
238            unsafe {
239                let a: $ity = transmute(a);
240                let b: $ity = ls::simd_splat(IMM.into());
241                let r: $ity = $op(a, b);
242                transmute(r)
243            }
244        }
245    };
246    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident, $ibs:expr) => {
247        #[inline]
248        #[target_feature(enable = $ft)]
249        #[rustc_legacy_const_generics(1)]
250        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
251        pub fn $name<const IMM: u32>(a: $oty) -> $oty {
252            static_assert_uimm_bits!(IMM, $ibs);
253            unsafe {
254                let a: $ity = transmute(a);
255                let b: $ity = ls::simd_splat(IMM.into());
256                let r: $ity = $op(a, b);
257                transmute(r)
258            }
259        }
260    };
261    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr, const) => {
262        #[inline]
263        #[target_feature(enable = $ft)]
264        #[rustc_legacy_const_generics(1)]
265        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
266        pub fn $name<const IMM: u32>(a: $oty) -> $oty {
267            static_assert_uimm_bits!(IMM, $ibs);
268            unsafe {
269                let a: $ity = transmute(a);
270                let r: $ity = $op::<IMM, _>(a);
271                transmute(r)
272            }
273        }
274    };
275}
276
277pub(super) use impl_vuv;
278
279macro_rules! impl_vug {
280    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident, $gty:ty, $ibs:expr) => {
281        #[inline]
282        #[target_feature(enable = $ft)]
283        #[rustc_legacy_const_generics(1)]
284        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
285        pub fn $name<const IMM: u32>(a: $oty) -> $gty {
286            static_assert_uimm_bits!(IMM, $ibs);
287            unsafe {
288                let a: $ity = transmute(a);
289                let r: <$ity as SimdExt>::Elem = $op(a, IMM);
290                r as $gty
291            }
292        }
293    };
294}
295
296pub(super) use impl_vug;
297
298macro_rules! impl_vsv {
299    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident, $ibs:expr) => {
300        #[inline]
301        #[target_feature(enable = $ft)]
302        #[rustc_legacy_const_generics(1)]
303        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
304        pub fn $name<const IMM: i32>(a: $oty) -> $oty {
305            static_assert_simm_bits!(IMM, $ibs);
306            unsafe {
307                let a: $ity = transmute(a);
308                let b: $ity = ls::simd_splat(IMM.into());
309                let r: $ity = $op(a, b);
310                transmute(r)
311            }
312        }
313    };
314}
315
316pub(super) use impl_vsv;
317
318macro_rules! impl_vvvv {
319    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ty) => {
320        #[inline]
321        #[target_feature(enable = $ft)]
322        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
323        pub fn $name(a: $oty, b: $oty, c: $oty) -> $oty {
324            unsafe {
325                let a: $ity = transmute(a);
326                let b: $ity = transmute(b);
327                let c: $ity = transmute(c);
328                let r: $ity = $op(a, b, c);
329                transmute(r)
330            }
331        }
332    };
333}
334
335pub(super) use impl_vvvv;
336
337macro_rules! impl_vvuv {
338    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr, const) => {
339        #[inline]
340        #[target_feature(enable = $ft)]
341        #[rustc_legacy_const_generics(2)]
342        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
343        pub fn $name<const IMM: u32>(a: $oty, b: $oty) -> $oty {
344            static_assert_uimm_bits!(IMM, $ibs);
345            unsafe {
346                let a: $ity = transmute(a);
347                let b: $ity = transmute(b);
348                let r: $ity = $op::<IMM, _>(a, b);
349                transmute(r)
350            }
351        }
352    };
353}
354
355pub(super) use impl_vvuv;
356
357macro_rules! impl_vugv {
358    ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident, $gty:ty, $ibs:expr) => {
359        #[inline]
360        #[target_feature(enable = $ft)]
361        #[rustc_legacy_const_generics(2)]
362        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
363        pub fn $name<const IMM: u32>(a: $oty, b: $gty) -> $oty {
364            static_assert_uimm_bits!(IMM, $ibs);
365            unsafe {
366                let a: $ity = transmute(a);
367                let r: $ity = $op(a, IMM, b as <$ity as SimdExt>::Elem);
368                transmute(r)
369            }
370        }
371    };
372}
373
374pub(super) use impl_vugv;