Line data Source code
1 : /* crc-intel-pclmul.c - Intel PCLMUL accelerated CRC implementation
2 : * Copyright (C) 2016 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3 : *
4 : * This file is part of Libgcrypt.
5 : *
6 : * Libgcrypt is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU Lesser General Public License as
8 : * published by the Free Software Foundation; either version 2.1 of
9 : * the License, or (at your option) any later version.
10 : *
11 : * Libgcrypt is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU Lesser General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public
17 : * License along with this program; if not, write to the Free Software
18 : * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 : *
20 : */
21 :
22 : #include <config.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <string.h>
26 :
27 : #include "g10lib.h"
28 :
29 : #include "bithelp.h"
30 : #include "bufhelp.h"
31 :
32 :
33 : #if defined(ENABLE_PCLMUL_SUPPORT) && defined(ENABLE_SSE41_SUPPORT) && \
34 : __GNUC__ >= 4 && \
35 : ((defined(__i386__) && SIZEOF_UNSIGNED_LONG == 4) || defined(__x86_64__))
36 :
37 :
38 : #if _GCRY_GCC_VERSION >= 40400 /* 4.4 */
39 : /* Prevent compiler from issuing SSE instructions between asm blocks. */
40 : # pragma GCC target("no-sse")
41 : #endif
42 :
43 :
44 : #define ALIGNED_16 __attribute__ ((aligned (16)))
45 :
46 :
47 : struct u16_unaligned_s
48 : {
49 : u16 a;
50 : } __attribute__((packed, aligned (1), may_alias));
51 :
52 :
53 : /* Constants structure for generic reflected/non-reflected CRC32 CLMUL
54 : * functions. */
55 : struct crc32_consts_s
56 : {
57 : /* k: { x^(32*17), x^(32*15), x^(32*5), x^(32*3), x^(32*2), 0 } mod P(x) */
58 : u64 k[6];
59 : /* my_p: { floor(x^64 / P(x)), P(x) } */
60 : u64 my_p[2];
61 : };
62 :
63 :
64 : /* CLMUL constants for CRC32 and CRC32RFC1510. */
65 : static const struct crc32_consts_s crc32_consts ALIGNED_16 =
66 : {
67 : { /* k[6] = reverse_33bits( x^(32*y) mod P(x) ) */
68 : U64_C(0x154442bd4), U64_C(0x1c6e41596), /* y = { 17, 15 } */
69 : U64_C(0x1751997d0), U64_C(0x0ccaa009e), /* y = { 5, 3 } */
70 : U64_C(0x163cd6124), 0 /* y = 2 */
71 : },
72 : { /* my_p[2] = reverse_33bits ( { floor(x^64 / P(x)), P(x) } ) */
73 : U64_C(0x1f7011641), U64_C(0x1db710641)
74 : }
75 : };
76 :
77 : /* CLMUL constants for CRC24RFC2440 (polynomial multiplied with x⁸). */
78 : static const struct crc32_consts_s crc24rfc2440_consts ALIGNED_16 =
79 : {
80 : { /* k[6] = x^(32*y) mod P(x) << 32*/
81 : U64_C(0x08289a00) << 32, U64_C(0x74b44a00) << 32, /* y = { 17, 15 } */
82 : U64_C(0xc4b14d00) << 32, U64_C(0xfd7e0c00) << 32, /* y = { 5, 3 } */
83 : U64_C(0xd9fe8c00) << 32, 0 /* y = 2 */
84 : },
85 : { /* my_p[2] = { floor(x^64 / P(x)), P(x) } */
86 : U64_C(0x1f845fe24), U64_C(0x1864cfb00)
87 : }
88 : };
89 :
90 : /* Common constants for CRC32 algorithms. */
91 : static const byte crc32_refl_shuf_shift[3 * 16] ALIGNED_16 =
92 : {
93 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
94 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
95 : 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
96 : 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
97 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
98 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
99 : };
100 : static const byte crc32_shuf_shift[3 * 16] ALIGNED_16 =
101 : {
102 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
103 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
104 : 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
105 : 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
106 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
107 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
108 : };
109 : static const byte *crc32_bswap_shuf = &crc32_shuf_shift[16];
110 : static const byte crc32_partial_fold_input_mask[16 + 16] ALIGNED_16 =
111 : {
112 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
113 : 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
115 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
116 : };
117 : static const u64 crc32_merge9to15_shuf[15 - 9 + 1][2] ALIGNED_16 =
118 : {
119 : { U64_C(0x0706050403020100), U64_C(0xffffffffffffff0f) }, /* 9 */
120 : { U64_C(0x0706050403020100), U64_C(0xffffffffffff0f0e) },
121 : { U64_C(0x0706050403020100), U64_C(0xffffffffff0f0e0d) },
122 : { U64_C(0x0706050403020100), U64_C(0xffffffff0f0e0d0c) },
123 : { U64_C(0x0706050403020100), U64_C(0xffffff0f0e0d0c0b) },
124 : { U64_C(0x0706050403020100), U64_C(0xffff0f0e0d0c0b0a) },
125 : { U64_C(0x0706050403020100), U64_C(0xff0f0e0d0c0b0a09) }, /* 15 */
126 : };
127 : static const u64 crc32_merge5to7_shuf[7 - 5 + 1][2] ALIGNED_16 =
128 : {
129 : { U64_C(0xffffff0703020100), U64_C(0xffffffffffffffff) }, /* 5 */
130 : { U64_C(0xffff070603020100), U64_C(0xffffffffffffffff) },
131 : { U64_C(0xff07060503020100), U64_C(0xffffffffffffffff) }, /* 7 */
132 : };
133 :
134 : /* PCLMUL functions for reflected CRC32. */
135 : static inline void
136 35948 : crc32_reflected_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
137 : const struct crc32_consts_s *consts)
138 : {
139 35948 : if (inlen >= 8 * 16)
140 : {
141 14086 : asm volatile ("movd %[crc], %%xmm4\n\t"
142 : "movdqu %[inbuf_0], %%xmm0\n\t"
143 : "movdqu %[inbuf_1], %%xmm1\n\t"
144 : "movdqu %[inbuf_2], %%xmm2\n\t"
145 : "movdqu %[inbuf_3], %%xmm3\n\t"
146 : "pxor %%xmm4, %%xmm0\n\t"
147 : :
148 : : [inbuf_0] "m" (inbuf[0 * 16]),
149 14086 : [inbuf_1] "m" (inbuf[1 * 16]),
150 14086 : [inbuf_2] "m" (inbuf[2 * 16]),
151 14086 : [inbuf_3] "m" (inbuf[3 * 16]),
152 : [crc] "m" (*pcrc)
153 : );
154 :
155 14086 : inbuf += 4 * 16;
156 14086 : inlen -= 4 * 16;
157 :
158 14086 : asm volatile ("movdqa %[k1k2], %%xmm4\n\t"
159 : :
160 : : [k1k2] "m" (consts->k[1 - 1])
161 : );
162 :
163 : /* Fold by 4. */
164 259514 : while (inlen >= 4 * 16)
165 : {
166 231342 : asm volatile ("movdqu %[inbuf_0], %%xmm5\n\t"
167 : "movdqa %%xmm0, %%xmm6\n\t"
168 : "pclmulqdq $0x00, %%xmm4, %%xmm0\n\t"
169 : "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t"
170 : "pxor %%xmm5, %%xmm0\n\t"
171 : "pxor %%xmm6, %%xmm0\n\t"
172 :
173 : "movdqu %[inbuf_1], %%xmm5\n\t"
174 : "movdqa %%xmm1, %%xmm6\n\t"
175 : "pclmulqdq $0x00, %%xmm4, %%xmm1\n\t"
176 : "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t"
177 : "pxor %%xmm5, %%xmm1\n\t"
178 : "pxor %%xmm6, %%xmm1\n\t"
179 :
180 : "movdqu %[inbuf_2], %%xmm5\n\t"
181 : "movdqa %%xmm2, %%xmm6\n\t"
182 : "pclmulqdq $0x00, %%xmm4, %%xmm2\n\t"
183 : "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t"
184 : "pxor %%xmm5, %%xmm2\n\t"
185 : "pxor %%xmm6, %%xmm2\n\t"
186 :
187 : "movdqu %[inbuf_3], %%xmm5\n\t"
188 : "movdqa %%xmm3, %%xmm6\n\t"
189 : "pclmulqdq $0x00, %%xmm4, %%xmm3\n\t"
190 : "pclmulqdq $0x11, %%xmm4, %%xmm6\n\t"
191 : "pxor %%xmm5, %%xmm3\n\t"
192 : "pxor %%xmm6, %%xmm3\n\t"
193 : :
194 : : [inbuf_0] "m" (inbuf[0 * 16]),
195 231342 : [inbuf_1] "m" (inbuf[1 * 16]),
196 231342 : [inbuf_2] "m" (inbuf[2 * 16]),
197 231342 : [inbuf_3] "m" (inbuf[3 * 16])
198 : );
199 :
200 231342 : inbuf += 4 * 16;
201 231342 : inlen -= 4 * 16;
202 : }
203 :
204 14086 : asm volatile ("movdqa %[k3k4], %%xmm6\n\t"
205 : "movdqa %[my_p], %%xmm5\n\t"
206 : :
207 : : [k3k4] "m" (consts->k[3 - 1]),
208 : [my_p] "m" (consts->my_p[0])
209 : );
210 :
211 : /* Fold 4 to 1. */
212 :
213 14086 : asm volatile ("movdqa %%xmm0, %%xmm4\n\t"
214 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
215 : "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t"
216 : "pxor %%xmm1, %%xmm0\n\t"
217 : "pxor %%xmm4, %%xmm0\n\t"
218 :
219 : "movdqa %%xmm0, %%xmm4\n\t"
220 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
221 : "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t"
222 : "pxor %%xmm2, %%xmm0\n\t"
223 : "pxor %%xmm4, %%xmm0\n\t"
224 :
225 : "movdqa %%xmm0, %%xmm4\n\t"
226 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
227 : "pclmulqdq $0x11, %%xmm6, %%xmm4\n\t"
228 : "pxor %%xmm3, %%xmm0\n\t"
229 : "pxor %%xmm4, %%xmm0\n\t"
230 : :
231 : :
232 : );
233 : }
234 : else
235 : {
236 21862 : asm volatile ("movd %[crc], %%xmm1\n\t"
237 : "movdqu %[inbuf], %%xmm0\n\t"
238 : "movdqa %[k3k4], %%xmm6\n\t"
239 : "pxor %%xmm1, %%xmm0\n\t"
240 : "movdqa %[my_p], %%xmm5\n\t"
241 : :
242 : : [inbuf] "m" (*inbuf),
243 : [crc] "m" (*pcrc),
244 : [k3k4] "m" (consts->k[3 - 1]),
245 : [my_p] "m" (consts->my_p[0])
246 : );
247 :
248 21862 : inbuf += 16;
249 21862 : inlen -= 16;
250 : }
251 :
252 : /* Fold by 1. */
253 35948 : if (inlen >= 16)
254 : {
255 185803 : while (inlen >= 16)
256 : {
257 : /* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */
258 122283 : asm volatile ("movdqu %[inbuf], %%xmm2\n\t"
259 : "movdqa %%xmm0, %%xmm1\n\t"
260 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
261 : "pclmulqdq $0x11, %%xmm6, %%xmm1\n\t"
262 : "pxor %%xmm2, %%xmm0\n\t"
263 : "pxor %%xmm1, %%xmm0\n\t"
264 : :
265 : : [inbuf] "m" (*inbuf)
266 : );
267 :
268 122283 : inbuf += 16;
269 122283 : inlen -= 16;
270 : }
271 : }
272 :
273 : /* Partial fold. */
274 35948 : if (inlen)
275 : {
276 : /* Load last input and add padding zeros. */
277 31917 : asm volatile ("movdqu %[shr_shuf], %%xmm3\n\t"
278 : "movdqu %[shl_shuf], %%xmm4\n\t"
279 : "movdqu %[mask], %%xmm2\n\t"
280 :
281 : "movdqa %%xmm0, %%xmm1\n\t"
282 : "pshufb %%xmm4, %%xmm0\n\t"
283 : "movdqu %[inbuf], %%xmm4\n\t"
284 : "pshufb %%xmm3, %%xmm1\n\t"
285 : "pand %%xmm4, %%xmm2\n\t"
286 : "por %%xmm1, %%xmm2\n\t"
287 :
288 : "movdqa %%xmm0, %%xmm1\n\t"
289 : "pclmulqdq $0x00, %%xmm6, %%xmm0\n\t"
290 : "pclmulqdq $0x11, %%xmm6, %%xmm1\n\t"
291 : "pxor %%xmm2, %%xmm0\n\t"
292 : "pxor %%xmm1, %%xmm0\n\t"
293 : :
294 31917 : : [inbuf] "m" (*(inbuf - 16 + inlen)),
295 : [mask] "m" (crc32_partial_fold_input_mask[inlen]),
296 : [shl_shuf] "m" (crc32_refl_shuf_shift[inlen]),
297 31917 : [shr_shuf] "m" (crc32_refl_shuf_shift[inlen + 16])
298 : );
299 :
300 31917 : inbuf += inlen;
301 31917 : inlen -= inlen;
302 : }
303 :
304 : /* Final fold. */
305 35948 : asm volatile (/* reduce 128-bits to 96-bits */
306 : "movdqa %%xmm0, %%xmm1\n\t"
307 : "pclmulqdq $0x10, %%xmm6, %%xmm0\n\t"
308 : "psrldq $8, %%xmm1\n\t"
309 : "pxor %%xmm1, %%xmm0\n\t"
310 :
311 : /* reduce 96-bits to 64-bits */
312 : "pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */
313 : "pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */
314 : "pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */
315 : "pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */
316 :
317 : /* barrett reduction */
318 : "pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */
319 : "pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */
320 : "pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */
321 : "pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */
322 : "pxor %%xmm1, %%xmm0\n\t"
323 :
324 : /* store CRC */
325 : "pextrd $2, %%xmm0, %[out]\n\t"
326 : : [out] "=m" (*pcrc)
327 : : [k5] "m" (consts->k[5 - 1])
328 : );
329 35948 : }
330 :
331 : static inline void
332 2000203 : crc32_reflected_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen,
333 : const struct crc32_consts_s *consts)
334 : {
335 2000203 : if (inlen < 4)
336 : {
337 2000046 : u32 crc = *pcrc;
338 : u32 data;
339 :
340 2000046 : asm volatile ("movdqa %[my_p], %%xmm5\n\t"
341 : :
342 : : [my_p] "m" (consts->my_p[0])
343 : );
344 :
345 2000046 : if (inlen == 1)
346 : {
347 2000021 : data = inbuf[0];
348 2000021 : data ^= crc;
349 2000021 : data <<= 24;
350 2000021 : crc >>= 8;
351 : }
352 25 : else if (inlen == 2)
353 : {
354 13 : data = ((const struct u16_unaligned_s *)inbuf)->a;
355 13 : data ^= crc;
356 13 : data <<= 16;
357 13 : crc >>= 16;
358 : }
359 : else
360 : {
361 12 : data = ((const struct u16_unaligned_s *)inbuf)->a;
362 12 : data |= inbuf[2] << 16;
363 12 : data ^= crc;
364 12 : data <<= 8;
365 12 : crc >>= 24;
366 : }
367 :
368 : /* Barrett reduction */
369 2000046 : asm volatile ("movd %[in], %%xmm0\n\t"
370 : "movd %[crc], %%xmm1\n\t"
371 :
372 : "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
373 : "psllq $32, %%xmm1\n\t"
374 : "pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */
375 : "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
376 : "pxor %%xmm1, %%xmm0\n\t"
377 :
378 : "pextrd $1, %%xmm0, %[out]\n\t"
379 : : [out] "=m" (*pcrc)
380 : : [in] "rm" (data),
381 : [crc] "rm" (crc)
382 : );
383 : }
384 157 : else if (inlen == 4)
385 : {
386 : /* Barrett reduction */
387 21 : asm volatile ("movd %[crc], %%xmm1\n\t"
388 : "movd %[in], %%xmm0\n\t"
389 : "movdqa %[my_p], %%xmm5\n\t"
390 : "pxor %%xmm1, %%xmm0\n\t"
391 :
392 : "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
393 : "pshufd $0xfc, %%xmm0, %%xmm0\n\t" /* [00][00][00][x] */
394 : "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
395 :
396 : "pextrd $1, %%xmm0, %[out]\n\t"
397 : : [out] "=m" (*pcrc)
398 : : [in] "m" (*inbuf),
399 : [crc] "m" (*pcrc),
400 : [my_p] "m" (consts->my_p[0])
401 : );
402 : }
403 : else
404 : {
405 136 : asm volatile ("movdqu %[shuf], %%xmm4\n\t"
406 : "movd %[crc], %%xmm1\n\t"
407 : "movdqa %[my_p], %%xmm5\n\t"
408 : "movdqa %[k3k4], %%xmm6\n\t"
409 : :
410 : : [shuf] "m" (crc32_refl_shuf_shift[inlen]),
411 : [crc] "m" (*pcrc),
412 : [my_p] "m" (consts->my_p[0]),
413 : [k3k4] "m" (consts->k[3 - 1])
414 : );
415 :
416 136 : if (inlen >= 8)
417 : {
418 104 : asm volatile ("movq %[inbuf], %%xmm0\n\t"
419 : :
420 : : [inbuf] "m" (*inbuf)
421 : );
422 104 : if (inlen > 8)
423 : {
424 92 : asm volatile (/*"pinsrq $1, %[inbuf_tail], %%xmm0\n\t"*/
425 : "movq %[inbuf_tail], %%xmm2\n\t"
426 : "punpcklqdq %%xmm2, %%xmm0\n\t"
427 : "pshufb %[merge_shuf], %%xmm0\n\t"
428 : :
429 92 : : [inbuf_tail] "m" (inbuf[inlen - 8]),
430 : [merge_shuf] "m"
431 92 : (*crc32_merge9to15_shuf[inlen - 9])
432 : );
433 : }
434 : }
435 : else
436 : {
437 32 : asm volatile ("movd %[inbuf], %%xmm0\n\t"
438 : "pinsrd $1, %[inbuf_tail], %%xmm0\n\t"
439 : "pshufb %[merge_shuf], %%xmm0\n\t"
440 : :
441 : : [inbuf] "m" (*inbuf),
442 32 : [inbuf_tail] "m" (inbuf[inlen - 4]),
443 : [merge_shuf] "m"
444 32 : (*crc32_merge5to7_shuf[inlen - 5])
445 : );
446 : }
447 :
448 : /* Final fold. */
449 136 : asm volatile ("pxor %%xmm1, %%xmm0\n\t"
450 : "pshufb %%xmm4, %%xmm0\n\t"
451 :
452 : /* reduce 128-bits to 96-bits */
453 : "movdqa %%xmm0, %%xmm1\n\t"
454 : "pclmulqdq $0x10, %%xmm6, %%xmm0\n\t"
455 : "psrldq $8, %%xmm1\n\t"
456 : "pxor %%xmm1, %%xmm0\n\t" /* top 32-bit are zero */
457 :
458 : /* reduce 96-bits to 64-bits */
459 : "pshufd $0xfc, %%xmm0, %%xmm1\n\t" /* [00][00][00][x] */
460 : "pshufd $0xf9, %%xmm0, %%xmm0\n\t" /* [00][00][x>>64][x>>32] */
461 : "pclmulqdq $0x00, %[k5], %%xmm1\n\t" /* [00][00][xx][xx] */
462 : "pxor %%xmm1, %%xmm0\n\t" /* top 64-bit are zero */
463 :
464 : /* barrett reduction */
465 : "pshufd $0xf3, %%xmm0, %%xmm1\n\t" /* [00][00][x>>32][00] */
466 : "pslldq $4, %%xmm0\n\t" /* [??][x>>32][??][??] */
467 : "pclmulqdq $0x00, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */
468 : "pclmulqdq $0x10, %%xmm5, %%xmm1\n\t" /* [00][xx][xx][00] */
469 : "pxor %%xmm1, %%xmm0\n\t"
470 :
471 : /* store CRC */
472 : "pextrd $2, %%xmm0, %[out]\n\t"
473 : : [out] "=m" (*pcrc)
474 : : [k5] "m" (consts->k[5 - 1])
475 : );
476 : }
477 2000203 : }
478 :
479 : /* PCLMUL functions for non-reflected CRC32. */
480 : static inline void
481 17425 : crc32_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
482 : const struct crc32_consts_s *consts)
483 : {
484 17425 : asm volatile ("movdqa %[bswap], %%xmm7\n\t"
485 : :
486 17425 : : [bswap] "m" (*crc32_bswap_shuf)
487 : );
488 :
489 17425 : if (inlen >= 8 * 16)
490 : {
491 6601 : asm volatile ("movd %[crc], %%xmm4\n\t"
492 : "movdqu %[inbuf_0], %%xmm0\n\t"
493 : "movdqu %[inbuf_1], %%xmm1\n\t"
494 : "movdqu %[inbuf_2], %%xmm2\n\t"
495 : "pxor %%xmm4, %%xmm0\n\t"
496 : "movdqu %[inbuf_3], %%xmm3\n\t"
497 : "pshufb %%xmm7, %%xmm0\n\t"
498 : "pshufb %%xmm7, %%xmm1\n\t"
499 : "pshufb %%xmm7, %%xmm2\n\t"
500 : "pshufb %%xmm7, %%xmm3\n\t"
501 : :
502 : : [inbuf_0] "m" (inbuf[0 * 16]),
503 6601 : [inbuf_1] "m" (inbuf[1 * 16]),
504 6601 : [inbuf_2] "m" (inbuf[2 * 16]),
505 6601 : [inbuf_3] "m" (inbuf[3 * 16]),
506 : [crc] "m" (*pcrc)
507 : );
508 :
509 6601 : inbuf += 4 * 16;
510 6601 : inlen -= 4 * 16;
511 :
512 6601 : asm volatile ("movdqa %[k1k2], %%xmm4\n\t"
513 : :
514 : : [k1k2] "m" (consts->k[1 - 1])
515 : );
516 :
517 : /* Fold by 4. */
518 114755 : while (inlen >= 4 * 16)
519 : {
520 101553 : asm volatile ("movdqu %[inbuf_0], %%xmm5\n\t"
521 : "movdqa %%xmm0, %%xmm6\n\t"
522 : "pshufb %%xmm7, %%xmm5\n\t"
523 : "pclmulqdq $0x01, %%xmm4, %%xmm0\n\t"
524 : "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t"
525 : "pxor %%xmm5, %%xmm0\n\t"
526 : "pxor %%xmm6, %%xmm0\n\t"
527 :
528 : "movdqu %[inbuf_1], %%xmm5\n\t"
529 : "movdqa %%xmm1, %%xmm6\n\t"
530 : "pshufb %%xmm7, %%xmm5\n\t"
531 : "pclmulqdq $0x01, %%xmm4, %%xmm1\n\t"
532 : "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t"
533 : "pxor %%xmm5, %%xmm1\n\t"
534 : "pxor %%xmm6, %%xmm1\n\t"
535 :
536 : "movdqu %[inbuf_2], %%xmm5\n\t"
537 : "movdqa %%xmm2, %%xmm6\n\t"
538 : "pshufb %%xmm7, %%xmm5\n\t"
539 : "pclmulqdq $0x01, %%xmm4, %%xmm2\n\t"
540 : "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t"
541 : "pxor %%xmm5, %%xmm2\n\t"
542 : "pxor %%xmm6, %%xmm2\n\t"
543 :
544 : "movdqu %[inbuf_3], %%xmm5\n\t"
545 : "movdqa %%xmm3, %%xmm6\n\t"
546 : "pshufb %%xmm7, %%xmm5\n\t"
547 : "pclmulqdq $0x01, %%xmm4, %%xmm3\n\t"
548 : "pclmulqdq $0x10, %%xmm4, %%xmm6\n\t"
549 : "pxor %%xmm5, %%xmm3\n\t"
550 : "pxor %%xmm6, %%xmm3\n\t"
551 : :
552 : : [inbuf_0] "m" (inbuf[0 * 16]),
553 101553 : [inbuf_1] "m" (inbuf[1 * 16]),
554 101553 : [inbuf_2] "m" (inbuf[2 * 16]),
555 101553 : [inbuf_3] "m" (inbuf[3 * 16])
556 : );
557 :
558 101553 : inbuf += 4 * 16;
559 101553 : inlen -= 4 * 16;
560 : }
561 :
562 6601 : asm volatile ("movdqa %[k3k4], %%xmm6\n\t"
563 : "movdqa %[my_p], %%xmm5\n\t"
564 : :
565 : : [k3k4] "m" (consts->k[3 - 1]),
566 : [my_p] "m" (consts->my_p[0])
567 : );
568 :
569 : /* Fold 4 to 1. */
570 :
571 6601 : asm volatile ("movdqa %%xmm0, %%xmm4\n\t"
572 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
573 : "pclmulqdq $0x10, %%xmm6, %%xmm4\n\t"
574 : "pxor %%xmm1, %%xmm0\n\t"
575 : "pxor %%xmm4, %%xmm0\n\t"
576 :
577 : "movdqa %%xmm0, %%xmm4\n\t"
578 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
579 : "pclmulqdq $0x10, %%xmm6, %%xmm4\n\t"
580 : "pxor %%xmm2, %%xmm0\n\t"
581 : "pxor %%xmm4, %%xmm0\n\t"
582 :
583 : "movdqa %%xmm0, %%xmm4\n\t"
584 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
585 : "pclmulqdq $0x10, %%xmm6, %%xmm4\n\t"
586 : "pxor %%xmm3, %%xmm0\n\t"
587 : "pxor %%xmm4, %%xmm0\n\t"
588 : :
589 : :
590 : );
591 : }
592 : else
593 : {
594 10824 : asm volatile ("movd %[crc], %%xmm1\n\t"
595 : "movdqu %[inbuf], %%xmm0\n\t"
596 : "movdqa %[k3k4], %%xmm6\n\t"
597 : "pxor %%xmm1, %%xmm0\n\t"
598 : "movdqa %[my_p], %%xmm5\n\t"
599 : "pshufb %%xmm7, %%xmm0\n\t"
600 : :
601 : : [inbuf] "m" (*inbuf),
602 : [crc] "m" (*pcrc),
603 : [k3k4] "m" (consts->k[3 - 1]),
604 : [my_p] "m" (consts->my_p[0])
605 : );
606 :
607 10824 : inbuf += 16;
608 10824 : inlen -= 16;
609 : }
610 :
611 : /* Fold by 1. */
612 17425 : if (inlen >= 16)
613 : {
614 91530 : while (inlen >= 16)
615 : {
616 : /* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */
617 60670 : asm volatile ("movdqu %[inbuf], %%xmm2\n\t"
618 : "movdqa %%xmm0, %%xmm1\n\t"
619 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
620 : "pshufb %%xmm7, %%xmm2\n\t"
621 : "pclmulqdq $0x10, %%xmm6, %%xmm1\n\t"
622 : "pxor %%xmm2, %%xmm0\n\t"
623 : "pxor %%xmm1, %%xmm0\n\t"
624 : :
625 : : [inbuf] "m" (*inbuf)
626 : );
627 :
628 60670 : inbuf += 16;
629 60670 : inlen -= 16;
630 : }
631 : }
632 :
633 : /* Partial fold. */
634 17425 : if (inlen)
635 : {
636 : /* Load last input and add padding zeros. */
637 15957 : asm volatile ("movdqu %[shl_shuf], %%xmm4\n\t"
638 : "movdqu %[shr_shuf], %%xmm3\n\t"
639 : "movdqu %[mask], %%xmm2\n\t"
640 :
641 : "movdqa %%xmm0, %%xmm1\n\t"
642 : "pshufb %%xmm4, %%xmm0\n\t"
643 : "movdqu %[inbuf], %%xmm4\n\t"
644 : "pshufb %%xmm3, %%xmm1\n\t"
645 : "pand %%xmm4, %%xmm2\n\t"
646 : "por %%xmm1, %%xmm2\n\t"
647 :
648 : "pshufb %%xmm7, %%xmm2\n\t"
649 :
650 : "movdqa %%xmm0, %%xmm1\n\t"
651 : "pclmulqdq $0x01, %%xmm6, %%xmm0\n\t"
652 : "pclmulqdq $0x10, %%xmm6, %%xmm1\n\t"
653 : "pxor %%xmm2, %%xmm0\n\t"
654 : "pxor %%xmm1, %%xmm0\n\t"
655 : :
656 15957 : : [inbuf] "m" (*(inbuf - 16 + inlen)),
657 : [mask] "m" (crc32_partial_fold_input_mask[inlen]),
658 15957 : [shl_shuf] "m" (crc32_refl_shuf_shift[32 - inlen]),
659 15957 : [shr_shuf] "m" (crc32_shuf_shift[inlen + 16])
660 : );
661 :
662 15957 : inbuf += inlen;
663 15957 : inlen -= inlen;
664 : }
665 :
666 : /* Final fold. */
667 17425 : asm volatile (/* reduce 128-bits to 96-bits */
668 : "movdqa %%xmm0, %%xmm1\n\t"
669 : "pclmulqdq $0x11, %%xmm6, %%xmm0\n\t"
670 : "pslldq $8, %%xmm1\n\t"
671 : "pxor %%xmm1, %%xmm0\n\t" /* bottom 32-bit are zero */
672 :
673 : /* reduce 96-bits to 64-bits */
674 : "pshufd $0x30, %%xmm0, %%xmm1\n\t" /* [00][x>>96][00][00] */
675 : "pshufd $0x24, %%xmm0, %%xmm0\n\t" /* [00][xx][xx][00] */
676 : "pclmulqdq $0x01, %[k5], %%xmm1\n\t" /* [00][xx][xx][00] */
677 : "pxor %%xmm1, %%xmm0\n\t" /* top and bottom 32-bit are zero */
678 :
679 : /* barrett reduction */
680 : "pshufd $0x01, %%xmm0, %%xmm1\n\t" /* [00][00][00][x>>32] */
681 : "pclmulqdq $0x01, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][xx] */
682 : "psrldq $4, %%xmm0\n\t" /* [00][00][xx][xx] */
683 : "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t"
684 : "pxor %%xmm1, %%xmm0\n\t"
685 :
686 : /* store CRC in input endian */
687 : "movd %%xmm0, %%eax\n\t"
688 : "bswapl %%eax\n\t"
689 : "movl %%eax, %[out]\n\t"
690 : : [out] "=m" (*pcrc)
691 : : [k5] "m" (consts->k[5 - 1])
692 : : "eax" );
693 17425 : }
694 :
695 : static inline void
696 1000089 : crc32_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen,
697 : const struct crc32_consts_s *consts)
698 : {
699 1000089 : if (inlen < 4)
700 : {
701 1000014 : u32 crc = *pcrc;
702 : u32 data;
703 :
704 1000014 : asm volatile ("movdqa %[my_p], %%xmm5\n\t"
705 : :
706 : : [my_p] "m" (consts->my_p[0])
707 : );
708 :
709 1000014 : if (inlen == 1)
710 : {
711 1000004 : data = inbuf[0];
712 1000004 : data ^= crc;
713 1000004 : data = _gcry_bswap32(data << 24);
714 1000004 : crc = _gcry_bswap32(crc >> 8);
715 : }
716 10 : else if (inlen == 2)
717 : {
718 5 : data = ((const struct u16_unaligned_s *)inbuf)->a;
719 5 : data ^= crc;
720 5 : data = _gcry_bswap32(data << 16);
721 5 : crc = _gcry_bswap32(crc >> 16);
722 : }
723 : else
724 : {
725 5 : data = ((const struct u16_unaligned_s *)inbuf)->a;
726 5 : data |= inbuf[2] << 16;
727 5 : data ^= crc;
728 5 : data = _gcry_bswap32(data << 8);
729 5 : crc = _gcry_bswap32(crc >> 24);
730 : }
731 :
732 : /* Barrett reduction */
733 1000014 : asm volatile ("movd %[in], %%xmm0\n\t"
734 : "psllq $32, %%xmm0\n\t" /* [00][00][xx][00] */
735 : "movd %[crc], %%xmm1\n\t"
736 :
737 : "pclmulqdq $0x00, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][00] */
738 : "pclmulqdq $0x11, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
739 : "pxor %%xmm1, %%xmm0\n\t"
740 :
741 : /* store CRC in input endian */
742 : "movd %%xmm0, %%eax\n\t"
743 : "bswapl %%eax\n\t"
744 : "movl %%eax, %[out]\n\t"
745 : : [out] "=m" (*pcrc)
746 : : [in] "r" (data),
747 : [crc] "r" (crc)
748 : : "eax" );
749 : }
750 75 : else if (inlen == 4)
751 : {
752 : /* Barrett reduction */
753 8 : asm volatile ("movd %[crc], %%xmm0\n\t"
754 : "movd %[in], %%xmm1\n\t"
755 : "movdqa %[my_p], %%xmm5\n\t"
756 : :
757 : : [in] "m" (*inbuf),
758 : [crc] "m" (*pcrc),
759 : [my_p] "m" (consts->my_p[0])
760 : : "cc" );
761 :
762 8 : asm volatile ("pxor %%xmm1, %%xmm0\n\t"
763 : "pshufb %[bswap], %%xmm0\n\t" /* [xx][00][00][00] */
764 :
765 : "pclmulqdq $0x01, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][00] */
766 : "pclmulqdq $0x11, %%xmm5, %%xmm0\n\t" /* [00][00][xx][xx] */
767 : :
768 8 : : [bswap] "m" (*crc32_bswap_shuf)
769 : : "cc" );
770 :
771 8 : asm volatile (/* store CRC in input endian */
772 : "movd %%xmm0, %%eax\n\t"
773 : "bswapl %%eax\n\t"
774 : "movl %%eax, %[out]\n\t"
775 : : [out] "=m" (*pcrc)
776 : :
777 : : "eax", "cc" );
778 : }
779 : else
780 : {
781 67 : asm volatile ("movdqu %[shuf], %%xmm7\n\t"
782 : "movd %[crc], %%xmm1\n\t"
783 : "movdqa %[my_p], %%xmm5\n\t"
784 : "movdqa %[k3k4], %%xmm6\n\t"
785 : :
786 67 : : [shuf] "m" (crc32_shuf_shift[32 - inlen]),
787 : [crc] "m" (*pcrc),
788 : [my_p] "m" (consts->my_p[0]),
789 : [k3k4] "m" (consts->k[3 - 1])
790 : );
791 :
792 67 : if (inlen >= 8)
793 : {
794 51 : asm volatile ("movq %[inbuf], %%xmm0\n\t"
795 : :
796 : : [inbuf] "m" (*inbuf)
797 : );
798 51 : if (inlen > 8)
799 : {
800 45 : asm volatile (/*"pinsrq $1, %[inbuf_tail], %%xmm0\n\t"*/
801 : "movq %[inbuf_tail], %%xmm2\n\t"
802 : "punpcklqdq %%xmm2, %%xmm0\n\t"
803 : "pshufb %[merge_shuf], %%xmm0\n\t"
804 : :
805 45 : : [inbuf_tail] "m" (inbuf[inlen - 8]),
806 : [merge_shuf] "m"
807 45 : (*crc32_merge9to15_shuf[inlen - 9])
808 : );
809 : }
810 : }
811 : else
812 : {
813 16 : asm volatile ("movd %[inbuf], %%xmm0\n\t"
814 : "pinsrd $1, %[inbuf_tail], %%xmm0\n\t"
815 : "pshufb %[merge_shuf], %%xmm0\n\t"
816 : :
817 : : [inbuf] "m" (*inbuf),
818 16 : [inbuf_tail] "m" (inbuf[inlen - 4]),
819 : [merge_shuf] "m"
820 16 : (*crc32_merge5to7_shuf[inlen - 5])
821 : );
822 : }
823 :
824 : /* Final fold. */
825 67 : asm volatile ("pxor %%xmm1, %%xmm0\n\t"
826 : "pshufb %%xmm7, %%xmm0\n\t"
827 :
828 : /* reduce 128-bits to 96-bits */
829 : "movdqa %%xmm0, %%xmm1\n\t"
830 : "pclmulqdq $0x11, %%xmm6, %%xmm0\n\t"
831 : "pslldq $8, %%xmm1\n\t"
832 : "pxor %%xmm1, %%xmm0\n\t" /* bottom 32-bit are zero */
833 :
834 : /* reduce 96-bits to 64-bits */
835 : "pshufd $0x30, %%xmm0, %%xmm1\n\t" /* [00][x>>96][00][00] */
836 : "pshufd $0x24, %%xmm0, %%xmm0\n\t" /* [00][xx][xx][00] */
837 : "pclmulqdq $0x01, %[k5], %%xmm1\n\t" /* [00][xx][xx][00] */
838 : "pxor %%xmm1, %%xmm0\n\t" /* top and bottom 32-bit are zero */
839 :
840 : /* barrett reduction */
841 : "pshufd $0x01, %%xmm0, %%xmm1\n\t" /* [00][00][00][x>>32] */
842 : "pclmulqdq $0x01, %%xmm5, %%xmm0\n\t" /* [00][xx][xx][xx] */
843 : "psrldq $4, %%xmm0\n\t" /* [00][00][xx][xx] */
844 : "pclmulqdq $0x10, %%xmm5, %%xmm0\n\t"
845 : "pxor %%xmm1, %%xmm0\n\t"
846 :
847 : /* store CRC in input endian */
848 : "movd %%xmm0, %%eax\n\t"
849 : "bswapl %%eax\n\t"
850 : "movl %%eax, %[out]\n\t"
851 : : [out] "=m" (*pcrc)
852 : : [k5] "m" (consts->k[5 - 1])
853 : : "eax" );
854 : }
855 1000089 : }
856 :
857 : void
858 2038108 : _gcry_crc32_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen)
859 : {
860 2038108 : const struct crc32_consts_s *consts = &crc32_consts;
861 : #if defined(__x86_64__) && defined(__WIN64__)
862 : char win64tmp[2 * 16];
863 :
864 : /* XMM6-XMM7 need to be restored after use. */
865 : asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t"
866 : "movdqu %%xmm7, 1*16(%0)\n\t"
867 : :
868 : : "r" (win64tmp)
869 : : "memory");
870 : #endif
871 :
872 2038108 : if (!inlen)
873 1957 : return;
874 :
875 2036151 : if (inlen >= 16)
876 35948 : crc32_reflected_bulk(pcrc, inbuf, inlen, consts);
877 : else
878 2000203 : crc32_reflected_less_than_16(pcrc, inbuf, inlen, consts);
879 :
880 : #if defined(__x86_64__) && defined(__WIN64__)
881 : /* Restore used registers. */
882 : asm volatile("movdqu 0*16(%0), %%xmm6\n\t"
883 : "movdqu 1*16(%0), %%xmm7\n\t"
884 : :
885 : : "r" (win64tmp)
886 : : "memory");
887 : #endif
888 : }
889 :
890 : void
891 1018492 : _gcry_crc24rfc2440_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen)
892 : {
893 1018492 : const struct crc32_consts_s *consts = &crc24rfc2440_consts;
894 : #if defined(__x86_64__) && defined(__WIN64__)
895 : char win64tmp[2 * 16];
896 :
897 : /* XMM6-XMM7 need to be restored after use. */
898 : asm volatile ("movdqu %%xmm6, 0*16(%0)\n\t"
899 : "movdqu %%xmm7, 1*16(%0)\n\t"
900 : :
901 : : "r" (win64tmp)
902 : : "memory");
903 : #endif
904 :
905 1018492 : if (!inlen)
906 978 : return;
907 :
908 : /* Note: *pcrc in input endian. */
909 :
910 1017514 : if (inlen >= 16)
911 17425 : crc32_bulk(pcrc, inbuf, inlen, consts);
912 : else
913 1000089 : crc32_less_than_16(pcrc, inbuf, inlen, consts);
914 :
915 : #if defined(__x86_64__) && defined(__WIN64__)
916 : /* Restore used registers. */
917 : asm volatile("movdqu 0*16(%0), %%xmm6\n\t"
918 : "movdqu 1*16(%0), %%xmm7\n\t"
919 : :
920 : : "r" (win64tmp)
921 : : "memory");
922 : #endif
923 : }
924 :
925 : #endif /* USE_INTEL_PCLMUL */
|