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_vv {
308    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ty) => {
309        #[inline]
310        #[target_feature(enable = $ft)]
311        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
312        pub fn $name(a: $oty) -> $oty {
313            unsafe {
314                let a: $ity = transmute(a);
315                let r: $ity = $op(a);
316                transmute(r)
317            }
318        }
319    };
320}
321
322pub(super) use impl_vv;
323
324macro_rules! impl_gv {
325    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty) => {
326        #[inline]
327        #[target_feature(enable = $ft)]
328        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
329        pub fn $name(a: $gty) -> $oty {
330            unsafe {
331                let r: $ity = $op(a.into());
332                transmute(r)
333            }
334        }
335    };
336}
337
338pub(super) use impl_gv;
339
340macro_rules! impl_ggv {
341    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $xty:ty, unsafe) => {
342        #[inline]
343        #[target_feature(enable = $ft)]
344        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
345        pub unsafe fn $name(a: $gty, b: $xty) -> $oty {
346            let r: $ity = $op(a, b);
347            transmute(r)
348        }
349    };
350}
351
352pub(super) use impl_ggv;
353
354macro_rules! impl_gsv {
355    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr, const, unsafe) => {
356        #[inline]
357        #[target_feature(enable = $ft)]
358        #[rustc_legacy_const_generics(1)]
359        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
360        pub unsafe fn $name<const IMM: i32>(a: $gty) -> $oty {
361            static_assert_simm_bits!(IMM, $ibs);
362            let r: $ity = $op::<IMM, _>(a);
363            transmute(r)
364        }
365    };
366}
367
368pub(super) use impl_gsv;
369
370macro_rules! impl_sv {
371    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr) => {
372        #[inline]
373        #[target_feature(enable = $ft)]
374        #[rustc_legacy_const_generics(0)]
375        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
376        pub fn $name<const IMM: i32>() -> $oty {
377            static_assert_simm_bits!(IMM, $ibs);
378            unsafe {
379                let r: $ity = $op(IMM.into());
380                transmute(r)
381            }
382        }
383    };
384    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr, const) => {
385        #[inline]
386        #[target_feature(enable = $ft)]
387        #[rustc_legacy_const_generics(0)]
388        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
389        pub fn $name<const IMM: i32>() -> $oty {
390            static_assert_simm_bits!(IMM, $ibs);
391            unsafe {
392                let r: $ity = $op::<IMM, _>();
393                transmute(r)
394            }
395        }
396    };
397}
398
399pub(super) use impl_sv;
400
401macro_rules! impl_vvv {
402    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ty) => {
403        #[inline]
404        #[target_feature(enable = $ft)]
405        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
406        pub fn $name(a: $oty, b: $oty) -> $oty {
407            unsafe {
408                let a: $ity = transmute(a);
409                let b: $ity = transmute(b);
410                let r: $ity = $op(a, b);
411                transmute(r)
412            }
413        }
414    };
415    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ty, $wty:ty) => {
416        #[inline]
417        #[target_feature(enable = $ft)]
418        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
419        pub fn $name(a: $oty, b: $oty) -> $oty {
420            unsafe {
421                let a: $ity = transmute(a);
422                let b: $ity = transmute(b);
423                let r: $ity = $op::<$ity, $wty>(a, b);
424                transmute(r)
425            }
426        }
427    };
428}
429
430pub(super) use impl_vvv;
431
432macro_rules! impl_vgg {
433    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $xty:ty, unsafe) => {
434        #[inline]
435        #[target_feature(enable = $ft)]
436        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
437        pub unsafe fn $name(a: $oty, b: $gty, c: $xty) {
438            $op(a, b, c);
439        }
440    };
441}
442
443pub(super) use impl_vgg;
444
445macro_rules! impl_vgs {
446    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr, const, unsafe) => {
447        #[inline]
448        #[target_feature(enable = $ft)]
449        #[rustc_legacy_const_generics(2)]
450        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
451        pub unsafe fn $name<const IMM: i32>(a: $oty, b: $gty) {
452            static_assert_simm_bits!(IMM, $ibs);
453            $op::<IMM, _>(a, b);
454        }
455    };
456}
457
458pub(super) use impl_vgs;
459
460macro_rules! impl_vuv {
461    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident) => {
462        #[inline]
463        #[target_feature(enable = $ft)]
464        #[rustc_legacy_const_generics(1)]
465        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
466        pub fn $name<const IMM: u32>(a: $oty) -> $oty {
467            static_assert_uimm_bits!(IMM, (size_of::<<$ity as SimdExt>::Elem>() * 8).ilog2());
468            unsafe {
469                let a: $ity = transmute(a);
470                let b: $ity = simd_ext_splat(IMM.into());
471                let r: $ity = $op(a, b);
472                transmute(r)
473            }
474        }
475    };
476    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr) => {
477        #[inline]
478        #[target_feature(enable = $ft)]
479        #[rustc_legacy_const_generics(1)]
480        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
481        pub fn $name<const IMM: u32>(a: $oty) -> $oty {
482            static_assert_uimm_bits!(IMM, $ibs);
483            unsafe {
484                let a: $ity = transmute(a);
485                let b: $ity = simd_ext_splat(IMM.into());
486                let r: $ity = $op(a, b);
487                transmute(r)
488            }
489        }
490    };
491    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr, const) => {
492        #[inline]
493        #[target_feature(enable = $ft)]
494        #[rustc_legacy_const_generics(1)]
495        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
496        pub fn $name<const IMM: u32>(a: $oty) -> $oty {
497            static_assert_uimm_bits!(IMM, $ibs);
498            unsafe {
499                let a: $ity = transmute(a);
500                let r: $ity = $op::<IMM, _>(a);
501                transmute(r)
502            }
503        }
504    };
505}
506
507pub(super) use impl_vuv;
508
509macro_rules! impl_vug {
510    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr) => {
511        #[inline]
512        #[target_feature(enable = $ft)]
513        #[rustc_legacy_const_generics(1)]
514        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
515        pub fn $name<const IMM: u32>(a: $oty) -> $gty {
516            static_assert_uimm_bits!(IMM, $ibs);
517            unsafe {
518                let a: $ity = transmute(a);
519                let r: <$ity as SimdExt>::Elem = $op(a, IMM);
520                r as $gty
521            }
522        }
523    };
524}
525
526pub(super) use impl_vug;
527
528macro_rules! impl_vsv {
529    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr) => {
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: i32>(a: $oty) -> $oty {
535            static_assert_simm_bits!(IMM, $ibs);
536            unsafe {
537                let a: $ity = transmute(a);
538                let b: $ity = simd_ext_splat(IMM.into());
539                let r: $ity = $op(a, b);
540                transmute(r)
541            }
542        }
543    };
544}
545
546pub(super) use impl_vsv;
547
548macro_rules! impl_vvvv {
549    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ty) => {
550        #[inline]
551        #[target_feature(enable = $ft)]
552        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
553        pub fn $name(a: $oty, b: $oty, c: $oty) -> $oty {
554            unsafe {
555                let a: $ity = transmute(a);
556                let b: $ity = transmute(b);
557                let c: $ity = transmute(c);
558                let r: $ity = $op(a, b, c);
559                transmute(r)
560            }
561        }
562    };
563}
564
565pub(super) use impl_vvvv;
566
567macro_rules! impl_vvuv {
568    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $ibs:expr, const) => {
569        #[inline]
570        #[target_feature(enable = $ft)]
571        #[rustc_legacy_const_generics(2)]
572        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
573        pub fn $name<const IMM: u32>(a: $oty, b: $oty) -> $oty {
574            static_assert_uimm_bits!(IMM, $ibs);
575            unsafe {
576                let a: $ity = transmute(a);
577                let b: $ity = transmute(b);
578                let r: $ity = $op::<IMM, _>(a, b);
579                transmute(r)
580            }
581        }
582    };
583}
584
585pub(super) use impl_vvuv;
586
587macro_rules! impl_vugv {
588    ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr) => {
589        #[inline]
590        #[target_feature(enable = $ft)]
591        #[rustc_legacy_const_generics(2)]
592        #[unstable(feature = "stdarch_loongarch", issue = "117427")]
593        pub fn $name<const IMM: u32>(a: $oty, b: $gty) -> $oty {
594            static_assert_uimm_bits!(IMM, $ibs);
595            unsafe {
596                let a: $ity = transmute(a);
597                let r: $ity = $op(a, IMM, b as <$ity as SimdExt>::Elem);
598                transmute(r)
599            }
600        }
601    };
602}
603
604pub(super) use impl_vugv;