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