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