1 /**
2 * immintrin.h style functions
3 * 
4 * Copyright:
5 * (C) 2014-2015 Etienne Cimon
6 *
7 * License:
8 * Released under the MIT license
9 */
10 module botan.utils.simd.immintrin;
11 
12 
13 import botan.constants;
14 
15 static if (BOTAN_HAS_THREEFISH_512_AVX2):
16 
17 import core.simd;
18 
19 alias __m256i = byte32;
20 
21 pure:
22 nothrow:
23 @trusted:
24 
25 int _MM_SHUFFLE(int a, int b, int c, int d)
26 {
27     return (z<<6) | (y<<4) | (x<<2) | w;
28 }
29 
30 version(GDC) {
31     // GDC <--> immintrin => gcc/gcc/config/i386/immintrin.h
32     static import gcc.attribute;
33     import gcc.builtins;
34     enum inline = gcc.attribute.attribute("forceinline");
35     enum avx2 = gcc.attribute.attribute("target", "avx2");
36 
37     @inline @avx2
38     __m256i _mm256_unpacklo_epi64(__m256i a, __m256i b) {
39         return cast(__m256i) __builtin_ia32_punpcklqdq256(cast(long4) a, cast(long4) b);
40     }
41 
42 
43     @inline @avx2
44     __m256i _mm256_unpackhi_epi64(__m256i a, __m256i b) {
45         return cast(__m256i) __builtin_ia32_punpckhqdq256(cast(long4) a, cast(long4) b);
46     }
47 
48     @inline @avx2
49     __m256i _mm256_set_epi64x(long a, long b, long c, long d) {
50         return cast(__m256i) long4([a, b, c, d]);
51     }
52     
53     @inline @avx2
54     void _mm256_storeu_si256(__m256i* ptr, __m256i a) {
55         __builtin_ia32_storedqu256(ptr, a);
56         return;
57     }
58 
59     @inline @avx2
60     __m256i _mm256_loadu_si256(__m256i* ptr) {
61         return cast(__m256i) __builtin_ia32_loaddqu256(ptr);
62     }
63 
64 
65     @inline @avx2
66     __m256i _mm256_permute4x64_epi64(__m256 X, in int M) {
67         return cast(__m256i) __builtin_ia32_permdi256(cast(long4) X, M);
68     }
69 
70     @inline @avx2
71     __m256i _mm256_add_epi64(__m256 a, __m256 b) {
72         return cast(__m256i) __builtin_ia32_paddq256(cast(long4) a, cast(long4) b);
73     }
74     
75     @inline @avx2
76     __m256i _mm256_sub_epi64(__m256 a, __m256 b) {
77         return cast(__m256i) __builtin_ia32_psubq256(cast(long4) a, cast(long4) b);
78     }
79 
80     @inline @avx2
81     __m256i _mm256_xor_si256(__m256 a, __m256 b) {
82         return cast(__m256i) __builtin_ia32_pxor256(cast(long4) a, cast(long4) b);
83     }
84 
85     @inline @avx2
86     __m256i _mm256_or_si256(__m256 a, __m256 b) {
87         return cast(__m256i) __builtin_ia32_por256(cast(long4) a, cast(long4) b);
88     }
89 
90     @inline @avx2
91     __m256i _mm256_srlv_epi64(__m256 a, __m256 b) {
92         return cast(__m256i) __builtin_ia32_psrlv4di(cast(long4) a, cast(long4) b);
93     }
94 
95     @inline @avx2
96     __m256i _mm256_sllv_epi64(__m256 a, __m256 b) {
97         return cast(__m256i) __builtin_ia32_psllv4di(cast(long4) a, cast(long4) b);
98     }
99 
100 
101 }
102 
103 version(none) {
104     // LDC <--> immintrin ==> clang/test/CodeGen/avx2-builtins.c, rdrand-builtins.c
105 
106     pragma(LDC_inline_ir)
107         R inlineIR(string s, R, P...)(P);
108 
109     pragma(LDC_intrinsic, "llvm.x86.rdrand.32")
110         int _rdrand32_step(uint*);
111 
112     __m256i _mm256_set_epi64x(long a, long b, long c, long d) {
113         return cast(__m256i) long4([a, b, c, d]);
114     }
115 
116     __m256i _mm256_unpacklo_epi64(__m256i a, __m256i b) {
117         pragma(LDC_allow_inline);
118         return inlineIR!(`
119             %tmp = shufflevector <4 x i64> %0, <4 x i64> %1, <4 x i32> <i32 0, i32 4, i32 2, i32 6>
120             ret <4 x i64> %tmp`, 
121               __m256i)(a, b);
122     }
123 
124     __m256i _mm256_unpackhi_epi64(__m256i a, __m256i b) {
125         pragma(LDC_allow_inline);
126         return inlineIR!(`
127             %tmp = shufflevector <4 x i64> %0, <4 x i64> %1, <4 x i32> <i32 1, i32 5, i32 3, i32 7>
128             ret <4 x i64> %tmp`,
129                 __m256i)(a, b);
130     }
131     
132     __m256i _mm256_loadu_si256(__m256i* a) {
133         pragma(LDC_allow_inline);
134         return inlineIR!(`
135             %tmp = load <4 x i64>* %0, align 1
136             ret <4 x i64> %tmp`,
137                          __m256i)(a);
138         
139     }
140     
141     void _mm256_storeu_si256(__m256i* ptr, __m256i a) {
142         pragma(LDC_allow_inline);
143         return inlineIR!(`store <4 x i64> %1, <4 x i64>* %0
144                              ret`,
145                          void)(ptr, a);
146         
147     }
148     
149     __m256i _mm256_permute4x64_epi64(__m256i a, in int M) {
150         pragma(LDC_allow_inline);
151 
152         int[4] val = [(M) & 0x3, ((M) & 0xc) >> 2, ((M) & 0x30) >> 4, ((M) & 0xc0) >> 6];
153         return inlineIR!(`%tmp = shufflevector <4 x i64> %0, <4 x i64> undef, <i32 %1, i32 %2, i32 %3, i32 %4>
154                              ret <4 x i64> %tmp`,
155                          __m256i)(a, val[0], val[1], val[2], val[3]);        
156     }
157     
158     __m256i _mm256_add_epi64(__m256i a, __m256i b) {
159         pragma(LDC_allow_inline);
160         return inlineIR!(`%tmp = add <4 x i64> %0, %1
161                              ret <4 x i64> %tmp`,
162                          __m256i)(a, b);
163     }
164 
165     __m256i _mm256_sub_epi64(__m256i a, __m256i b) {
166         pragma(LDC_allow_inline);
167         return inlineIR!(`%tmp = sub <4 x i64> %0, %1
168                              ret <4 x i64> %tmp`,
169                          __m256i)(a, b);
170     }
171         
172     __m256i _mm256_xor_si256(__m256i a, __m256i b) {
173         pragma(LDC_allow_inline);
174         return inlineIR!(`%tmp = xor <4 x i64> %0, %1
175                              ret <4 x i64> %tmp`,
176                          __m256i)(a, b);
177     }
178     
179     __m256i _mm256_or_si256(__m256i a, __m256i b) {
180         pragma(LDC_allow_inline);
181         return inlineIR!(`%tmp = or <4 x i64> %0, %1
182                              ret <4 x i64> %tmp`,
183                          __m256i)(a, b);
184     }
185 
186     pragma(LDC_intrinsic, "llvm.x86.avx2.psrlv.q.256")
187         __m256i _mm256_srlv_epi64(__m256i a, __m256i b);
188 
189     pragma(LDC_intrinsic, "llvm.x86.avx2.psllv.q.256")
190         __m256i _mm256_sllv_epi64(__m256i a, __m256i b);
191 
192 
193 
194 }
195 
196 version(D_InlineAsm_X86_64) {
197     static assert(false, "DMD does not currently support AVX2.");
198 
199     __m256i _mm256_unpacklo_epi64(__m256i a, __m256i b) 
200     {
201         // http://www.felixcloutier.com/x86/PUNPCKLBW:PUNPCKLWD:PUNPCKLDQ:PUNPCKLQDQ.html
202 
203         __m256i ret;
204 
205         __m256i* _a = &a;
206         __m256i* _b = &b;
207         __m256i* _c = &ret;
208         
209         asm 
210         {
211             mov RAX, _a;
212             mov RBX, _b;
213             mov RCX, _c;
214             vpunpcklqdq [RCX], [RAX], [RBX]; 
215         }
216         
217         return ret;
218         
219     }
220 
221     __m256i _mm256_unpackhi_epi64(__m256i a, __m256i b) 
222     {
223         // http://www.felixcloutier.com/x86/PUNPCKHBW:PUNPCKHWD:PUNPCKHDQ:PUNPCKHQDQ.html
224 
225         __m256i ret;
226 
227         __m256i* _a = &a;
228         __m256i* _b = &b;
229         __m256i* _c = &ret;
230         
231         asm 
232         {
233             mov RAX, _a;
234             mov RBX, _b;
235             mov RCX, _c;
236             vpunpckhqdq [RCX], [RAX], [RBX];
237         }
238         
239         return ret;
240         
241     }
242 
243     __m256i _mm256_set_epi64x(long a, long b, long c, long d) {
244         return cast(__m256i) long4([a, b, c, d]);
245     }
246     
247     __m256i _mm256_loadu_si256(__m256i* a) 
248     {
249         // http://www.felixcloutier.com/x86/MOVDQU.html
250 
251         __m256i ret;
252         __m256i* b = &ret;
253         asm 
254         {
255             mov RAX, a;
256             mov RBX, b;
257             vmovdqu YMM0, [RAX];
258             vmovdqu [RBX], YMM0;
259         }
260         
261         return ret;
262         
263     }
264 
265     void _mm256_storeu_si256(__m256i* ptr, __m256i a) {
266 
267         __m256i ret;
268         __m256i* _a = &a;
269         __m256i* _b = &ret;
270         asm 
271         {
272             mov RAX, _a;
273             mov RBX, _b;
274             vmovdqu YMM0, [RAX];
275             vmovdqu [RBX], YMM0;
276         }
277 
278         *ptr = ret;
279                 
280     }
281 
282     __m256i _mm256_permute4x64_epi64(__m256i a, in int M) {
283         __m256i ret;
284         __m256i* _a = &a;
285         __m256i* _b = &ret;
286         ubyte[4] val = [cast(ubyte) ((M) & 0x3), cast(ubyte) (((M) & 0xc) >> 2), cast(ubyte) (((M) & 0x30) >> 4), cast(ubyte) (((M) & 0xc0) >> 6)];
287 
288         ubyte _imm8;
289         _imm8 |= (val >> 0) & 0x3;
290         _imm8 |= (val >> 2) & 0x3;
291         _imm8 |= (val >> 4) & 0x3;
292         _imm8 |= (val >> 6) & 0x3;
293 
294         asm 
295         {
296             mov imm8, _imm8;
297             mov RAX, _a;
298             mov RBX, _b;
299             vmovdqu YMM0, [RAX];
300             vmovdqu [RBX], YMM0;
301         }
302         
303         *ptr = ret;    
304     }
305 
306     // todo: Prepare the rest of the assembly. Use GDC/LDC in the meantime
307 
308 }
309 
310 // _mm256_unpacklo_epi64
311 // _mm256_unpackhi_epi64
312 // _mm256_set_epi64x
313 // _mm256_loadu_si256
314 // _mm256_storeu_si256
315 // _mm256_permute4x64_epi64
316 // _mm256_add_epi64
317 // _mm256_sub_epi64
318 // _mm256_xor_si256
319 // _mm256_or_si256
320 // _mm256_srlv_epi64
321 // _mm256_sllv_epi64
322 // _rdrand32_step => asm(".ubyte 0x0F, 0xC7, 0xF0; adcl $0,%1" : "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");