      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117

    //! PowerPC Vector Scalar eXtensions (VSX) intrinsics.
    //!
    //! The references are: [POWER ISA v2.07B (for POWER8 & POWER8 with NVIDIA
    //! NVlink)] and [POWER ISA v3.0B (for POWER9)].
    //!
    //! [POWER ISA v2.07B (for POWER8 & POWER8 with NVIDIA NVlink)]: https://ibm.box.com/s/jd5w15gz301s5b5dt375mshpq9c3lh4u
    //! [POWER ISA v3.0B (for POWER9)]: https://ibm.box.com/s/1hzcwkwf8rbju5h9iyf44wm94amnlcrv

    #![allow(non_camel_case_types)]

    use crate::core_arch::simd_llvm::*;

    #[cfg(test)]
    use stdarch_test::assert_instr;

    use crate::mem;

    types! {
        // pub struct vector_Float16 = f16x8;
        /// PowerPC-specific 128-bit wide vector of two packed `i64`
        pub struct vector_signed_long(i64, i64);
        /// PowerPC-specific 128-bit wide vector of two packed `u64`
        pub struct vector_unsigned_long(u64, u64);
        /// PowerPC-specific 128-bit wide vector mask of two elements
        pub struct vector_bool_long(i64, i64);
        /// PowerPC-specific 128-bit wide vector of two packed `f64`
        pub struct vector_double(f64, f64);
        // pub struct vector_signed_long_long = vector_signed_long;
        // pub struct vector_unsigned_long_long = vector_unsigned_long;
        // pub struct vector_bool_long_long = vector_bool_long;
        // pub struct vector_signed___int128 = i128x1;
        // pub struct vector_unsigned___int128 = i128x1;
    }

    mod sealed {
        use super::*;
        use crate::core_arch::simd::*;

        pub trait VectorPermDI {
            unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self;
        }

        // xxpermdi has an big-endian bias and extended mnemonics
        #[inline]
        #[target_feature(enable = "vsx")]
        #[cfg_attr(all(test, target_endian = "little"), assert_instr(xxmrgld, dm = 0x0))]
        #[cfg_attr(all(test, target_endian = "big"), assert_instr(xxspltd, dm = 0x0))]
        unsafe fn xxpermdi(a: i64x2, b: i64x2, dm: u8) -> i64x2 {
            match dm & 0b11 {
                0 => simd_shuffle2(a, b, [0b00, 0b10]),
                1 => simd_shuffle2(a, b, [0b01, 0b10]),
                2 => simd_shuffle2(a, b, [0b00, 0b11]),
                _ => simd_shuffle2(a, b, [0b01, 0b11]),
            }
        }

        macro_rules! vec_xxpermdi {
            {$impl: ident} => {
                impl VectorPermDI for $impl {
                    #[inline]
                    #[target_feature(enable = "vsx")]
                    unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self {
                        mem::transmute(xxpermdi(mem::transmute(self), mem::transmute(b), dm))
                    }
                }
            }
        }

        vec_xxpermdi! { vector_unsigned_long }
        vec_xxpermdi! { vector_signed_long }
        vec_xxpermdi! { vector_bool_long }
        vec_xxpermdi! { vector_double }
    }

    /// Vector permute.
    #[inline]
    #[target_feature(enable = "vsx")]
    #[rustc_args_required_const(2)]
    pub unsafe fn vec_xxpermdi<T>(a: T, b: T, dm: u8) -> T
    where
        T: sealed::VectorPermDI,
    {
        a.vec_xxpermdi(b, dm)
    }

    #[cfg(test)]
    mod tests {
        #[cfg(target_arch = "powerpc")]
        use crate::core_arch::arch::powerpc::*;

        #[cfg(target_arch = "powerpc64")]
        use crate::core_arch::arch::powerpc64::*;

        use super::mem;
        use crate::core_arch::simd::*;
        use stdarch_test::simd_test;

        macro_rules! test_vec_xxpermdi {
            {$name:ident, $shorttype:ident, $longtype:ident, [$($a:expr),+], [$($b:expr),+], [$($c:expr),+], [$($d:expr),+]} => {
                #[simd_test(enable = "vsx")]
                unsafe fn $name() {
                    let a: $longtype = mem::transmute($shorttype::new($($a),+, $($b),+));
                    let b = mem::transmute($shorttype::new($($c),+, $($d),+));

                    assert_eq!($shorttype::new($($a),+, $($c),+), mem::transmute(vec_xxpermdi(a, b, 0)));
                    assert_eq!($shorttype::new($($b),+, $($c),+), mem::transmute(vec_xxpermdi(a, b, 1)));
                    assert_eq!($shorttype::new($($a),+, $($d),+), mem::transmute(vec_xxpermdi(a, b, 2)));
                    assert_eq!($shorttype::new($($b),+, $($d),+), mem::transmute(vec_xxpermdi(a, b, 3)));
                }
            }
        }

        test_vec_xxpermdi! {test_vec_xxpermdi_u64x2, u64x2, vector_unsigned_long, [0], [1], [2], [3]}
        test_vec_xxpermdi! {test_vec_xxpermdi_i64x2, i64x2, vector_signed_long, [0], [-1], [2], [-3]}
        test_vec_xxpermdi! {test_vec_xxpermdi_m64x2, m64x2, vector_bool_long, [false], [true], [false], [true]}
        test_vec_xxpermdi! {test_vec_xxpermdi_f64x2, f64x2, vector_double, [0.0], [1.0], [2.0], [3.0]}
    }