Skip to main content

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