Add clang target pragma for mixed C/assembly x86-64 implementations
[libgcrypt.git] / cipher / sha1-intel-shaext.c
1 /* sha1-intel-shaext.S - SHAEXT accelerated SHA-1 transform function
2  * Copyright (C) 2018 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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21
22 #include "types.h"
23
24 #if defined(HAVE_GCC_INLINE_ASM_SHAEXT) && \
25     defined(HAVE_GCC_INLINE_ASM_SSE41) && defined(USE_SHA1) && \
26     defined(ENABLE_SHAEXT_SUPPORT)
27
28 #if _GCRY_GCC_VERSION >= 40400 /* 4.4 */
29 /* Prevent compiler from issuing SSE instructions between asm blocks. */
30 #  pragma GCC target("no-sse")
31 #endif
32 #if __clang__
33 #  pragma clang attribute push (__attribute__((target("no-sse"))), apply_to = function)
34 #endif
35
36 /* Two macros to be called prior and after the use of SHA-EXT
37    instructions.  There should be no external function calls between
38    the use of these macros.  There purpose is to make sure that the
39    SSE regsiters are cleared and won't reveal any information about
40    the key or the data.  */
41 #ifdef __WIN64__
42 /* XMM6-XMM15 are callee-saved registers on WIN64. */
43 # define shaext_prepare_variable char win64tmp[2*16]
44 # define shaext_prepare_variable_size sizeof(win64tmp)
45 # define shaext_prepare()                                               \
46    do { asm volatile ("movdqu %%xmm6, (%0)\n"                           \
47                       "movdqu %%xmm7, (%1)\n"                           \
48                       :                                                 \
49                       : "r" (&win64tmp[0]), "r" (&win64tmp[16])         \
50                       : "memory");                                      \
51    } while (0)
52 # define shaext_cleanup(tmp0,tmp1)                                      \
53    do { asm volatile ("movdqu (%0), %%xmm6\n"                           \
54                       "movdqu (%1), %%xmm7\n"                           \
55                       "pxor %%xmm0, %%xmm0\n"                           \
56                       "pxor %%xmm1, %%xmm1\n"                           \
57                       "pxor %%xmm2, %%xmm2\n"                           \
58                       "pxor %%xmm3, %%xmm3\n"                           \
59                       "pxor %%xmm4, %%xmm4\n"                           \
60                       "pxor %%xmm5, %%xmm5\n"                           \
61                       "movdqa %%xmm0, (%2)\n\t"                         \
62                       "movdqa %%xmm0, (%3)\n\t"                         \
63                       :                                                 \
64                       : "r" (&win64tmp[0]), "r" (&win64tmp[16]),        \
65                         "r" (tmp0), "r" (tmp1)                          \
66                       : "memory");                                      \
67    } while (0)
68 #else
69 # define shaext_prepare_variable
70 # define shaext_prepare_variable_size 0
71 # define shaext_prepare() do { } while (0)
72 # define shaext_cleanup(tmp0,tmp1)                                      \
73    do { asm volatile ("pxor %%xmm0, %%xmm0\n"                           \
74                       "pxor %%xmm1, %%xmm1\n"                           \
75                       "pxor %%xmm2, %%xmm2\n"                           \
76                       "pxor %%xmm3, %%xmm3\n"                           \
77                       "pxor %%xmm4, %%xmm4\n"                           \
78                       "pxor %%xmm5, %%xmm5\n"                           \
79                       "pxor %%xmm6, %%xmm6\n"                           \
80                       "pxor %%xmm7, %%xmm7\n"                           \
81                       "movdqa %%xmm0, (%0)\n\t"                         \
82                       "movdqa %%xmm0, (%1)\n\t"                         \
83                       :                                                 \
84                       : "r" (tmp0), "r" (tmp1)                          \
85                       : "memory");                                      \
86    } while (0)
87 #endif
88
89 /*
90  * Transform nblks*64 bytes (nblks*16 32-bit words) at DATA.
91  */
92 unsigned int
93 _gcry_sha1_transform_intel_shaext(void *state, const unsigned char *data,
94                                   size_t nblks)
95 {
96   static const unsigned char be_mask[16] __attribute__ ((aligned (16))) =
97     { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
98   char save_buf[2 * 16 + 15];
99   char *abcd_save;
100   char *e_save;
101   shaext_prepare_variable;
102
103   if (nblks == 0)
104     return 0;
105
106   shaext_prepare ();
107
108   asm volatile ("" : "=r" (abcd_save) : "0" (save_buf) : "memory");
109   abcd_save = abcd_save + (-(uintptr_t)abcd_save & 15);
110   e_save = abcd_save + 16;
111
112   /* byteswap mask => XMM7 */
113   asm volatile ("movdqa %[mask], %%xmm7\n\t" /* Preload mask */
114                 :
115                 : [mask] "m" (*be_mask)
116                 : "memory");
117
118   /* Load state.. ABCD => XMM4, E => XMM5 */
119   asm volatile ("movd 16(%[state]), %%xmm5\n\t"
120                 "movdqu (%[state]), %%xmm4\n\t"
121                 "pslldq $12, %%xmm5\n\t"
122                 "pshufd $0x1b, %%xmm4, %%xmm4\n\t"
123                 "movdqa %%xmm5, (%[e_save])\n\t"
124                 "movdqa %%xmm4, (%[abcd_save])\n\t"
125                 :
126                 : [state] "r" (state), [abcd_save] "r" (abcd_save),
127                   [e_save] "r" (e_save)
128                 : "memory" );
129
130   /* DATA => XMM[0..4] */
131   asm volatile ("movdqu 0(%[data]), %%xmm0\n\t"
132                 "movdqu 16(%[data]), %%xmm1\n\t"
133                 "movdqu 32(%[data]), %%xmm2\n\t"
134                 "movdqu 48(%[data]), %%xmm3\n\t"
135                 "pshufb %%xmm7, %%xmm0\n\t"
136                 "pshufb %%xmm7, %%xmm1\n\t"
137                 "pshufb %%xmm7, %%xmm2\n\t"
138                 "pshufb %%xmm7, %%xmm3\n\t"
139                 :
140                 : [data] "r" (data)
141                 : "memory" );
142   data += 64;
143
144   while (1)
145     {
146       /* Round 0..3 */
147       asm volatile ("paddd %%xmm0, %%xmm5\n\t"
148                     "movdqa %%xmm4, %%xmm6\n\t" /* ABCD => E1 */
149                     "sha1rnds4 $0, %%xmm5, %%xmm4\n\t"
150                     ::: "memory" );
151
152       /* Round 4..7 */
153       asm volatile ("sha1nexte %%xmm1, %%xmm6\n\t"
154                     "movdqa %%xmm4, %%xmm5\n\t"
155                     "sha1rnds4 $0, %%xmm6, %%xmm4\n\t"
156                     "sha1msg1 %%xmm1, %%xmm0\n\t"
157                     ::: "memory" );
158
159       /* Round 8..11 */
160       asm volatile ("sha1nexte %%xmm2, %%xmm5\n\t"
161                     "movdqa %%xmm4, %%xmm6\n\t"
162                     "sha1rnds4 $0, %%xmm5, %%xmm4\n\t"
163                     "sha1msg1 %%xmm2, %%xmm1\n\t"
164                     "pxor %%xmm2, %%xmm0\n\t"
165                     ::: "memory" );
166
167 #define ROUND(imm, E0, E1, MSG0, MSG1, MSG2, MSG3) \
168       asm volatile ("sha1nexte %%"MSG0", %%"E0"\n\t" \
169                     "movdqa %%xmm4, %%"E1"\n\t" \
170                     "sha1msg2 %%"MSG0", %%"MSG1"\n\t" \
171                     "sha1rnds4 $"imm", %%"E0", %%xmm4\n\t" \
172                     "sha1msg1 %%"MSG0", %%"MSG3"\n\t" \
173                     "pxor %%"MSG0", %%"MSG2"\n\t" \
174                     ::: "memory" )
175
176       /* Rounds 12..15 to 64..67 */
177       ROUND("0", "xmm6", "xmm5", "xmm3", "xmm0", "xmm1", "xmm2");
178       ROUND("0", "xmm5", "xmm6", "xmm0", "xmm1", "xmm2", "xmm3");
179       ROUND("1", "xmm6", "xmm5", "xmm1", "xmm2", "xmm3", "xmm0");
180       ROUND("1", "xmm5", "xmm6", "xmm2", "xmm3", "xmm0", "xmm1");
181       ROUND("1", "xmm6", "xmm5", "xmm3", "xmm0", "xmm1", "xmm2");
182       ROUND("1", "xmm5", "xmm6", "xmm0", "xmm1", "xmm2", "xmm3");
183       ROUND("1", "xmm6", "xmm5", "xmm1", "xmm2", "xmm3", "xmm0");
184       ROUND("2", "xmm5", "xmm6", "xmm2", "xmm3", "xmm0", "xmm1");
185       ROUND("2", "xmm6", "xmm5", "xmm3", "xmm0", "xmm1", "xmm2");
186       ROUND("2", "xmm5", "xmm6", "xmm0", "xmm1", "xmm2", "xmm3");
187       ROUND("2", "xmm6", "xmm5", "xmm1", "xmm2", "xmm3", "xmm0");
188       ROUND("2", "xmm5", "xmm6", "xmm2", "xmm3", "xmm0", "xmm1");
189       ROUND("3", "xmm6", "xmm5", "xmm3", "xmm0", "xmm1", "xmm2");
190       ROUND("3", "xmm5", "xmm6", "xmm0", "xmm1", "xmm2", "xmm3");
191
192       if (--nblks == 0)
193         break;
194
195       /* Round 68..71 */
196       asm volatile ("movdqu 0(%[data]), %%xmm0\n\t"
197                     "sha1nexte %%xmm1, %%xmm6\n\t"
198                     "movdqa %%xmm4, %%xmm5\n\t"
199                     "sha1msg2 %%xmm1, %%xmm2\n\t"
200                     "sha1rnds4 $3, %%xmm6, %%xmm4\n\t"
201                     "pxor %%xmm1, %%xmm3\n\t"
202                     "pshufb %%xmm7, %%xmm0\n\t"
203                     :
204                     : [data] "r" (data)
205                     : "memory" );
206
207       /* Round 72..75 */
208       asm volatile ("movdqu 16(%[data]), %%xmm1\n\t"
209                     "sha1nexte %%xmm2, %%xmm5\n\t"
210                     "movdqa %%xmm4, %%xmm6\n\t"
211                     "sha1msg2 %%xmm2, %%xmm3\n\t"
212                     "sha1rnds4 $3, %%xmm5, %%xmm4\n\t"
213                     "pshufb %%xmm7, %%xmm1\n\t"
214                     :
215                     : [data] "r" (data)
216                     : "memory" );
217
218       /* Round 76..79 */
219       asm volatile ("movdqu 32(%[data]), %%xmm2\n\t"
220                     "sha1nexte %%xmm3, %%xmm6\n\t"
221                     "movdqa %%xmm4, %%xmm5\n\t"
222                     "sha1rnds4 $3, %%xmm6, %%xmm4\n\t"
223                     "pshufb %%xmm7, %%xmm2\n\t"
224                     :
225                     : [data] "r" (data)
226                     : "memory" );
227
228       /* Merge states, store current. */
229       asm volatile ("movdqu 48(%[data]), %%xmm3\n\t"
230                     "sha1nexte (%[e_save]), %%xmm5\n\t"
231                     "paddd (%[abcd_save]), %%xmm4\n\t"
232                     "pshufb %%xmm7, %%xmm3\n\t"
233                     "movdqa %%xmm5, (%[e_save])\n\t"
234                     "movdqa %%xmm4, (%[abcd_save])\n\t"
235                     :
236                     : [abcd_save] "r" (abcd_save), [e_save] "r" (e_save),
237                       [data] "r" (data)
238                     : "memory" );
239
240       data += 64;
241     }
242
243   /* Round 68..71 */
244   asm volatile ("sha1nexte %%xmm1, %%xmm6\n\t"
245                 "movdqa %%xmm4, %%xmm5\n\t"
246                 "sha1msg2 %%xmm1, %%xmm2\n\t"
247                 "sha1rnds4 $3, %%xmm6, %%xmm4\n\t"
248                 "pxor %%xmm1, %%xmm3\n\t"
249                 ::: "memory" );
250
251   /* Round 72..75 */
252   asm volatile ("sha1nexte %%xmm2, %%xmm5\n\t"
253                 "movdqa %%xmm4, %%xmm6\n\t"
254                 "sha1msg2 %%xmm2, %%xmm3\n\t"
255                 "sha1rnds4 $3, %%xmm5, %%xmm4\n\t"
256                 ::: "memory" );
257
258   /* Round 76..79 */
259   asm volatile ("sha1nexte %%xmm3, %%xmm6\n\t"
260                 "movdqa %%xmm4, %%xmm5\n\t"
261                 "sha1rnds4 $3, %%xmm6, %%xmm4\n\t"
262                 ::: "memory" );
263
264   /* Merge states. */
265   asm volatile ("sha1nexte (%[e_save]), %%xmm5\n\t"
266                 "paddd (%[abcd_save]), %%xmm4\n\t"
267                 :
268                 : [abcd_save] "r" (abcd_save), [e_save] "r" (e_save)
269                 : "memory" );
270
271   /* Save state */
272   asm volatile ("pshufd $0x1b, %%xmm4, %%xmm4\n\t"
273                 "psrldq $12, %%xmm5\n\t"
274                 "movdqu %%xmm4, (%[state])\n\t"
275                 "movd %%xmm5, 16(%[state])\n\t"
276                 :
277                 : [state] "r" (state)
278                 : "memory" );
279
280   shaext_cleanup (abcd_save, e_save);
281   return 0;
282 }
283
284 #if __clang__
285 #  pragma clang attribute pop
286 #endif
287
288 #endif /* HAVE_GCC_INLINE_ASM_SHA_EXT */