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