8ff08ec103af135bf565416998f1e64ff6774628
[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 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 crc32_reflected_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
137                       const struct crc32_consts_s *consts)
138 {
139   if (inlen >= 8 * 16)
140     {
141       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                       [inbuf_1] "m" (inbuf[1 * 16]),
150                       [inbuf_2] "m" (inbuf[2 * 16]),
151                       [inbuf_3] "m" (inbuf[3 * 16]),
152                       [crc] "m" (*pcrc)
153                     );
154
155       inbuf += 4 * 16;
156       inlen -= 4 * 16;
157
158       asm volatile ("movdqa %[k1k2], %%xmm4\n\t"
159                     :
160                     : [k1k2] "m" (consts->k[1 - 1])
161                     );
162
163       /* Fold by 4. */
164       while (inlen >= 4 * 16)
165         {
166           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                           [inbuf_1] "m" (inbuf[1 * 16]),
196                           [inbuf_2] "m" (inbuf[2 * 16]),
197                           [inbuf_3] "m" (inbuf[3 * 16])
198                         );
199
200           inbuf += 4 * 16;
201           inlen -= 4 * 16;
202         }
203
204       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       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       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       inbuf += 16;
249       inlen -= 16;
250     }
251
252   /* Fold by 1. */
253   if (inlen >= 16)
254     {
255       while (inlen >= 16)
256         {
257           /* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */
258           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           inbuf += 16;
269           inlen -= 16;
270         }
271     }
272
273   /* Partial fold. */
274   if (inlen)
275     {
276       /* Load last input and add padding zeros. */
277       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                     : [inbuf] "m" (*(inbuf - 16 + inlen)),
295                       [mask] "m" (crc32_partial_fold_input_mask[inlen]),
296                       [shl_shuf] "m" (crc32_refl_shuf_shift[inlen]),
297                       [shr_shuf] "m" (crc32_refl_shuf_shift[inlen + 16])
298                     );
299
300       inbuf += inlen;
301       inlen -= inlen;
302     }
303
304   /* Final fold. */
305   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 }
330
331 static inline void
332 crc32_reflected_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen,
333                               const struct crc32_consts_s *consts)
334 {
335   if (inlen < 4)
336     {
337       u32 crc = *pcrc;
338       u32 data;
339
340       asm volatile ("movdqa %[my_p], %%xmm5\n\t"
341                     :
342                     : [my_p] "m" (consts->my_p[0])
343                     );
344
345       if (inlen == 1)
346         {
347           data = inbuf[0];
348           data ^= crc;
349           data <<= 24;
350           crc >>= 8;
351         }
352       else if (inlen == 2)
353         {
354           data = ((const struct u16_unaligned_s *)inbuf)->a;
355           data ^= crc;
356           data <<= 16;
357           crc >>= 16;
358         }
359       else
360         {
361           data = ((const struct u16_unaligned_s *)inbuf)->a;
362           data |= inbuf[2] << 16;
363           data ^= crc;
364           data <<= 8;
365           crc >>= 24;
366         }
367
368       /* Barrett reduction */
369       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   else if (inlen == 4)
385     {
386       /* Barrett reduction */
387       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       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       if (inlen >= 8)
417         {
418           asm volatile ("movq %[inbuf], %%xmm0\n\t"
419                         :
420                         : [inbuf] "m" (*inbuf)
421                         );
422           if (inlen > 8)
423             {
424               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                             : [inbuf_tail] "m" (inbuf[inlen - 8]),
430                               [merge_shuf] "m"
431                                 (*crc32_merge9to15_shuf[inlen - 9])
432                             );
433             }
434         }
435       else
436         {
437           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                           [inbuf_tail] "m" (inbuf[inlen - 4]),
443                           [merge_shuf] "m"
444                             (*crc32_merge5to7_shuf[inlen - 5])
445                         );
446         }
447
448       /* Final fold. */
449       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 }
478
479 /* PCLMUL functions for non-reflected CRC32. */
480 static inline void
481 crc32_bulk (u32 *pcrc, const byte *inbuf, size_t inlen,
482             const struct crc32_consts_s *consts)
483 {
484   asm volatile ("movdqa %[bswap], %%xmm7\n\t"
485                 :
486                 : [bswap] "m" (*crc32_bswap_shuf)
487                 );
488
489   if (inlen >= 8 * 16)
490     {
491       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                       [inbuf_1] "m" (inbuf[1 * 16]),
504                       [inbuf_2] "m" (inbuf[2 * 16]),
505                       [inbuf_3] "m" (inbuf[3 * 16]),
506                       [crc] "m" (*pcrc)
507                     );
508
509       inbuf += 4 * 16;
510       inlen -= 4 * 16;
511
512       asm volatile ("movdqa %[k1k2], %%xmm4\n\t"
513                     :
514                     : [k1k2] "m" (consts->k[1 - 1])
515                     );
516
517       /* Fold by 4. */
518       while (inlen >= 4 * 16)
519         {
520           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                           [inbuf_1] "m" (inbuf[1 * 16]),
554                           [inbuf_2] "m" (inbuf[2 * 16]),
555                           [inbuf_3] "m" (inbuf[3 * 16])
556                         );
557
558           inbuf += 4 * 16;
559           inlen -= 4 * 16;
560         }
561
562       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       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       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       inbuf += 16;
608       inlen -= 16;
609     }
610
611   /* Fold by 1. */
612   if (inlen >= 16)
613     {
614       while (inlen >= 16)
615         {
616           /* Load next block to XMM2. Fold XMM0 to XMM0:XMM1. */
617           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           inbuf += 16;
629           inlen -= 16;
630         }
631     }
632
633   /* Partial fold. */
634   if (inlen)
635     {
636       /* Load last input and add padding zeros. */
637       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                     : [inbuf] "m" (*(inbuf - 16 + inlen)),
657                       [mask] "m" (crc32_partial_fold_input_mask[inlen]),
658                       [shl_shuf] "m" (crc32_refl_shuf_shift[32 - inlen]),
659                       [shr_shuf] "m" (crc32_shuf_shift[inlen + 16])
660                     );
661
662       inbuf += inlen;
663       inlen -= inlen;
664     }
665
666   /* Final fold. */
667   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 }
694
695 static inline void
696 crc32_less_than_16 (u32 *pcrc, const byte *inbuf, size_t inlen,
697                     const struct crc32_consts_s *consts)
698 {
699   if (inlen < 4)
700     {
701       u32 crc = *pcrc;
702       u32 data;
703
704       asm volatile ("movdqa %[my_p], %%xmm5\n\t"
705                     :
706                     : [my_p] "m" (consts->my_p[0])
707                     );
708
709       if (inlen == 1)
710         {
711           data = inbuf[0];
712           data ^= crc;
713           data = _gcry_bswap32(data << 24);
714           crc = _gcry_bswap32(crc >> 8);
715         }
716       else if (inlen == 2)
717         {
718           data = ((const struct u16_unaligned_s *)inbuf)->a;
719           data ^= crc;
720           data = _gcry_bswap32(data << 16);
721           crc = _gcry_bswap32(crc >> 16);
722         }
723       else
724         {
725           data = ((const struct u16_unaligned_s *)inbuf)->a;
726           data |= inbuf[2] << 16;
727           data ^= crc;
728           data = _gcry_bswap32(data << 8);
729           crc = _gcry_bswap32(crc >> 24);
730         }
731
732       /* Barrett reduction */
733       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   else if (inlen == 4)
751     {
752       /* Barrett reduction */
753       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       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                     : [bswap] "m" (*crc32_bswap_shuf)
769                     : "cc" );
770
771       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       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                     : [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       if (inlen >= 8)
793         {
794           asm volatile ("movq %[inbuf], %%xmm0\n\t"
795                         :
796                         : [inbuf] "m" (*inbuf)
797                         );
798           if (inlen > 8)
799             {
800               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                             : [inbuf_tail] "m" (inbuf[inlen - 8]),
806                               [merge_shuf] "m"
807                                 (*crc32_merge9to15_shuf[inlen - 9])
808                             );
809             }
810         }
811       else
812         {
813           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                           [inbuf_tail] "m" (inbuf[inlen - 4]),
819                           [merge_shuf] "m"
820                             (*crc32_merge5to7_shuf[inlen - 5])
821                         );
822         }
823
824       /* Final fold. */
825       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 }
856
857 void
858 _gcry_crc32_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen)
859 {
860   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   if (!inlen)
873     return;
874
875   if (inlen >= 16)
876     crc32_reflected_bulk(pcrc, inbuf, inlen, consts);
877   else
878     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 _gcry_crc24rfc2440_intel_pclmul (u32 *pcrc, const byte *inbuf, size_t inlen)
892 {
893   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   if (!inlen)
906     return;
907
908   /* Note: *pcrc in input endian. */
909
910   if (inlen >= 16)
911     crc32_bulk(pcrc, inbuf, inlen, consts);
912   else
913     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 */