core/stdarch/crates/core_arch/src/powerpc/
vsx.rs

1//! PowerPC Vector Scalar eXtensions (VSX) intrinsics.
2//!
3//! The references are: [POWER ISA v2.07B (for POWER8 & POWER8 with NVIDIA
4//! NVlink)] and [POWER ISA v3.0B (for POWER9)].
5//!
6//! [POWER ISA v2.07B (for POWER8 & POWER8 with NVIDIA NVlink)]: https://ibm.box.com/s/jd5w15gz301s5b5dt375mshpq9c3lh4u
7//! [POWER ISA v3.0B (for POWER9)]: https://ibm.box.com/s/1hzcwkwf8rbju5h9iyf44wm94amnlcrv
8
9#![allow(non_camel_case_types)]
10
11use crate::core_arch::powerpc::*;
12
13#[cfg(test)]
14use stdarch_test::assert_instr;
15
16use crate::mem::transmute;
17
18types! {
19    #![unstable(feature = "stdarch_powerpc", issue = "111145")]
20
21    // pub struct vector_Float16 = f16x8;
22    /// PowerPC-specific 128-bit wide vector of two packed `i64`
23    pub struct vector_signed_long(2 x i64);
24    /// PowerPC-specific 128-bit wide vector of two packed `u64`
25    pub struct vector_unsigned_long(2 x u64);
26    /// PowerPC-specific 128-bit wide vector mask of two `i64`
27    pub struct vector_bool_long(2 x i64);
28    /// PowerPC-specific 128-bit wide vector of two packed `f64`
29    pub struct vector_double(2 x f64);
30    // pub struct vector_signed_long_long = vector_signed_long;
31    // pub struct vector_unsigned_long_long = vector_unsigned_long;
32    // pub struct vector_bool_long_long = vector_bool_long;
33    // pub struct vector_signed___int128 = i128x1;
34    // pub struct vector_unsigned___int128 = i128x1;
35}
36
37#[allow(improper_ctypes)]
38extern "C" {
39    #[link_name = "llvm.ppc.altivec.vperm"]
40    fn vperm(
41        a: vector_signed_int,
42        b: vector_signed_int,
43        c: vector_unsigned_char,
44    ) -> vector_signed_int;
45}
46
47mod sealed {
48    use super::*;
49    use crate::core_arch::simd::*;
50
51    #[unstable(feature = "stdarch_powerpc", issue = "111145")]
52    pub trait VectorPermDI {
53        #[unstable(feature = "stdarch_powerpc", issue = "111145")]
54        unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self;
55    }
56
57    // xxpermdi has an big-endian bias and extended mnemonics
58    #[inline]
59    #[target_feature(enable = "vsx")]
60    #[cfg_attr(all(test, target_endian = "little"), assert_instr(xxmrgld, dm = 0x0))]
61    #[cfg_attr(all(test, target_endian = "big"), assert_instr(xxspltd, dm = 0x0))]
62    unsafe fn xxpermdi(a: vector_signed_long, b: vector_signed_long, dm: u8) -> vector_signed_long {
63        let a: i64x2 = transmute(a);
64        let b: i64x2 = transmute(b);
65        let r: i64x2 = match dm & 0b11 {
66            0 => simd_shuffle!(a, b, [0b00, 0b10]),
67            1 => simd_shuffle!(a, b, [0b01, 0b10]),
68            2 => simd_shuffle!(a, b, [0b00, 0b11]),
69            _ => simd_shuffle!(a, b, [0b01, 0b11]),
70        };
71        transmute(r)
72    }
73
74    macro_rules! vec_xxpermdi {
75        {$impl: ident} => {
76            #[unstable(feature = "stdarch_powerpc", issue = "111145")]
77            impl VectorPermDI for $impl {
78                #[inline]
79                #[target_feature(enable = "vsx")]
80                unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self {
81                    transmute(xxpermdi(transmute(self), transmute(b), dm))
82                }
83            }
84        }
85    }
86
87    vec_xxpermdi! { vector_unsigned_long }
88    vec_xxpermdi! { vector_signed_long }
89    vec_xxpermdi! { vector_bool_long }
90    vec_xxpermdi! { vector_double }
91
92    #[unstable(feature = "stdarch_powerpc", issue = "111145")]
93    pub trait VectorMergeEo {
94        #[unstable(feature = "stdarch_powerpc", issue = "111145")]
95        unsafe fn vec_mergee(self, b: Self) -> Self;
96        #[unstable(feature = "stdarch_powerpc", issue = "111145")]
97        unsafe fn vec_mergeo(self, b: Self) -> Self;
98    }
99
100    #[inline]
101    #[target_feature(enable = "altivec")]
102    #[cfg_attr(
103        all(test, target_endian = "little", target_feature = "power8-vector"),
104        assert_instr(vmrgow)
105    )]
106    #[cfg_attr(
107        all(test, target_endian = "big", target_feature = "power8-vector"),
108        assert_instr(vmrgew)
109    )]
110    unsafe fn mergee(a: vector_signed_int, b: vector_signed_int) -> vector_signed_int {
111        let p = transmute(u8x16::new(
112            0x00, 0x01, 0x02, 0x03, 0x10, 0x11, 0x12, 0x13, 0x08, 0x09, 0x0A, 0x0B, 0x18, 0x19,
113            0x1A, 0x1B,
114        ));
115        vec_perm(a, b, p)
116    }
117
118    #[inline]
119    #[target_feature(enable = "altivec")]
120    #[cfg_attr(
121        all(test, target_endian = "little", target_feature = "power8-vector"),
122        assert_instr(vmrgew)
123    )]
124    #[cfg_attr(
125        all(test, target_endian = "big", target_feature = "power8-vector"),
126        assert_instr(vmrgow)
127    )]
128    unsafe fn mergeo(a: vector_signed_int, b: vector_signed_int) -> vector_signed_int {
129        let p = transmute(u8x16::new(
130            0x04, 0x05, 0x06, 0x07, 0x14, 0x15, 0x16, 0x17, 0x0C, 0x0D, 0x0E, 0x0F, 0x1C, 0x1D,
131            0x1E, 0x1F,
132        ));
133        vec_perm(a, b, p)
134    }
135
136    macro_rules! vec_mergeeo {
137        { $impl: ident, $even: ident, $odd: ident } => {
138            #[unstable(feature = "stdarch_powerpc", issue = "111145")]
139            impl VectorMergeEo for $impl {
140                #[inline]
141                #[target_feature(enable = "altivec")]
142                unsafe fn vec_mergee(self, b: Self) -> Self {
143                    transmute(mergee(transmute(self), transmute(b)))
144                }
145                #[inline]
146                #[target_feature(enable = "altivec")]
147                unsafe fn vec_mergeo(self, b: Self) -> Self {
148                    transmute(mergeo(transmute(self), transmute(b)))
149                }
150            }
151        }
152    }
153
154    vec_mergeeo! { vector_signed_int, mergee, mergeo }
155    vec_mergeeo! { vector_unsigned_int, mergee, mergeo }
156    vec_mergeeo! { vector_bool_int, mergee, mergeo }
157    vec_mergeeo! { vector_float, mergee, mergeo }
158}
159
160/// Vector permute.
161#[inline]
162#[target_feature(enable = "vsx")]
163//#[rustc_legacy_const_generics(2)]
164#[unstable(feature = "stdarch_powerpc", issue = "111145")]
165pub unsafe fn vec_xxpermdi<T, const DM: i32>(a: T, b: T) -> T
166where
167    T: sealed::VectorPermDI,
168{
169    static_assert_uimm_bits!(DM, 2);
170    a.vec_xxpermdi(b, DM as u8)
171}
172
173/// Vector Merge Even
174///
175/// ## Purpose
176/// Merges the even-numbered values from two vectors.
177///
178/// ## Result value
179/// The even-numbered elements of a are stored into the even-numbered elements of r.
180/// The even-numbered elements of b are stored into the odd-numbered elements of r.
181#[inline]
182#[target_feature(enable = "altivec")]
183#[unstable(feature = "stdarch_powerpc", issue = "111145")]
184pub unsafe fn vec_mergee<T>(a: T, b: T) -> T
185where
186    T: sealed::VectorMergeEo,
187{
188    a.vec_mergee(b)
189}
190
191/// Vector Merge Odd
192///
193/// ## Purpose
194/// Merges the odd-numbered values from two vectors.
195///
196/// ## Result value
197/// The odd-numbered elements of a are stored into the even-numbered elements of r.
198/// The odd-numbered elements of b are stored into the odd-numbered elements of r.
199#[inline]
200#[target_feature(enable = "altivec")]
201#[unstable(feature = "stdarch_powerpc", issue = "111145")]
202pub unsafe fn vec_mergeo<T>(a: T, b: T) -> T
203where
204    T: sealed::VectorMergeEo,
205{
206    a.vec_mergeo(b)
207}
208
209#[cfg(test)]
210mod tests {
211    #[cfg(target_arch = "powerpc")]
212    use crate::core_arch::arch::powerpc::*;
213
214    #[cfg(target_arch = "powerpc64")]
215    use crate::core_arch::arch::powerpc64::*;
216
217    use crate::core_arch::simd::*;
218    use crate::mem::transmute;
219    use stdarch_test::simd_test;
220
221    macro_rules! test_vec_xxpermdi {
222        {$name:ident, $shorttype:ident, $longtype:ident, [$($a:expr),+], [$($b:expr),+], [$($c:expr),+], [$($d:expr),+]} => {
223            #[simd_test(enable = "vsx")]
224            unsafe fn $name() {
225                let a: $longtype = transmute($shorttype::new($($a),+, $($b),+));
226                let b = transmute($shorttype::new($($c),+, $($d),+));
227
228                assert_eq!($shorttype::new($($a),+, $($c),+), transmute(vec_xxpermdi::<_, 0>(a, b)));
229                assert_eq!($shorttype::new($($b),+, $($c),+), transmute(vec_xxpermdi::<_, 1>(a, b)));
230                assert_eq!($shorttype::new($($a),+, $($d),+), transmute(vec_xxpermdi::<_, 2>(a, b)));
231                assert_eq!($shorttype::new($($b),+, $($d),+), transmute(vec_xxpermdi::<_, 3>(a, b)));
232            }
233        }
234    }
235
236    test_vec_xxpermdi! {test_vec_xxpermdi_u64x2, u64x2, vector_unsigned_long, [0], [1], [2], [3]}
237    test_vec_xxpermdi! {test_vec_xxpermdi_i64x2, i64x2, vector_signed_long, [0], [-1], [2], [-3]}
238    test_vec_xxpermdi! {test_vec_xxpermdi_m64x2, m64x2, vector_bool_long, [false], [true], [false], [true]}
239    test_vec_xxpermdi! {test_vec_xxpermdi_f64x2, f64x2, vector_double, [0.0], [1.0], [2.0], [3.0]}
240}