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