]> git.sesse.net Git - stockfish/blob - src/simd.h
Enable compilation on older Windows systems
[stockfish] / src / simd.h
1 /*
2   Stockfish, a UCI chess playing engine derived from Glaurung 2.1
3   Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
4
5   Stockfish is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9
10   Stockfish is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifndef STOCKFISH_SIMD_H_INCLUDED
20 #define STOCKFISH_SIMD_H_INCLUDED
21
22 #if defined(USE_AVX2)
23 # include <immintrin.h>
24
25 #elif defined(USE_SSE41)
26 # include <smmintrin.h>
27
28 #elif defined(USE_SSSE3)
29 # include <tmmintrin.h>
30
31 #elif defined(USE_SSE2)
32 # include <emmintrin.h>
33
34 #elif defined(USE_MMX)
35 # include <mmintrin.h>
36
37 #elif defined(USE_NEON)
38 # include <arm_neon.h>
39 #endif
40
41 // The inline asm is only safe for GCC, where it is necessary to get good codegen.
42 // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101693
43 // Clang does fine without it.
44 // Play around here: https://godbolt.org/z/7EWqrYq51
45 #if (defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER))
46 #define USE_INLINE_ASM
47 #endif
48
49 namespace Stockfish::Simd {
50
51 #if defined (USE_AVX512)
52
53     [[maybe_unused]] static int m512_hadd(__m512i sum, int bias) {
54       return _mm512_reduce_add_epi32(sum) + bias;
55     }
56
57     /*
58       Parameters:
59         sum0 = [zmm0.i128[0], zmm0.i128[1], zmm0.i128[2], zmm0.i128[3]]
60         sum1 = [zmm1.i128[0], zmm1.i128[1], zmm1.i128[2], zmm1.i128[3]]
61         sum2 = [zmm2.i128[0], zmm2.i128[1], zmm2.i128[2], zmm2.i128[3]]
62         sum3 = [zmm3.i128[0], zmm3.i128[1], zmm3.i128[2], zmm3.i128[3]]
63
64       Returns:
65         ret = [
66           reduce_add_epi32(zmm0.i128[0]), reduce_add_epi32(zmm1.i128[0]), reduce_add_epi32(zmm2.i128[0]), reduce_add_epi32(zmm3.i128[0]),
67           reduce_add_epi32(zmm0.i128[1]), reduce_add_epi32(zmm1.i128[1]), reduce_add_epi32(zmm2.i128[1]), reduce_add_epi32(zmm3.i128[1]),
68           reduce_add_epi32(zmm0.i128[2]), reduce_add_epi32(zmm1.i128[2]), reduce_add_epi32(zmm2.i128[2]), reduce_add_epi32(zmm3.i128[2]),
69           reduce_add_epi32(zmm0.i128[3]), reduce_add_epi32(zmm1.i128[3]), reduce_add_epi32(zmm2.i128[3]), reduce_add_epi32(zmm3.i128[3])
70         ]
71     */
72     [[maybe_unused]] static __m512i m512_hadd128x16_interleave(
73         __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3) {
74
75       __m512i sum01a = _mm512_unpacklo_epi32(sum0, sum1);
76       __m512i sum01b = _mm512_unpackhi_epi32(sum0, sum1);
77
78       __m512i sum23a = _mm512_unpacklo_epi32(sum2, sum3);
79       __m512i sum23b = _mm512_unpackhi_epi32(sum2, sum3);
80
81       __m512i sum01 = _mm512_add_epi32(sum01a, sum01b);
82       __m512i sum23 = _mm512_add_epi32(sum23a, sum23b);
83
84       __m512i sum0123a = _mm512_unpacklo_epi64(sum01, sum23);
85       __m512i sum0123b = _mm512_unpackhi_epi64(sum01, sum23);
86
87       return _mm512_add_epi32(sum0123a, sum0123b);
88     }
89
90     [[maybe_unused]] static __m128i m512_haddx4(
91         __m512i sum0, __m512i sum1, __m512i sum2, __m512i sum3,
92         __m128i bias) {
93
94       __m512i sum = m512_hadd128x16_interleave(sum0, sum1, sum2, sum3);
95
96       __m256i sum256lo = _mm512_castsi512_si256(sum);
97       __m256i sum256hi = _mm512_extracti64x4_epi64(sum, 1);
98
99       sum256lo = _mm256_add_epi32(sum256lo, sum256hi);
100
101       __m128i sum128lo = _mm256_castsi256_si128(sum256lo);
102       __m128i sum128hi = _mm256_extracti128_si256(sum256lo, 1);
103
104       return _mm_add_epi32(_mm_add_epi32(sum128lo, sum128hi), bias);
105     }
106
107     [[maybe_unused]] static void m512_add_dpbusd_epi32(
108         __m512i& acc,
109         __m512i a,
110         __m512i b) {
111
112 # if defined (USE_VNNI)
113 #   if defined (USE_INLINE_ASM)
114       asm(
115         "vpdpbusd %[b], %[a], %[acc]\n\t"
116         : [acc]"+v"(acc)
117         : [a]"v"(a), [b]"vm"(b)
118       );
119 #   else
120       acc = _mm512_dpbusd_epi32(acc, a, b);
121 #   endif
122 # else
123 #   if defined (USE_INLINE_ASM)
124       __m512i tmp = _mm512_maddubs_epi16(a, b);
125       asm(
126           "vpmaddwd    %[tmp], %[ones], %[tmp]\n\t"
127           "vpaddd      %[acc], %[tmp], %[acc]\n\t"
128           : [acc]"+v"(acc), [tmp]"+&v"(tmp)
129           : [ones]"v"(_mm512_set1_epi16(1))
130       );
131 #   else
132       __m512i product0 = _mm512_maddubs_epi16(a, b);
133       product0 = _mm512_madd_epi16(product0, _mm512_set1_epi16(1));
134       acc = _mm512_add_epi32(acc, product0);
135 #   endif
136 # endif
137     }
138
139     [[maybe_unused]] static void m512_add_dpbusd_epi32x2(
140         __m512i& acc,
141         __m512i a0, __m512i b0,
142         __m512i a1, __m512i b1) {
143
144 # if defined (USE_VNNI)
145 #   if defined (USE_INLINE_ASM)
146       asm(
147         "vpdpbusd %[b0], %[a0], %[acc]\n\t"
148         "vpdpbusd %[b1], %[a1], %[acc]\n\t"
149         : [acc]"+v"(acc)
150         : [a0]"v"(a0), [b0]"vm"(b0), [a1]"v"(a1), [b1]"vm"(b1)
151       );
152 #   else
153       acc = _mm512_dpbusd_epi32(acc, a0, b0);
154       acc = _mm512_dpbusd_epi32(acc, a1, b1);
155 #   endif
156 # else
157 #   if defined (USE_INLINE_ASM)
158       __m512i tmp0 = _mm512_maddubs_epi16(a0, b0);
159       __m512i tmp1 = _mm512_maddubs_epi16(a1, b1);
160       asm(
161           "vpaddsw     %[tmp0], %[tmp1], %[tmp0]\n\t"
162           "vpmaddwd    %[tmp0], %[ones], %[tmp0]\n\t"
163           "vpaddd      %[acc], %[tmp0], %[acc]\n\t"
164           : [acc]"+v"(acc), [tmp0]"+&v"(tmp0)
165           : [tmp1]"v"(tmp1), [ones]"v"(_mm512_set1_epi16(1))
166       );
167 #   else
168       __m512i product0 = _mm512_maddubs_epi16(a0, b0);
169       __m512i product1 = _mm512_maddubs_epi16(a1, b1);
170       product0 = _mm512_adds_epi16(product0, product1);
171       product0 = _mm512_madd_epi16(product0, _mm512_set1_epi16(1));
172       acc = _mm512_add_epi32(acc, product0);
173 #   endif
174 # endif
175     }
176
177 #endif
178
179 #if defined (USE_AVX2)
180
181     [[maybe_unused]] static int m256_hadd(__m256i sum, int bias) {
182       __m128i sum128 = _mm_add_epi32(_mm256_castsi256_si128(sum), _mm256_extracti128_si256(sum, 1));
183       sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_PERM_BADC));
184       sum128 = _mm_add_epi32(sum128, _mm_shuffle_epi32(sum128, _MM_PERM_CDAB));
185       return _mm_cvtsi128_si32(sum128) + bias;
186     }
187
188     [[maybe_unused]] static __m128i m256_haddx4(
189         __m256i sum0, __m256i sum1, __m256i sum2, __m256i sum3,
190         __m128i bias) {
191
192       sum0 = _mm256_hadd_epi32(sum0, sum1);
193       sum2 = _mm256_hadd_epi32(sum2, sum3);
194
195       sum0 = _mm256_hadd_epi32(sum0, sum2);
196
197       __m128i sum128lo = _mm256_castsi256_si128(sum0);
198       __m128i sum128hi = _mm256_extracti128_si256(sum0, 1);
199
200       return _mm_add_epi32(_mm_add_epi32(sum128lo, sum128hi), bias);
201     }
202
203     [[maybe_unused]] static void m256_add_dpbusd_epi32(
204         __m256i& acc,
205         __m256i a,
206         __m256i b) {
207
208 # if defined (USE_VNNI)
209 #   if defined (USE_INLINE_ASM)
210       asm(
211         "vpdpbusd %[b], %[a], %[acc]\n\t"
212         : [acc]"+v"(acc)
213         : [a]"v"(a), [b]"vm"(b)
214       );
215 #   else
216       acc = _mm256_dpbusd_epi32(acc, a, b);
217 #   endif
218 # else
219 #   if defined (USE_INLINE_ASM)
220       __m256i tmp = _mm256_maddubs_epi16(a, b);
221       asm(
222           "vpmaddwd    %[tmp], %[ones], %[tmp]\n\t"
223           "vpaddd      %[acc], %[tmp], %[acc]\n\t"
224           : [acc]"+v"(acc), [tmp]"+&v"(tmp)
225           : [ones]"v"(_mm256_set1_epi16(1))
226       );
227 #   else
228       __m256i product0 = _mm256_maddubs_epi16(a, b);
229       product0 = _mm256_madd_epi16(product0, _mm256_set1_epi16(1));
230       acc = _mm256_add_epi32(acc, product0);
231 #   endif
232 # endif
233     }
234
235     [[maybe_unused]] static void m256_add_dpbusd_epi32x2(
236         __m256i& acc,
237         __m256i a0, __m256i b0,
238         __m256i a1, __m256i b1) {
239
240 # if defined (USE_VNNI)
241 #   if defined (USE_INLINE_ASM)
242       asm(
243         "vpdpbusd %[b0], %[a0], %[acc]\n\t"
244         "vpdpbusd %[b1], %[a1], %[acc]\n\t"
245         : [acc]"+v"(acc)
246         : [a0]"v"(a0), [b0]"vm"(b0), [a1]"v"(a1), [b1]"vm"(b1)
247       );
248 #   else
249       acc = _mm256_dpbusd_epi32(acc, a0, b0);
250       acc = _mm256_dpbusd_epi32(acc, a1, b1);
251 #   endif
252 # else
253 #   if defined (USE_INLINE_ASM)
254       __m256i tmp0 = _mm256_maddubs_epi16(a0, b0);
255       __m256i tmp1 = _mm256_maddubs_epi16(a1, b1);
256       asm(
257           "vpaddsw     %[tmp0], %[tmp1], %[tmp0]\n\t"
258           "vpmaddwd    %[tmp0], %[ones], %[tmp0]\n\t"
259           "vpaddd      %[acc], %[tmp0], %[acc]\n\t"
260           : [acc]"+v"(acc), [tmp0]"+&v"(tmp0)
261           : [tmp1]"v"(tmp1), [ones]"v"(_mm256_set1_epi16(1))
262       );
263 #   else
264       __m256i product0 = _mm256_maddubs_epi16(a0, b0);
265       __m256i product1 = _mm256_maddubs_epi16(a1, b1);
266       product0 = _mm256_adds_epi16(product0, product1);
267       product0 = _mm256_madd_epi16(product0, _mm256_set1_epi16(1));
268       acc = _mm256_add_epi32(acc, product0);
269 #   endif
270 # endif
271     }
272
273 #endif
274
275 #if defined (USE_SSSE3)
276
277     [[maybe_unused]] static int m128_hadd(__m128i sum, int bias) {
278       sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, 0x4E)); //_MM_PERM_BADC
279       sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, 0xB1)); //_MM_PERM_CDAB
280       return _mm_cvtsi128_si32(sum) + bias;
281     }
282
283     [[maybe_unused]] static __m128i m128_haddx4(
284         __m128i sum0, __m128i sum1, __m128i sum2, __m128i sum3,
285         __m128i bias) {
286
287       sum0 = _mm_hadd_epi32(sum0, sum1);
288       sum2 = _mm_hadd_epi32(sum2, sum3);
289       sum0 = _mm_hadd_epi32(sum0, sum2);
290       return _mm_add_epi32(sum0, bias);
291     }
292
293     [[maybe_unused]] static void m128_add_dpbusd_epi32(
294         __m128i& acc,
295         __m128i a,
296         __m128i b) {
297
298 #   if defined (USE_INLINE_ASM)
299       __m128i tmp = _mm_maddubs_epi16(a, b);
300       asm(
301           "pmaddwd    %[ones], %[tmp]\n\t"
302           "paddd      %[tmp], %[acc]\n\t"
303           : [acc]"+v"(acc), [tmp]"+&v"(tmp)
304           : [ones]"v"(_mm_set1_epi16(1))
305       );
306 #   else
307       __m128i product0 = _mm_maddubs_epi16(a, b);
308       product0 = _mm_madd_epi16(product0, _mm_set1_epi16(1));
309       acc = _mm_add_epi32(acc, product0);
310 #   endif
311     }
312
313     [[maybe_unused]] static void m128_add_dpbusd_epi32x2(
314         __m128i& acc,
315         __m128i a0, __m128i b0,
316         __m128i a1, __m128i b1) {
317
318 #   if defined (USE_INLINE_ASM)
319       __m128i tmp0 = _mm_maddubs_epi16(a0, b0);
320       __m128i tmp1 = _mm_maddubs_epi16(a1, b1);
321       asm(
322           "paddsw     %[tmp1], %[tmp0]\n\t"
323           "pmaddwd    %[ones], %[tmp0]\n\t"
324           "paddd      %[tmp0], %[acc]\n\t"
325           : [acc]"+v"(acc), [tmp0]"+&v"(tmp0)
326           : [tmp1]"v"(tmp1), [ones]"v"(_mm_set1_epi16(1))
327       );
328 #   else
329       __m128i product0 = _mm_maddubs_epi16(a0, b0);
330       __m128i product1 = _mm_maddubs_epi16(a1, b1);
331       product0 = _mm_adds_epi16(product0, product1);
332       product0 = _mm_madd_epi16(product0, _mm_set1_epi16(1));
333       acc = _mm_add_epi32(acc, product0);
334 #   endif
335     }
336
337 #endif
338
339 }
340
341 #endif // STOCKFISH_SIMD_H_INCLUDED