1 /**
2 * Lightweight wrappers around AltiVec for 32-bit operations
3 * 
4 * Copyright:
5 * (C) 2009 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.simd.simd_altivec;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_SIMD_ALTIVEC):
15 
16 import botan.utils.loadstor;
17 import botan.utils.cpuid;
18 import botan.utils.simd.altivec;
19 
20 struct SIMDAltivec
21 {
22 public:
23     static bool enabled() { return CPUID.hasAltivec(); }
24 
25     this(in uint[4] B)
26     {
27         m_reg = [B[0], B[1], B[2], B[3]];
28     }
29 
30     this(uint B0, uint B1, uint B2, uint B3)
31     {
32         m_reg = [B0, B1, B2, B3];
33     }
34 
35     this(uint B)
36     {
37         m_reg = [B, B, B, B];
38     }
39 
40     static SIMDAltivec loadLittleEndian(in void* input)
41     {
42         const uint* in_32 = cast(const uint*)(input);
43 
44         vector_uint R0 = vec_ld(0, in_32);
45         vector_uint R1 = vec_ld(12, in_32);
46 
47         vector_byte perm = vec_lvsl(0, in_32);
48 
49         perm = vec_xor(perm, vec_splat_u8(3));
50 
51         R0 = vec_perm(R0, R1, perm);
52 
53         return SIMDAltivec(R0);
54     }
55 
56     static SIMDAltivec loadBigEndian(in void* input)
57     {
58         const uint* in_32 = cast(const uint*)(input);
59 
60         vector_uint R0 = vec_ld(0, in_32);
61         vector_uint R1 = vec_ld(12, in_32);
62 
63         vector_byte perm = vec_lvsl(0, in_32);
64 
65         R0 = vec_perm(R0, R1, perm);
66 
67         return SIMDAltivec(R0);
68     }
69 
70     void storeLittleEndian(ubyte* output)
71     {
72         vector_byte perm = vec_lvsl(0, null);
73 
74         perm = vec_xor(perm, vec_splat_u8(3));
75 
76         union {
77             vector_uint V;
78             uint[4] R;
79         } vec;
80 
81         vec.V = vec_perm(m_reg, m_reg, perm);
82 
83         .storeBigEndian(output, vec.R[0], vec.R[1], vec.R[2], vec.R[3]);
84     }
85 
86     void storeBigEndian(ubyte* output)
87     {
88         union {
89             vector_uint V;
90             uint[4] R;
91         } vec;
92 
93         vec.V = m_reg;
94 
95         .storeBigEndian(output, vec.R[0], vec.R[1], vec.R[2], vec.R[3]);
96     }
97 
98     void rotateLeft(int rot)()
99     {
100         vector_uint rot_vec = vector_uint([rot, rot, rot, rot]);
101 
102         m_reg = vec_rl(m_reg, rot_vec);
103     }
104 
105     void rotateRight(int rot)()
106     {
107         this.rotateLeft!(32 - rot)();
108     }
109 
110     void opOpAssign(string op)(in SIMDAltivec other)
111         if (op == "+")
112     {
113         m_reg = vec_add(m_reg, other.m_reg);
114     }
115 
116     SIMDAltivec opBinary(string op)(in SIMDAltivec other)
117         if (op == "+")
118     {
119         return SIMDAltivec(vec_add(m_reg, other.m_reg));
120     }
121 
122     void opOpAssign(string op)(in SIMDAltivec other)
123         if (op == "-")
124     {
125         m_reg = vec_sub(m_reg, other.m_reg);
126     }
127 
128     SIMDAltivec opBinary(string op)(in SIMDAltivec other)
129         if (op == "-")
130     {
131         return SIMDAltivec(vec_sub(m_reg, other.m_reg));
132     }
133 
134     void opOpAssign(string op)(in SIMDAltivec other)
135         if (op == "^")
136     {
137         m_reg = vec_xor(m_reg, other.m_reg);
138     }
139 
140     SIMDAltivec opBinary(string op)(in SIMDAltivec other)
141         if (op == "^")
142     {
143         return SIMDAltivec(vec_xor(m_reg, other.m_reg));
144     }
145 
146     void opOpAssign(string op)(in SIMDAltivec other)
147         if (op == "|")
148     {
149         m_reg = vec_or(m_reg, other.m_reg);
150     }
151 
152     SIMDAltivec opBinary(string op)(in SIMDAltivec other)
153         if (op == "&")
154     {
155         return SIMDAltivec(vec_and(m_reg, other.m_reg));
156     }
157 
158     void opOpAssign(string op)(in SIMDAltivec other)
159         if (op == "&")
160     {
161         m_reg = vec_and(m_reg, other.m_reg);
162     }
163 
164     SIMDAltivec lshift(int shift_)()
165     {
166         uint shift = cast(uint) shift_;
167         vector_uint shift_vec = vector_uint([shift, shift, shift, shift]);
168 
169         return SIMDAltivec(vec_sl(m_reg, shift_vec));
170     }
171 
172     SIMDAltivec rshift(int shift_)()
173     {
174         uint shift = cast(uint) shift_;
175         vector_uint shift_vec = vector_uint([shift, shift, shift, shift]);
176 
177         return SIMDAltivec(vec_sr(m_reg, shift_vec));
178     }
179 
180     SIMDAltivec opUnary(string op)()
181         if (op == "~")
182     {
183         return SIMDAltivec(vec_nor(m_reg, m_reg));
184     }
185 
186     SIMDAltivec andc(in SIMDAltivec other)
187     {
188         // AltiVec does arg1 & ~arg2 rather than SSE's ~arg1 & arg2
189         return SIMDAltivec(vec_andc(other.m_reg, m_reg));
190     }
191 
192     SIMDAltivec bswap()
193     {
194         vector_byte perm = vec_lvsl(0, null);
195 
196         perm = vec_xor(perm, vec_splat_u8(3));
197 
198         return SIMDAltivec(vec_perm(m_reg, m_reg, perm));
199     }
200 
201     static void transpose(ref SIMDAltivec B0, ref SIMDAltivec B1,
202                           ref SIMDAltivec B2, ref SIMDAltivec B3)
203     {
204         vector_uint T0 = vec_mergeh(B0.m_reg, B2.m_reg);
205         vector_uint T1 = vec_mergel(B0.m_reg, B2.m_reg);
206         vector_uint T2 = vec_mergeh(B1.m_reg, B3.m_reg);
207         vector_uint T3 = vec_mergel(B1.m_reg, B3.m_reg);
208 
209         B0.m_reg = vec_mergeh(T0, T2);
210         B1.m_reg = vec_mergel(T0, T2);
211         B2.m_reg = vec_mergeh(T1, T3);
212         B3.m_reg = vec_mergel(T1, T3);
213     }
214 
215 private:
216     this(vector_uint input) { m_reg = input; }
217 
218     vector_uint m_reg;
219 }