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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! 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::powerpc::macros::*;
use crate::core_arch::powerpc::*;

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

use crate::mem::transmute;

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.ppc.vsx.lxvl"]
    fn lxvl(a: *const u8, l: usize) -> vector_signed_int;

    #[link_name = "llvm.ppc.vsx.stxvl"]
    fn stxvl(v: vector_signed_int, a: *mut u8, l: usize);
}

mod sealed {
    use super::*;

    #[inline]
    #[target_feature(enable = "power9-vector")]
    #[cfg_attr(test, assert_instr(lxvl))]
    unsafe fn vec_lxvl(p: *const u8, l: usize) -> vector_signed_int {
        lxvl(p, l << 56)
    }

    #[unstable(feature = "stdarch_powerpc", issue = "111145")]
    pub trait VectorXloads {
        type Result;
        unsafe fn vec_xl_len(self, l: usize) -> Self::Result;
    }

    macro_rules! impl_vsx_loads {
        ($ty:ident) => {
            #[unstable(feature = "stdarch_powerpc", issue = "111145")]
            impl VectorXloads for *const $ty {
                type Result = t_t_l!($ty);
                #[inline]
                #[target_feature(enable = "power9-vector")]
                unsafe fn vec_xl_len(self, l: usize) -> Self::Result {
                    transmute(vec_lxvl(self as *const u8, l))
                }
            }
        };
    }

    impl_vsx_loads! { i8 }
    impl_vsx_loads! { u8 }
    impl_vsx_loads! { i16 }
    impl_vsx_loads! { u16 }
    impl_vsx_loads! { i32 }
    impl_vsx_loads! { u32 }
    impl_vsx_loads! { f32 }

    #[inline]
    #[target_feature(enable = "power9-vector")]
    #[cfg_attr(test, assert_instr(stxvl))]
    unsafe fn vec_stxvl(v: vector_signed_int, a: *mut u8, l: usize) {
        stxvl(v, a, l << 56);
    }

    #[unstable(feature = "stdarch_powerpc", issue = "111145")]
    pub trait VectorXstores {
        type Out;
        unsafe fn vec_xst_len(self, p: Self::Out, l: usize);
    }

    macro_rules! impl_stores {
        ($ty:ident) => {
            #[unstable(feature = "stdarch_powerpc", issue = "111145")]
            impl VectorXstores for t_t_l!($ty) {
                type Out = *mut $ty;
                #[inline]
                #[target_feature(enable = "power9-vector")]
                unsafe fn vec_xst_len(self, a: Self::Out, l: usize) {
                    stxvl(transmute(self), a as *mut u8, l)
                }
            }
        };
    }

    impl_stores! { i8 }
    impl_stores! { u8 }
    impl_stores! { i16 }
    impl_stores! { u16 }
    impl_stores! { i32 }
    impl_stores! { u32 }
    impl_stores! { f32 }
}

/// Vector Load with Length
///
/// ## Purpose
/// Loads a vector of a specified byte length.
///
/// ## Result value
/// Loads the number of bytes specified by b from the address specified in a.
/// Initializes elements in order from the byte stream (as defined by the endianness of the
/// target). Any bytes of elements that cannot be initialized from the number of loaded bytes have
/// a zero value.
///
/// Between 0 and 16 bytes, inclusive, will be loaded. The length is specified by the
/// least-significant byte of b, as min (b mod 256, 16). The behavior is undefined if the length
/// argument is outside of the range 0–255, or if it is not a multiple of the vector element size.
///
/// ## Notes
/// vec_xl_len should not be used to load from cache-inhibited memory.
#[inline]
#[target_feature(enable = "power9-vector")]
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
pub unsafe fn vec_xl_len<T>(p: T, len: usize) -> <T as sealed::VectorXloads>::Result
where
    T: sealed::VectorXloads,
{
    p.vec_xl_len(len)
}

/// Vector Store with Length
///
/// ## Purpose
///
/// Stores a vector of a specified byte length.
///
/// ## Operation
///
/// Stores the number of bytes specified by c of the vector a to the address specified
/// in b. The bytes are obtained starting from the lowest-numbered byte of the lowest-numbered
/// element (as defined by the endianness of the target). All bytes of an element are accessed
/// before proceeding to the next higher element.
///
/// Between 0 and 16 bytes, inclusive, will be stored. The length is specified by the
/// least-significant byte of c, as min (c mod 256, 16). The behavior is undefined if the length
/// argument is outside of the range 0–255, or if it is not a multiple of the vector element size.
///
/// ## Notes
/// vec_xst_len should not be used to store to cache-inhibited memory.
#[inline]
#[target_feature(enable = "power9-vector")]
#[unstable(feature = "stdarch_powerpc", issue = "111145")]
pub unsafe fn vec_xst_len<T>(v: T, a: <T as sealed::VectorXstores>::Out, l: usize)
where
    T: sealed::VectorXstores,
{
    v.vec_xst_len(a, l)
}