Skip to main content

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

1//! LoongArch64 SIMD helpers
2
3use crate::intrinsics::simd::*;
4
5// Internal extension trait for concrete `Simd<T, N>` types.
6//
7// Provides a small set of helper functionality (`Elem` and `splat`)
8// so generic and macro-based code can operate on different SIMD
9// vector types in a uniform way.
10pub(super) const trait SimdExt: Sized {
11    type Elem;
12
13    unsafe fn splat(v: i64) -> Self;
14}
15
16#[rustfmt::skip] // FIXME: https://github.com/rust-lang/stdarch/pull/2133#issuecomment-4524350350
17macro_rules! impl_simd_ext {
18    ($v:ident, $e:ty) => {
19        #[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
20        const impl SimdExt for crate::core_arch::simd::$v {
21            type Elem = $e;
22
23            #[inline(always)]
24            unsafe fn splat(v: i64) -> Self {
25                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!(i16x32, i16);
38impl_simd_ext!(u16x8, u16);
39impl_simd_ext!(u16x16, u16);
40impl_simd_ext!(u16x32, u16);
41impl_simd_ext!(i32x4, i32);
42impl_simd_ext!(i32x8, i32);
43impl_simd_ext!(i32x16, i32);
44impl_simd_ext!(u32x4, u32);
45impl_simd_ext!(u32x8, u32);
46impl_simd_ext!(u32x16, u32);
47impl_simd_ext!(i64x2, i64);
48impl_simd_ext!(i64x4, i64);
49impl_simd_ext!(i64x8, i64);
50impl_simd_ext!(u64x2, u64);
51impl_simd_ext!(u64x4, u64);
52impl_simd_ext!(u64x8, u64);
53impl_simd_ext!(i128x2, i128);
54impl_simd_ext!(u128x2, u128);
55impl_simd_ext!(i128x4, i128);
56impl_simd_ext!(u128x4, u128);
57
58#[inline(always)]
59#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
60pub(super) const unsafe fn simd_ext_abs<T: Copy + const SimdExt>(a: T) -> T {
61    let m: T = simd_lt(a, simd_ext_splat(0));
62    simd_select(m, simd_neg(a), a)
63}
64
65#[inline(always)]
66#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
67pub(super) const unsafe fn simd_ext_absd<T: Copy>(a: T, b: T) -> T {
68    let m: T = simd_gt(a, b);
69    simd_select(m, simd_sub(a, b), simd_sub(b, a))
70}
71
72#[inline(always)]
73#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
74pub(super) const unsafe fn simd_ext_adda<T: Copy + const SimdExt>(a: T, b: T) -> T {
75    simd_add(simd_ext_abs(a), simd_ext_abs(b))
76}
77
78#[inline(always)]
79#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
80pub(super) const unsafe fn simd_ext_andn<T: Copy + const SimdExt>(a: T, b: T) -> T {
81    simd_and(simd_ext_not(a), b)
82}
83
84#[inline(always)]
85#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
86pub(super) const unsafe fn simd_ext_bitclr<T: Copy + const SimdExt>(a: T, b: T) -> T {
87    simd_ext_andn(simd_ext_shl(simd_ext_splat(1), b), a)
88}
89
90#[inline(always)]
91#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
92pub(super) const unsafe fn simd_ext_bitrev<T: Copy + const SimdExt>(a: T, b: T) -> T {
93    simd_xor(simd_ext_shl(simd_ext_splat(1), b), a)
94}
95
96#[inline(always)]
97#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
98pub(super) const unsafe fn simd_ext_bitset<T: Copy + const SimdExt>(a: T, b: T) -> T {
99    simd_or(simd_ext_shl(simd_ext_splat(1), b), a)
100}
101
102#[inline(always)]
103#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
104pub(super) const unsafe fn simd_ext_fmsub<T: Copy>(a: T, b: T, c: T) -> T {
105    simd_fma(a, b, simd_neg(c))
106}
107
108#[inline(always)]
109#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
110pub(super) const unsafe fn simd_ext_fnmadd<T: Copy>(a: T, b: T, c: T) -> T {
111    simd_neg(simd_fma(a, b, c))
112}
113
114#[inline(always)]
115#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
116pub(super) const unsafe fn simd_ext_fnmsub<T: Copy>(a: T, b: T, c: T) -> T {
117    simd_neg(simd_ext_fmsub(a, b, c))
118}
119
120#[inline(always)]
121#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
122pub(super) const unsafe fn simd_ext_frecip_s<T: Copy>(a: T) -> T {
123    simd_div(simd_splat(1.0f32), a)
124}
125
126#[inline(always)]
127#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
128pub(super) const unsafe fn simd_ext_frecip_d<T: Copy>(a: T) -> T {
129    simd_div(simd_splat(1.0f64), a)
130}
131
132#[inline(always)]
133pub(super) unsafe fn simd_ext_frsqrt_s<T: Copy>(a: T) -> T {
134    simd_ext_frecip_s(simd_fsqrt(a))
135}
136
137#[inline(always)]
138pub(super) unsafe fn simd_ext_frsqrt_d<T: Copy>(a: T) -> T {
139    simd_ext_frecip_d(simd_fsqrt(a))
140}
141
142#[inline(always)]
143#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
144pub(super) const unsafe fn simd_ext_ld<const I: i32, T: Copy>(a: *const i8) -> T {
145    let a = a.offset(I as isize) as *const T;
146    core::ptr::read_unaligned(a)
147}
148
149#[inline(always)]
150#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
151pub(super) const unsafe fn simd_ext_ldi<const I: i32, T: Copy + const SimdExt>() -> T {
152    use crate::core_arch::simd::{i8x8, i16x4, i32x2};
153    use crate::mem::transmute;
154
155    #[inline(always)]
156    const fn sext(v: i32, bits: u32) -> i64 {
157        ((v as i64) << (64 - bits)) >> (64 - bits)
158    }
159
160    #[inline(always)]
161    const fn expand_u8(imm: i32) -> u64 {
162        let mut v = imm as u64;
163        v = (v | (v << 28)) & 0x0000000f0000000f;
164        v = (v | (v << 14)) & 0x0003000300030003;
165        v = (v | (v << 7)) & 0x0101010101010101;
166        v.wrapping_mul(0xff)
167    }
168
169    #[inline(always)]
170    const fn fp32_imm(imm: i32) -> i32 {
171        ((imm & 0x80) << 24)
172            | ((!imm & 0x40) << 24)
173            | (((imm & 0x40) >> 6).wrapping_mul(0x1f) << 25)
174            | ((imm & 0x3f) << 19)
175    }
176
177    #[inline(always)]
178    const fn fp64_imm(imm: i32) -> i64 {
179        ((((imm & 0x80) << 24)
180            | ((!imm & 0x40) << 24)
181            | (((imm & 0x40) >> 6).wrapping_mul(0xff) << 22)
182            | ((imm & 0x3f) << 16)) as i64)
183            << 32
184    }
185
186    let imm8 = I & 0xff;
187    let imm10 = I & 0x3ff;
188
189    let r = if (I & 0x1000) == 0 {
190        match (I >> 10) & 3 {
191            0 => transmute(i8x8::splat(imm8 as i8)),
192            1 => transmute(i16x4::splat(sext(imm10, 10) as i16)),
193            2 => transmute(i32x2::splat(sext(imm10, 10) as i32)),
194            3 => sext(imm10, 10),
195            _ => unreachable!(),
196        }
197    } else {
198        match (I >> 8) & 0xf {
199            0..=3 => transmute(i32x2::splat(imm8 << (8 * ((I >> 8) & 3)))),
200            4..=5 => transmute(i16x4::splat((imm8 as i16) << (8 * ((I >> 8) & 1)))),
201            6 => transmute(i32x2::splat((imm8 << 8) | 0xff)),
202            7 => transmute(i32x2::splat((imm8 << 16) | 0xffff)),
203            8 => transmute(i8x8::splat(imm8 as i8)),
204            9 => expand_u8(imm8) as i64,
205            10 => transmute(i32x2::splat(fp32_imm(I))),
206            11 => transmute(i32x2::from_array([fp32_imm(I), 0])),
207            12 => fp64_imm(I),
208            _ => unreachable!(),
209        }
210    };
211
212    simd_ext_splat(r)
213}
214
215#[inline(always)]
216#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
217pub(super) const unsafe fn simd_ext_ldx<T: Copy>(a: *const i8, b: i64) -> T {
218    let a = a.offset(b as isize) as *const T;
219    core::ptr::read_unaligned(a)
220}
221
222#[inline(always)]
223#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
224pub(super) const unsafe fn simd_ext_madd<T: Copy>(a: T, b: T, c: T) -> T {
225    simd_add(a, simd_mul(b, c))
226}
227
228#[inline(always)]
229#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
230pub(super) const unsafe fn simd_ext_msub<T: Copy>(a: T, b: T, c: T) -> T {
231    simd_sub(a, simd_mul(b, c))
232}
233
234#[inline(always)]
235#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
236pub(super) const unsafe fn simd_ext_muh<T: Copy, W: Copy + const SimdExt>(a: T, b: T) -> T {
237    let a: W = simd_cast(a);
238    let b: W = simd_cast(b);
239    let p = simd_mul(a, b);
240    simd_cast(simd_shr(
241        p,
242        simd_ext_splat((size_of::<W::Elem>() * 8 / 2) as i64),
243    ))
244}
245
246#[inline(always)]
247#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
248pub(super) const unsafe fn simd_ext_nor<T: Copy + const SimdExt>(a: T, b: T) -> T {
249    simd_ext_not(simd_or(a, b))
250}
251
252#[inline(always)]
253#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
254pub(super) const unsafe fn simd_ext_not<T: Copy + const SimdExt>(a: T) -> T {
255    simd_xor(a, simd_ext_splat(!0))
256}
257
258#[inline(always)]
259#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
260pub(super) const unsafe fn simd_ext_orn<T: Copy + const SimdExt>(a: T, b: T) -> T {
261    simd_or(a, simd_ext_not(b))
262}
263
264#[inline(always)]
265#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
266pub(super) const unsafe fn simd_ext_rotr<T: Copy + const SimdExt>(a: T, b: T) -> T {
267    let m = (size_of::<T::Elem>() * 8 - 1) as i64;
268    let r = simd_and(b, simd_ext_splat(m));
269    let l = simd_and(simd_sub(simd_ext_splat(m + 1), r), simd_ext_splat(m));
270    simd_or(simd_shr(a, r), simd_shl(a, l))
271}
272
273#[inline(always)]
274#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
275pub(super) const unsafe fn simd_ext_shl<T: Copy + const SimdExt>(a: T, b: T) -> T {
276    let m = (size_of::<T::Elem>() * 8 - 1) as i64;
277    simd_shl(a, simd_and(b, simd_ext_splat(m)))
278}
279
280#[inline(always)]
281#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
282pub(super) const unsafe fn simd_ext_shr<T: Copy + const SimdExt>(a: T, b: T) -> T {
283    let m = (size_of::<T::Elem>() * 8 - 1) as i64;
284    simd_shr(a, simd_and(b, simd_ext_splat(m)))
285}
286
287#[inline(always)]
288#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
289pub(super) const unsafe fn simd_ext_splat<T: Copy + const SimdExt>(a: i64) -> T {
290    T::splat(a)
291}
292
293#[inline(always)]
294#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
295pub(super) const unsafe fn simd_ext_st<const I: i32, T: Copy>(a: T, b: *mut i8) {
296    let b = b.offset(I as isize) as *mut T;
297    core::ptr::write_unaligned(b, a);
298}
299
300#[inline(always)]
301#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")]
302pub(super) const unsafe fn simd_ext_stx<T: Copy>(a: T, b: *mut i8, c: i64) {
303    let b = b.offset(c as isize) as *mut T;
304    core::ptr::write_unaligned(b, a);
305}
306
307macro_rules! impl_vavg {
308    ($ft:literal, $name:ident, $oty:ty, $ity:ty, $wty:ty) => {
309        #[inline]
310        #[target_feature(enable = $ft)]
311        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
312        pub fn $name(a: $oty, b: $oty) -> $oty {
313            unsafe {
314                let a: $wty = simd_cast(transmute::<_, $ity>(a));
315                let b: $wty = simd_cast(transmute::<_, $ity>(b));
316                let r: $ity = simd_cast(simd_shr(simd_add(a, b), <$wty>::splat(1)));
317                transmute(r)
318            }
319        }
320    };
321}
322
323macro_rules! impl_vavgr {
324    ($ft:literal, $name:ident, $oty:ty, $ity:ty, $wty:ty) => {
325        #[inline]
326        #[target_feature(enable = $ft)]
327        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
328        pub fn $name(a: $oty, b: $oty) -> $oty {
329            unsafe {
330                let a: $wty = simd_cast(transmute::<_, $ity>(a));
331                let b: $wty = simd_cast(transmute::<_, $ity>(b));
332                let r: $ity = simd_cast(simd_shr(
333                    simd_add(simd_add(a, b), <$wty>::splat(1)),
334                    <$wty>::splat(1),
335                ));
336                transmute(r)
337            }
338        }
339    };
340}
341
342pub(super) use impl_vavg;
343pub(super) use impl_vavgr;
344
345macro_rules! impl_vv {
346    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ty) => {
347        #[inline]
348        #[target_feature(enable = $ft)]
349        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
350        pub fn $name(a: $oty) -> $oty {
351            unsafe {
352                let a: $ity = transmute(a);
353                let r: $ity = $op(a);
354                transmute(r)
355            }
356        }
357    };
358}
359
360pub(super) use impl_vv;
361
362macro_rules! impl_gv {
363    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty) => {
364        #[inline]
365        #[target_feature(enable = $ft)]
366        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
367        pub fn $name(a: $gty) -> $oty {
368            unsafe {
369                let r: $ity = $op(a.into());
370                transmute(r)
371            }
372        }
373    };
374}
375
376pub(super) use impl_gv;
377
378macro_rules! impl_ggv {
379    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $xty:ty, unsafe) => {
380        #[inline]
381        #[target_feature(enable = $ft)]
382        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
383        pub unsafe fn $name(a: $gty, b: $xty) -> $oty {
384            let r: $ity = $op(a, b);
385            transmute(r)
386        }
387    };
388}
389
390pub(super) use impl_ggv;
391
392macro_rules! impl_gsv {
393    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr, const, unsafe) => {
394        #[inline]
395        #[target_feature(enable = $ft)]
396        #[rustc_legacy_const_generics(1)]
397        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
398        pub unsafe fn $name<const IMM: i32>(a: $gty) -> $oty {
399            static_assert_simm_bits!(IMM, $ibs);
400            let r: $ity = $op::<IMM, _>(a);
401            transmute(r)
402        }
403    };
404}
405
406pub(super) use impl_gsv;
407
408macro_rules! impl_sv {
409    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr) => {
410        #[inline]
411        #[target_feature(enable = $ft)]
412        #[rustc_legacy_const_generics(0)]
413        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
414        pub fn $name<const IMM: i32>() -> $oty {
415            static_assert_simm_bits!(IMM, $ibs);
416            unsafe {
417                let r: $ity = $op(IMM.into());
418                transmute(r)
419            }
420        }
421    };
422    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr, const) => {
423        #[inline]
424        #[target_feature(enable = $ft)]
425        #[rustc_legacy_const_generics(0)]
426        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
427        pub fn $name<const IMM: i32>() -> $oty {
428            static_assert_simm_bits!(IMM, $ibs);
429            unsafe {
430                let r: $ity = $op::<IMM, _>();
431                transmute(r)
432            }
433        }
434    };
435}
436
437pub(super) use impl_sv;
438
439macro_rules! impl_vvv {
440    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ty) => {
441        #[inline]
442        #[target_feature(enable = $ft)]
443        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
444        pub fn $name(a: $oty, b: $oty) -> $oty {
445            unsafe {
446                let a: $ity = transmute(a);
447                let b: $ity = transmute(b);
448                let r: $ity = $op(a, b);
449                transmute(r)
450            }
451        }
452    };
453    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ty, $wty:ty) => {
454        #[inline]
455        #[target_feature(enable = $ft)]
456        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
457        pub fn $name(a: $oty, b: $oty) -> $oty {
458            unsafe {
459                let a: $ity = transmute(a);
460                let b: $ity = transmute(b);
461                let r: $ity = $op::<$ity, $wty>(a, b);
462                transmute(r)
463            }
464        }
465    };
466}
467
468pub(super) use impl_vvv;
469
470macro_rules! impl_vgg {
471    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $xty:ty, unsafe) => {
472        #[inline]
473        #[target_feature(enable = $ft)]
474        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
475        pub unsafe fn $name(a: $oty, b: $gty, c: $xty) {
476            $op(a, b, c);
477        }
478    };
479}
480
481pub(super) use impl_vgg;
482
483macro_rules! impl_vgs {
484    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr, const, unsafe) => {
485        #[inline]
486        #[target_feature(enable = $ft)]
487        #[rustc_legacy_const_generics(2)]
488        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
489        pub unsafe fn $name<const IMM: i32>(a: $oty, b: $gty) {
490            static_assert_simm_bits!(IMM, $ibs);
491            $op::<IMM, _>(a, b);
492        }
493    };
494}
495
496pub(super) use impl_vgs;
497
498macro_rules! impl_vuv {
499    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident) => {
500        #[inline]
501        #[target_feature(enable = $ft)]
502        #[rustc_legacy_const_generics(1)]
503        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
504        pub fn $name<const IMM: u32>(a: $oty) -> $oty {
505            static_assert_uimm_bits!(IMM, (size_of::<<$ity as SimdExt>::Elem>() * 8).ilog2());
506            unsafe {
507                let a: $ity = transmute(a);
508                let b: $ity = simd_ext_splat(IMM.into());
509                let r: $ity = $op(a, b);
510                transmute(r)
511            }
512        }
513    };
514    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr) => {
515        #[inline]
516        #[target_feature(enable = $ft)]
517        #[rustc_legacy_const_generics(1)]
518        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
519        pub fn $name<const IMM: u32>(a: $oty) -> $oty {
520            static_assert_uimm_bits!(IMM, $ibs);
521            unsafe {
522                let a: $ity = transmute(a);
523                let b: $ity = simd_ext_splat(IMM.into());
524                let r: $ity = $op(a, b);
525                transmute(r)
526            }
527        }
528    };
529    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr, const) => {
530        #[inline]
531        #[target_feature(enable = $ft)]
532        #[rustc_legacy_const_generics(1)]
533        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
534        pub fn $name<const IMM: u32>(a: $oty) -> $oty {
535            static_assert_uimm_bits!(IMM, $ibs);
536            unsafe {
537                let a: $ity = transmute(a);
538                let r: $ity = $op::<IMM, _>(a);
539                transmute(r)
540            }
541        }
542    };
543}
544
545pub(super) use impl_vuv;
546
547macro_rules! impl_vug {
548    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr) => {
549        #[inline]
550        #[target_feature(enable = $ft)]
551        #[rustc_legacy_const_generics(1)]
552        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
553        pub fn $name<const IMM: u32>(a: $oty) -> $gty {
554            static_assert_uimm_bits!(IMM, $ibs);
555            unsafe {
556                let a: $ity = transmute(a);
557                let r: <$ity as SimdExt>::Elem = $op(a, IMM);
558                r as $gty
559            }
560        }
561    };
562}
563
564pub(super) use impl_vug;
565
566macro_rules! impl_vsv {
567    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr) => {
568        #[inline]
569        #[target_feature(enable = $ft)]
570        #[rustc_legacy_const_generics(1)]
571        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
572        pub fn $name<const IMM: i32>(a: $oty) -> $oty {
573            static_assert_simm_bits!(IMM, $ibs);
574            unsafe {
575                let a: $ity = transmute(a);
576                let b: $ity = simd_ext_splat(IMM.into());
577                let r: $ity = $op(a, b);
578                transmute(r)
579            }
580        }
581    };
582}
583
584pub(super) use impl_vsv;
585
586macro_rules! impl_vvvv {
587    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ty) => {
588        #[inline]
589        #[target_feature(enable = $ft)]
590        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
591        pub fn $name(a: $oty, b: $oty, c: $oty) -> $oty {
592            unsafe {
593                let a: $ity = transmute(a);
594                let b: $ity = transmute(b);
595                let c: $ity = transmute(c);
596                let r: $ity = $op(a, b, c);
597                transmute(r)
598            }
599        }
600    };
601}
602
603pub(super) use impl_vvvv;
604
605macro_rules! impl_vvuv {
606    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr, const) => {
607        #[inline]
608        #[target_feature(enable = $ft)]
609        #[rustc_legacy_const_generics(2)]
610        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
611        pub fn $name<const IMM: u32>(a: $oty, b: $oty) -> $oty {
612            static_assert_uimm_bits!(IMM, $ibs);
613            unsafe {
614                let a: $ity = transmute(a);
615                let b: $ity = transmute(b);
616                let r: $ity = $op::<IMM, _>(a, b);
617                transmute(r)
618            }
619        }
620    };
621}
622
623pub(super) use impl_vvuv;
624
625macro_rules! impl_vugv {
626    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr) => {
627        #[inline]
628        #[target_feature(enable = $ft)]
629        #[rustc_legacy_const_generics(2)]
630        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
631        pub fn $name<const IMM: u32>(a: $oty, b: $gty) -> $oty {
632            static_assert_uimm_bits!(IMM, $ibs);
633            unsafe {
634                let a: $ity = transmute(a);
635                let r: $ity = $op(a, IMM, b as <$ity as SimdExt>::Elem);
636                transmute(r)
637            }
638        }
639    };
640}
641
642pub(super) use impl_vugv;