Separate PolarSSL from PDKIM. Bug 1192
[users/heiko/exim.git] / src / src / pdkim / polarssl / bn_mul.h
1 /**
2  * \file bn_mul.h
3  *
4  *  Copyright (C) 2006-2010, Brainspark B.V.
5  *
6  *  This file is part of PolarSSL (http://www.polarssl.org)
7  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8  *
9  *  All rights reserved.
10  *
11  *  This program is free software; you can redistribute it and/or modify
12  *  it under the terms of the GNU General Public License as published by
13  *  the Free Software Foundation; either version 2 of the License, or
14  *  (at your option) any later version.
15  *
16  *  This program is distributed in the hope that it will be useful,
17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  *  GNU General Public License for more details.
20  *
21  *  You should have received a copy of the GNU General Public License along
22  *  with this program; if not, write to the Free Software Foundation, Inc.,
23  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 /*
26  *      Multiply source vector [s] with b, add result
27  *       to destination vector [d] and set carry c.
28  *
29  *      Currently supports:
30  *
31  *         . IA-32 (386+)         . AMD64 / EM64T
32  *         . IA-32 (SSE2)         . Motorola 68000
33  *         . PowerPC, 32-bit      . MicroBlaze
34  *         . PowerPC, 64-bit      . TriCore
35  *         . SPARC v8             . ARM v3+
36  *         . Alpha                . MIPS32
37  *         . C, longlong          . C, generic
38  */
39 #ifndef POLARSSL_BN_MUL_H
40 #define POLARSSL_BN_MUL_H
41
42 #include "polarssl/config.h"
43
44 #if defined(POLARSSL_HAVE_ASM)
45
46 #if defined(__GNUC__)
47 #if defined(__i386__)
48
49 #define MULADDC_INIT                \
50     asm( "                          \
51         movl   %%ebx, %0;           \
52         movl   %5, %%esi;           \
53         movl   %6, %%edi;           \
54         movl   %7, %%ecx;           \
55         movl   %8, %%ebx;           \
56         "
57
58 #define MULADDC_CORE                \
59         "                           \
60         lodsl;                      \
61         mull   %%ebx;               \
62         addl   %%ecx,   %%eax;      \
63         adcl   $0,      %%edx;      \
64         addl   (%%edi), %%eax;      \
65         adcl   $0,      %%edx;      \
66         movl   %%edx,   %%ecx;      \
67         stosl;                      \
68         "
69
70 #if defined(POLARSSL_HAVE_SSE2)
71
72 #define MULADDC_HUIT                    \
73         "                               \
74         movd     %%ecx,     %%mm1;      \
75         movd     %%ebx,     %%mm0;      \
76         movd     (%%edi),   %%mm3;      \
77         paddq    %%mm3,     %%mm1;      \
78         movd     (%%esi),   %%mm2;      \
79         pmuludq  %%mm0,     %%mm2;      \
80         movd     4(%%esi),  %%mm4;      \
81         pmuludq  %%mm0,     %%mm4;      \
82         movd     8(%%esi),  %%mm6;      \
83         pmuludq  %%mm0,     %%mm6;      \
84         movd     12(%%esi), %%mm7;      \
85         pmuludq  %%mm0,     %%mm7;      \
86         paddq    %%mm2,     %%mm1;      \
87         movd     4(%%edi),  %%mm3;      \
88         paddq    %%mm4,     %%mm3;      \
89         movd     8(%%edi),  %%mm5;      \
90         paddq    %%mm6,     %%mm5;      \
91         movd     12(%%edi), %%mm4;      \
92         paddq    %%mm4,     %%mm7;      \
93         movd     %%mm1,     (%%edi);    \
94         movd     16(%%esi), %%mm2;      \
95         pmuludq  %%mm0,     %%mm2;      \
96         psrlq    $32,       %%mm1;      \
97         movd     20(%%esi), %%mm4;      \
98         pmuludq  %%mm0,     %%mm4;      \
99         paddq    %%mm3,     %%mm1;      \
100         movd     24(%%esi), %%mm6;      \
101         pmuludq  %%mm0,     %%mm6;      \
102         movd     %%mm1,     4(%%edi);   \
103         psrlq    $32,       %%mm1;      \
104         movd     28(%%esi), %%mm3;      \
105         pmuludq  %%mm0,     %%mm3;      \
106         paddq    %%mm5,     %%mm1;      \
107         movd     16(%%edi), %%mm5;      \
108         paddq    %%mm5,     %%mm2;      \
109         movd     %%mm1,     8(%%edi);   \
110         psrlq    $32,       %%mm1;      \
111         paddq    %%mm7,     %%mm1;      \
112         movd     20(%%edi), %%mm5;      \
113         paddq    %%mm5,     %%mm4;      \
114         movd     %%mm1,     12(%%edi);  \
115         psrlq    $32,       %%mm1;      \
116         paddq    %%mm2,     %%mm1;      \
117         movd     24(%%edi), %%mm5;      \
118         paddq    %%mm5,     %%mm6;      \
119         movd     %%mm1,     16(%%edi);  \
120         psrlq    $32,       %%mm1;      \
121         paddq    %%mm4,     %%mm1;      \
122         movd     28(%%edi), %%mm5;      \
123         paddq    %%mm5,     %%mm3;      \
124         movd     %%mm1,     20(%%edi);  \
125         psrlq    $32,       %%mm1;      \
126         paddq    %%mm6,     %%mm1;      \
127         movd     %%mm1,     24(%%edi);  \
128         psrlq    $32,       %%mm1;      \
129         paddq    %%mm3,     %%mm1;      \
130         movd     %%mm1,     28(%%edi);  \
131         addl     $32,       %%edi;      \
132         addl     $32,       %%esi;      \
133         psrlq    $32,       %%mm1;      \
134         movd     %%mm1,     %%ecx;      \
135         "
136
137 #define MULADDC_STOP            \
138         "                       \
139         emms;                   \
140         movl   %4, %%ebx;       \
141         movl   %%ecx, %1;       \
142         movl   %%edi, %2;       \
143         movl   %%esi, %3;       \
144         "                       \
145         : "=m" (t), "=m" (c), "=m" (d), "=m" (s)        \
146         : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b)   \
147         : "eax", "ecx", "edx", "esi", "edi"             \
148     );
149
150 #else
151
152 #define MULADDC_STOP            \
153         "                       \
154         movl   %4, %%ebx;       \
155         movl   %%ecx, %1;       \
156         movl   %%edi, %2;       \
157         movl   %%esi, %3;       \
158         "                       \
159         : "=m" (t), "=m" (c), "=m" (d), "=m" (s)        \
160         : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b)   \
161         : "eax", "ecx", "edx", "esi", "edi"             \
162     );
163 #endif /* SSE2 */
164 #endif /* i386 */
165
166 #if defined(__amd64__) || defined (__x86_64__)
167
168 #define MULADDC_INIT                            \
169     asm( "movq   %0, %%rsi      " :: "m" (s));  \
170     asm( "movq   %0, %%rdi      " :: "m" (d));  \
171     asm( "movq   %0, %%rcx      " :: "m" (c));  \
172     asm( "movq   %0, %%rbx      " :: "m" (b));  \
173     asm( "xorq   %r8, %r8       " );
174
175 #define MULADDC_CORE                            \
176     asm( "movq  (%rsi),%rax     " );            \
177     asm( "mulq   %rbx           " );            \
178     asm( "addq   $8,   %rsi     " );            \
179     asm( "addq   %rcx, %rax     " );            \
180     asm( "movq   %r8,  %rcx     " );            \
181     asm( "adcq   $0,   %rdx     " );            \
182     asm( "nop                   " );            \
183     asm( "addq   %rax, (%rdi)   " );            \
184     asm( "adcq   %rdx, %rcx     " );            \
185     asm( "addq   $8,   %rdi     " );
186
187 #define MULADDC_STOP                            \
188     asm( "movq   %%rcx, %0      " : "=m" (c));  \
189     asm( "movq   %%rdi, %0      " : "=m" (d));  \
190     asm( "movq   %%rsi, %0      " : "=m" (s) :: \
191     "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
192
193 #endif /* AMD64 */
194
195 #if defined(__mc68020__) || defined(__mcpu32__)
196
197 #define MULADDC_INIT                            \
198     asm( "movl   %0, %%a2       " :: "m" (s));  \
199     asm( "movl   %0, %%a3       " :: "m" (d));  \
200     asm( "movl   %0, %%d3       " :: "m" (c));  \
201     asm( "movl   %0, %%d2       " :: "m" (b));  \
202     asm( "moveq  #0, %d0        " );
203
204 #define MULADDC_CORE                            \
205     asm( "movel  %a2@+, %d1     " );            \
206     asm( "mulul  %d2, %d4:%d1   " );            \
207     asm( "addl   %d3, %d1       " );            \
208     asm( "addxl  %d0, %d4       " );            \
209     asm( "moveq  #0,  %d3       " );            \
210     asm( "addl   %d1, %a3@+     " );            \
211     asm( "addxl  %d4, %d3       " );
212
213 #define MULADDC_STOP                            \
214     asm( "movl   %%d3, %0       " : "=m" (c));  \
215     asm( "movl   %%a3, %0       " : "=m" (d));  \
216     asm( "movl   %%a2, %0       " : "=m" (s) :: \
217     "d0", "d1", "d2", "d3", "d4", "a2", "a3" );
218
219 #define MULADDC_HUIT                            \
220     asm( "movel  %a2@+, %d1     " );            \
221     asm( "mulul  %d2, %d4:%d1   " );            \
222     asm( "addxl  %d3, %d1       " );            \
223     asm( "addxl  %d0, %d4       " );            \
224     asm( "addl   %d1, %a3@+     " );            \
225     asm( "movel  %a2@+, %d1     " );            \
226     asm( "mulul  %d2, %d3:%d1   " );            \
227     asm( "addxl  %d4, %d1       " );            \
228     asm( "addxl  %d0, %d3       " );            \
229     asm( "addl   %d1, %a3@+     " );            \
230     asm( "movel  %a2@+, %d1     " );            \
231     asm( "mulul  %d2, %d4:%d1   " );            \
232     asm( "addxl  %d3, %d1       " );            \
233     asm( "addxl  %d0, %d4       " );            \
234     asm( "addl   %d1, %a3@+     " );            \
235     asm( "movel  %a2@+, %d1     " );            \
236     asm( "mulul  %d2, %d3:%d1   " );            \
237     asm( "addxl  %d4, %d1       " );            \
238     asm( "addxl  %d0, %d3       " );            \
239     asm( "addl   %d1, %a3@+     " );            \
240     asm( "movel  %a2@+, %d1     " );            \
241     asm( "mulul  %d2, %d4:%d1   " );            \
242     asm( "addxl  %d3, %d1       " );            \
243     asm( "addxl  %d0, %d4       " );            \
244     asm( "addl   %d1, %a3@+     " );            \
245     asm( "movel  %a2@+, %d1     " );            \
246     asm( "mulul  %d2, %d3:%d1   " );            \
247     asm( "addxl  %d4, %d1       " );            \
248     asm( "addxl  %d0, %d3       " );            \
249     asm( "addl   %d1, %a3@+     " );            \
250     asm( "movel  %a2@+, %d1     " );            \
251     asm( "mulul  %d2, %d4:%d1   " );            \
252     asm( "addxl  %d3, %d1       " );            \
253     asm( "addxl  %d0, %d4       " );            \
254     asm( "addl   %d1, %a3@+     " );            \
255     asm( "movel  %a2@+, %d1     " );            \
256     asm( "mulul  %d2, %d3:%d1   " );            \
257     asm( "addxl  %d4, %d1       " );            \
258     asm( "addxl  %d0, %d3       " );            \
259     asm( "addl   %d1, %a3@+     " );            \
260     asm( "addxl  %d0, %d3       " );
261
262 #endif /* MC68000 */
263
264 #if defined(__powerpc__)   || defined(__ppc__)
265 #if defined(__powerpc64__) || defined(__ppc64__)
266
267 #if defined(__MACH__) && defined(__APPLE__)
268
269 #define MULADDC_INIT                            \
270     asm( "ld     r3, %0         " :: "m" (s));  \
271     asm( "ld     r4, %0         " :: "m" (d));  \
272     asm( "ld     r5, %0         " :: "m" (c));  \
273     asm( "ld     r6, %0         " :: "m" (b));  \
274     asm( "addi   r3, r3, -8     " );            \
275     asm( "addi   r4, r4, -8     " );            \
276     asm( "addic  r5, r5,  0     " );
277
278 #define MULADDC_CORE                            \
279     asm( "ldu    r7, 8(r3)      " );            \
280     asm( "mulld  r8, r7, r6     " );            \
281     asm( "mulhdu r9, r7, r6     " );            \
282     asm( "adde   r8, r8, r5     " );            \
283     asm( "ld     r7, 8(r4)      " );            \
284     asm( "addze  r5, r9         " );            \
285     asm( "addc   r8, r8, r7     " );            \
286     asm( "stdu   r8, 8(r4)      " );
287
288 #define MULADDC_STOP                            \
289     asm( "addze  r5, r5         " );            \
290     asm( "addi   r4, r4, 8      " );            \
291     asm( "addi   r3, r3, 8      " );            \
292     asm( "std    r5, %0         " : "=m" (c));  \
293     asm( "std    r4, %0         " : "=m" (d));  \
294     asm( "std    r3, %0         " : "=m" (s) :: \
295     "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
296
297 #else
298
299 #define MULADDC_INIT                            \
300     asm( "ld     %%r3, %0       " :: "m" (s));  \
301     asm( "ld     %%r4, %0       " :: "m" (d));  \
302     asm( "ld     %%r5, %0       " :: "m" (c));  \
303     asm( "ld     %%r6, %0       " :: "m" (b));  \
304     asm( "addi   %r3, %r3, -8   " );            \
305     asm( "addi   %r4, %r4, -8   " );            \
306     asm( "addic  %r5, %r5,  0   " );
307
308 #define MULADDC_CORE                            \
309     asm( "ldu    %r7, 8(%r3)    " );            \
310     asm( "mulld  %r8, %r7, %r6  " );            \
311     asm( "mulhdu %r9, %r7, %r6  " );            \
312     asm( "adde   %r8, %r8, %r5  " );            \
313     asm( "ld     %r7, 8(%r4)    " );            \
314     asm( "addze  %r5, %r9       " );            \
315     asm( "addc   %r8, %r8, %r7  " );            \
316     asm( "stdu   %r8, 8(%r4)    " );
317
318 #define MULADDC_STOP                            \
319     asm( "addze  %r5, %r5       " );            \
320     asm( "addi   %r4, %r4, 8    " );            \
321     asm( "addi   %r3, %r3, 8    " );            \
322     asm( "std    %%r5, %0       " : "=m" (c));  \
323     asm( "std    %%r4, %0       " : "=m" (d));  \
324     asm( "std    %%r3, %0       " : "=m" (s) :: \
325     "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
326
327 #endif
328
329 #else /* PPC32 */
330
331 #if defined(__MACH__) && defined(__APPLE__)
332
333 #define MULADDC_INIT                            \
334     asm( "lwz    r3, %0         " :: "m" (s));  \
335     asm( "lwz    r4, %0         " :: "m" (d));  \
336     asm( "lwz    r5, %0         " :: "m" (c));  \
337     asm( "lwz    r6, %0         " :: "m" (b));  \
338     asm( "addi   r3, r3, -4     " );            \
339     asm( "addi   r4, r4, -4     " );            \
340     asm( "addic  r5, r5,  0     " );
341
342 #define MULADDC_CORE                            \
343     asm( "lwzu   r7, 4(r3)      " );            \
344     asm( "mullw  r8, r7, r6     " );            \
345     asm( "mulhwu r9, r7, r6     " );            \
346     asm( "adde   r8, r8, r5     " );            \
347     asm( "lwz    r7, 4(r4)      " );            \
348     asm( "addze  r5, r9         " );            \
349     asm( "addc   r8, r8, r7     " );            \
350     asm( "stwu   r8, 4(r4)      " );
351
352 #define MULADDC_STOP                            \
353     asm( "addze  r5, r5         " );            \
354     asm( "addi   r4, r4, 4      " );            \
355     asm( "addi   r3, r3, 4      " );            \
356     asm( "stw    r5, %0         " : "=m" (c));  \
357     asm( "stw    r4, %0         " : "=m" (d));  \
358     asm( "stw    r3, %0         " : "=m" (s) :: \
359     "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
360
361 #else
362
363 #define MULADDC_INIT                            \
364     asm( "lwz    %%r3, %0       " :: "m" (s));  \
365     asm( "lwz    %%r4, %0       " :: "m" (d));  \
366     asm( "lwz    %%r5, %0       " :: "m" (c));  \
367     asm( "lwz    %%r6, %0       " :: "m" (b));  \
368     asm( "addi   %r3, %r3, -4   " );            \
369     asm( "addi   %r4, %r4, -4   " );            \
370     asm( "addic  %r5, %r5,  0   " );
371
372 #define MULADDC_CORE                            \
373     asm( "lwzu   %r7, 4(%r3)    " );            \
374     asm( "mullw  %r8, %r7, %r6  " );            \
375     asm( "mulhwu %r9, %r7, %r6  " );            \
376     asm( "adde   %r8, %r8, %r5  " );            \
377     asm( "lwz    %r7, 4(%r4)    " );            \
378     asm( "addze  %r5, %r9       " );            \
379     asm( "addc   %r8, %r8, %r7  " );            \
380     asm( "stwu   %r8, 4(%r4)    " );
381
382 #define MULADDC_STOP                            \
383     asm( "addze  %r5, %r5       " );            \
384     asm( "addi   %r4, %r4, 4    " );            \
385     asm( "addi   %r3, %r3, 4    " );            \
386     asm( "stw    %%r5, %0       " : "=m" (c));  \
387     asm( "stw    %%r4, %0       " : "=m" (d));  \
388     asm( "stw    %%r3, %0       " : "=m" (s) :: \
389     "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
390
391 #endif
392
393 #endif /* PPC32 */
394 #endif /* PPC64 */
395
396 #if defined(__sparc__)
397
398 #define MULADDC_INIT                            \
399     asm( "ld     %0, %%o0       " :: "m" (s));  \
400     asm( "ld     %0, %%o1       " :: "m" (d));  \
401     asm( "ld     %0, %%o2       " :: "m" (c));  \
402     asm( "ld     %0, %%o3       " :: "m" (b));
403
404 #define MULADDC_CORE                            \
405     asm( "ld    [%o0], %o4      " );            \
406     asm( "inc      4,  %o0      " );            \
407     asm( "ld    [%o1], %o5      " );            \
408     asm( "umul   %o3,  %o4, %o4 " );            \
409     asm( "addcc  %o4,  %o2, %o4 " );            \
410     asm( "rd      %y,  %g1      " );            \
411     asm( "addx   %g1,    0, %g1 " );            \
412     asm( "addcc  %o4,  %o5, %o4 " );            \
413     asm( "st     %o4, [%o1]     " );            \
414     asm( "addx   %g1,    0, %o2 " );            \
415     asm( "inc      4,  %o1      " );
416
417 #define MULADDC_STOP                            \
418     asm( "st     %%o2, %0       " : "=m" (c));  \
419     asm( "st     %%o1, %0       " : "=m" (d));  \
420     asm( "st     %%o0, %0       " : "=m" (s) :: \
421     "g1", "o0", "o1", "o2", "o3", "o4", "o5" );
422
423 #endif /* SPARCv8 */
424
425 #if defined(__microblaze__) || defined(microblaze)
426
427 #define MULADDC_INIT                            \
428     asm( "lwi   r3,   %0        " :: "m" (s));  \
429     asm( "lwi   r4,   %0        " :: "m" (d));  \
430     asm( "lwi   r5,   %0        " :: "m" (c));  \
431     asm( "lwi   r6,   %0        " :: "m" (b));  \
432     asm( "andi  r7,   r6, 0xffff" );            \
433     asm( "bsrli r6,   r6, 16    " );
434
435 #define MULADDC_CORE                            \
436     asm( "lhui  r8,   r3,   0   " );            \
437     asm( "addi  r3,   r3,   2   " );            \
438     asm( "lhui  r9,   r3,   0   " );            \
439     asm( "addi  r3,   r3,   2   " );            \
440     asm( "mul   r10,  r9,  r6   " );            \
441     asm( "mul   r11,  r8,  r7   " );            \
442     asm( "mul   r12,  r9,  r7   " );            \
443     asm( "mul   r13,  r8,  r6   " );            \
444     asm( "bsrli  r8, r10,  16   " );            \
445     asm( "bsrli  r9, r11,  16   " );            \
446     asm( "add   r13, r13,  r8   " );            \
447     asm( "add   r13, r13,  r9   " );            \
448     asm( "bslli r10, r10,  16   " );            \
449     asm( "bslli r11, r11,  16   " );            \
450     asm( "add   r12, r12, r10   " );            \
451     asm( "addc  r13, r13,  r0   " );            \
452     asm( "add   r12, r12, r11   " );            \
453     asm( "addc  r13, r13,  r0   " );            \
454     asm( "lwi   r10,  r4,   0   " );            \
455     asm( "add   r12, r12, r10   " );            \
456     asm( "addc  r13, r13,  r0   " );            \
457     asm( "add   r12, r12,  r5   " );            \
458     asm( "addc   r5, r13,  r0   " );            \
459     asm( "swi   r12,  r4,   0   " );            \
460     asm( "addi   r4,  r4,   4   " );
461
462 #define MULADDC_STOP                            \
463     asm( "swi   r5,   %0        " : "=m" (c));  \
464     asm( "swi   r4,   %0        " : "=m" (d));  \
465     asm( "swi   r3,   %0        " : "=m" (s) :: \
466      "r3", "r4" , "r5" , "r6" , "r7" , "r8" ,   \
467      "r9", "r10", "r11", "r12", "r13" );
468
469 #endif /* MicroBlaze */
470
471 #if defined(__tricore__)
472
473 #define MULADDC_INIT                            \
474     asm( "ld.a   %%a2, %0       " :: "m" (s));  \
475     asm( "ld.a   %%a3, %0       " :: "m" (d));  \
476     asm( "ld.w   %%d4, %0       " :: "m" (c));  \
477     asm( "ld.w   %%d1, %0       " :: "m" (b));  \
478     asm( "xor    %d5, %d5       " );
479
480 #define MULADDC_CORE                            \
481     asm( "ld.w   %d0,   [%a2+]      " );        \
482     asm( "madd.u %e2, %e4, %d0, %d1 " );        \
483     asm( "ld.w   %d0,   [%a3]       " );        \
484     asm( "addx   %d2,    %d2,  %d0  " );        \
485     asm( "addc   %d3,    %d3,    0  " );        \
486     asm( "mov    %d4,    %d3        " );        \
487     asm( "st.w  [%a3+],  %d2        " );
488
489 #define MULADDC_STOP                            \
490     asm( "st.w   %0, %%d4       " : "=m" (c));  \
491     asm( "st.a   %0, %%a3       " : "=m" (d));  \
492     asm( "st.a   %0, %%a2       " : "=m" (s) :: \
493     "d0", "d1", "e2", "d4", "a2", "a3" );
494
495 #endif /* TriCore */
496
497 #if defined(__arm__)
498
499 #define MULADDC_INIT                            \
500     asm( "ldr    r0, %0         " :: "m" (s));  \
501     asm( "ldr    r1, %0         " :: "m" (d));  \
502     asm( "ldr    r2, %0         " :: "m" (c));  \
503     asm( "ldr    r3, %0         " :: "m" (b));
504
505 #define MULADDC_CORE                            \
506     asm( "ldr    r4, [r0], #4   " );            \
507     asm( "mov    r5, #0         " );            \
508     asm( "ldr    r6, [r1]       " );            \
509     asm( "umlal  r2, r5, r3, r4 " );            \
510     asm( "adds   r7, r6, r2     " );            \
511     asm( "adc    r2, r5, #0     " );            \
512     asm( "str    r7, [r1], #4   " );
513
514 #define MULADDC_STOP                            \
515     asm( "str    r2, %0         " : "=m" (c));  \
516     asm( "str    r1, %0         " : "=m" (d));  \
517     asm( "str    r0, %0         " : "=m" (s) :: \
518     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" );
519
520 #endif /* ARMv3 */
521
522 #if defined(__alpha__)
523
524 #define MULADDC_INIT                            \
525     asm( "ldq    $1, %0         " :: "m" (s));  \
526     asm( "ldq    $2, %0         " :: "m" (d));  \
527     asm( "ldq    $3, %0         " :: "m" (c));  \
528     asm( "ldq    $4, %0         " :: "m" (b));
529
530 #define MULADDC_CORE                            \
531     asm( "ldq    $6,  0($1)     " );            \
532     asm( "addq   $1,  8, $1     " );            \
533     asm( "mulq   $6, $4, $7     " );            \
534     asm( "umulh  $6, $4, $6     " );            \
535     asm( "addq   $7, $3, $7     " );            \
536     asm( "cmpult $7, $3, $3     " );            \
537     asm( "ldq    $5,  0($2)     " );            \
538     asm( "addq   $7, $5, $7     " );            \
539     asm( "cmpult $7, $5, $5     " );            \
540     asm( "stq    $7,  0($2)     " );            \
541     asm( "addq   $2,  8, $2     " );            \
542     asm( "addq   $6, $3, $3     " );            \
543     asm( "addq   $5, $3, $3     " );
544
545 #define MULADDC_STOP                            \
546     asm( "stq    $3, %0         " : "=m" (c));  \
547     asm( "stq    $2, %0         " : "=m" (d));  \
548     asm( "stq    $1, %0         " : "=m" (s) :: \
549     "$1", "$2", "$3", "$4", "$5", "$6", "$7" );
550
551 #endif /* Alpha */
552
553 #if defined(__mips__)
554
555 #define MULADDC_INIT                            \
556     asm( "lw     $10, %0        " :: "m" (s));  \
557     asm( "lw     $11, %0        " :: "m" (d));  \
558     asm( "lw     $12, %0        " :: "m" (c));  \
559     asm( "lw     $13, %0        " :: "m" (b));
560
561 #define MULADDC_CORE                            \
562     asm( "lw     $14, 0($10)    " );            \
563     asm( "multu  $13, $14       " );            \
564     asm( "addi   $10, $10, 4    " );            \
565     asm( "mflo   $14            " );            \
566     asm( "mfhi   $9             " );            \
567     asm( "addu   $14, $12, $14  " );            \
568     asm( "lw     $15, 0($11)    " );            \
569     asm( "sltu   $12, $14, $12  " );            \
570     asm( "addu   $15, $14, $15  " );            \
571     asm( "sltu   $14, $15, $14  " );            \
572     asm( "addu   $12, $12, $9   " );            \
573     asm( "sw     $15, 0($11)    " );            \
574     asm( "addu   $12, $12, $14  " );            \
575     asm( "addi   $11, $11, 4    " );
576
577 #define MULADDC_STOP                            \
578     asm( "sw     $12, %0        " : "=m" (c));  \
579     asm( "sw     $11, %0        " : "=m" (d));  \
580     asm( "sw     $10, %0        " : "=m" (s) :: \
581     "$9", "$10", "$11", "$12", "$13", "$14", "$15" );
582
583 #endif /* MIPS */
584 #endif /* GNUC */
585
586 #if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
587
588 #define MULADDC_INIT                            \
589     __asm   mov     esi, s                      \
590     __asm   mov     edi, d                      \
591     __asm   mov     ecx, c                      \
592     __asm   mov     ebx, b
593
594 #define MULADDC_CORE                            \
595     __asm   lodsd                               \
596     __asm   mul     ebx                         \
597     __asm   add     eax, ecx                    \
598     __asm   adc     edx, 0                      \
599     __asm   add     eax, [edi]                  \
600     __asm   adc     edx, 0                      \
601     __asm   mov     ecx, edx                    \
602     __asm   stosd
603
604 #if defined(POLARSSL_HAVE_SSE2)
605
606 #define EMIT __asm _emit
607
608 #define MULADDC_HUIT                            \
609     EMIT 0x0F  EMIT 0x6E  EMIT 0xC9             \
610     EMIT 0x0F  EMIT 0x6E  EMIT 0xC3             \
611     EMIT 0x0F  EMIT 0x6E  EMIT 0x1F             \
612     EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
613     EMIT 0x0F  EMIT 0x6E  EMIT 0x16             \
614     EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
615     EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x04  \
616     EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
617     EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x08  \
618     EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
619     EMIT 0x0F  EMIT 0x6E  EMIT 0x7E  EMIT 0x0C  \
620     EMIT 0x0F  EMIT 0xF4  EMIT 0xF8             \
621     EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
622     EMIT 0x0F  EMIT 0x6E  EMIT 0x5F  EMIT 0x04  \
623     EMIT 0x0F  EMIT 0xD4  EMIT 0xDC             \
624     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x08  \
625     EMIT 0x0F  EMIT 0xD4  EMIT 0xEE             \
626     EMIT 0x0F  EMIT 0x6E  EMIT 0x67  EMIT 0x0C  \
627     EMIT 0x0F  EMIT 0xD4  EMIT 0xFC             \
628     EMIT 0x0F  EMIT 0x7E  EMIT 0x0F             \
629     EMIT 0x0F  EMIT 0x6E  EMIT 0x56  EMIT 0x10  \
630     EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
631     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
632     EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x14  \
633     EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
634     EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
635     EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x18  \
636     EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
637     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x04  \
638     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
639     EMIT 0x0F  EMIT 0x6E  EMIT 0x5E  EMIT 0x1C  \
640     EMIT 0x0F  EMIT 0xF4  EMIT 0xD8             \
641     EMIT 0x0F  EMIT 0xD4  EMIT 0xCD             \
642     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x10  \
643     EMIT 0x0F  EMIT 0xD4  EMIT 0xD5             \
644     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x08  \
645     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
646     EMIT 0x0F  EMIT 0xD4  EMIT 0xCF             \
647     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x14  \
648     EMIT 0x0F  EMIT 0xD4  EMIT 0xE5             \
649     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x0C  \
650     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
651     EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
652     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x18  \
653     EMIT 0x0F  EMIT 0xD4  EMIT 0xF5             \
654     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x10  \
655     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
656     EMIT 0x0F  EMIT 0xD4  EMIT 0xCC             \
657     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x1C  \
658     EMIT 0x0F  EMIT 0xD4  EMIT 0xDD             \
659     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x14  \
660     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
661     EMIT 0x0F  EMIT 0xD4  EMIT 0xCE             \
662     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x18  \
663     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
664     EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
665     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x1C  \
666     EMIT 0x83  EMIT 0xC7  EMIT 0x20             \
667     EMIT 0x83  EMIT 0xC6  EMIT 0x20             \
668     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
669     EMIT 0x0F  EMIT 0x7E  EMIT 0xC9
670
671 #define MULADDC_STOP                            \
672     EMIT 0x0F  EMIT 0x77                        \
673     __asm   mov     c, ecx                      \
674     __asm   mov     d, edi                      \
675     __asm   mov     s, esi                      \
676
677 #else
678
679 #define MULADDC_STOP                            \
680     __asm   mov     c, ecx                      \
681     __asm   mov     d, edi                      \
682     __asm   mov     s, esi                      \
683
684 #endif /* SSE2 */
685 #endif /* MSVC */
686
687 #endif /* POLARSSL_HAVE_ASM */
688
689 #if !defined(MULADDC_CORE)
690 #if defined(POLARSSL_HAVE_LONGLONG)
691
692 #define MULADDC_INIT                    \
693 {                                       \
694     t_dbl r;                            \
695     t_int r0, r1;
696
697 #define MULADDC_CORE                    \
698     r   = *(s++) * (t_dbl) b;           \
699     r0  = r;                            \
700     r1  = r >> biL;                     \
701     r0 += c;  r1 += (r0 <  c);          \
702     r0 += *d; r1 += (r0 < *d);          \
703     c = r1; *(d++) = r0;
704
705 #define MULADDC_STOP                    \
706 }
707
708 #else
709 #define MULADDC_INIT                    \
710 {                                       \
711     t_int s0, s1, b0, b1;               \
712     t_int r0, r1, rx, ry;               \
713     b0 = ( b << biH ) >> biH;           \
714     b1 = ( b >> biH );
715
716 #define MULADDC_CORE                    \
717     s0 = ( *s << biH ) >> biH;          \
718     s1 = ( *s >> biH ); s++;            \
719     rx = s0 * b1; r0 = s0 * b0;         \
720     ry = s1 * b0; r1 = s1 * b1;         \
721     r1 += ( rx >> biH );                \
722     r1 += ( ry >> biH );                \
723     rx <<= biH; ry <<= biH;             \
724     r0 += rx; r1 += (r0 < rx);          \
725     r0 += ry; r1 += (r0 < ry);          \
726     r0 +=  c; r1 += (r0 <  c);          \
727     r0 += *d; r1 += (r0 < *d);          \
728     c = r1; *(d++) = r0;
729
730 #define MULADDC_STOP                    \
731 }
732
733 #endif /* C (generic)  */
734 #endif /* C (longlong) */
735
736 #endif /* bn_mul.h */
737 /**
738  * \file bn_mul.h
739  *
740  *  Copyright (C) 2006-2010, Brainspark B.V.
741  *
742  *  This file is part of PolarSSL (http://www.polarssl.org)
743  *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
744  *
745  *  All rights reserved.
746  *
747  *  This program is free software; you can redistribute it and/or modify
748  *  it under the terms of the GNU General Public License as published by
749  *  the Free Software Foundation; either version 2 of the License, or
750  *  (at your option) any later version.
751  *
752  *  This program is distributed in the hope that it will be useful,
753  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
754  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
755  *  GNU General Public License for more details.
756  *
757  *  You should have received a copy of the GNU General Public License along
758  *  with this program; if not, write to the Free Software Foundation, Inc.,
759  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
760  */
761 /*
762  *      Multiply source vector [s] with b, add result
763  *       to destination vector [d] and set carry c.
764  *
765  *      Currently supports:
766  *
767  *         . IA-32 (386+)         . AMD64 / EM64T
768  *         . IA-32 (SSE2)         . Motorola 68000
769  *         . PowerPC, 32-bit      . MicroBlaze
770  *         . PowerPC, 64-bit      . TriCore
771  *         . SPARC v8             . ARM v3+
772  *         . Alpha                . MIPS32
773  *         . C, longlong          . C, generic
774  */
775 #ifndef POLARSSL_BN_MUL_H
776 #define POLARSSL_BN_MUL_H
777
778 #include "polarssl/config.h"
779
780 #if defined(POLARSSL_HAVE_ASM)
781
782 #if defined(__GNUC__)
783 #if defined(__i386__)
784
785 #define MULADDC_INIT                \
786     asm( "                          \
787         movl   %%ebx, %0;           \
788         movl   %5, %%esi;           \
789         movl   %6, %%edi;           \
790         movl   %7, %%ecx;           \
791         movl   %8, %%ebx;           \
792         "
793
794 #define MULADDC_CORE                \
795         "                           \
796         lodsl;                      \
797         mull   %%ebx;               \
798         addl   %%ecx,   %%eax;      \
799         adcl   $0,      %%edx;      \
800         addl   (%%edi), %%eax;      \
801         adcl   $0,      %%edx;      \
802         movl   %%edx,   %%ecx;      \
803         stosl;                      \
804         "
805
806 #if defined(POLARSSL_HAVE_SSE2)
807
808 #define MULADDC_HUIT                    \
809         "                               \
810         movd     %%ecx,     %%mm1;      \
811         movd     %%ebx,     %%mm0;      \
812         movd     (%%edi),   %%mm3;      \
813         paddq    %%mm3,     %%mm1;      \
814         movd     (%%esi),   %%mm2;      \
815         pmuludq  %%mm0,     %%mm2;      \
816         movd     4(%%esi),  %%mm4;      \
817         pmuludq  %%mm0,     %%mm4;      \
818         movd     8(%%esi),  %%mm6;      \
819         pmuludq  %%mm0,     %%mm6;      \
820         movd     12(%%esi), %%mm7;      \
821         pmuludq  %%mm0,     %%mm7;      \
822         paddq    %%mm2,     %%mm1;      \
823         movd     4(%%edi),  %%mm3;      \
824         paddq    %%mm4,     %%mm3;      \
825         movd     8(%%edi),  %%mm5;      \
826         paddq    %%mm6,     %%mm5;      \
827         movd     12(%%edi), %%mm4;      \
828         paddq    %%mm4,     %%mm7;      \
829         movd     %%mm1,     (%%edi);    \
830         movd     16(%%esi), %%mm2;      \
831         pmuludq  %%mm0,     %%mm2;      \
832         psrlq    $32,       %%mm1;      \
833         movd     20(%%esi), %%mm4;      \
834         pmuludq  %%mm0,     %%mm4;      \
835         paddq    %%mm3,     %%mm1;      \
836         movd     24(%%esi), %%mm6;      \
837         pmuludq  %%mm0,     %%mm6;      \
838         movd     %%mm1,     4(%%edi);   \
839         psrlq    $32,       %%mm1;      \
840         movd     28(%%esi), %%mm3;      \
841         pmuludq  %%mm0,     %%mm3;      \
842         paddq    %%mm5,     %%mm1;      \
843         movd     16(%%edi), %%mm5;      \
844         paddq    %%mm5,     %%mm2;      \
845         movd     %%mm1,     8(%%edi);   \
846         psrlq    $32,       %%mm1;      \
847         paddq    %%mm7,     %%mm1;      \
848         movd     20(%%edi), %%mm5;      \
849         paddq    %%mm5,     %%mm4;      \
850         movd     %%mm1,     12(%%edi);  \
851         psrlq    $32,       %%mm1;      \
852         paddq    %%mm2,     %%mm1;      \
853         movd     24(%%edi), %%mm5;      \
854         paddq    %%mm5,     %%mm6;      \
855         movd     %%mm1,     16(%%edi);  \
856         psrlq    $32,       %%mm1;      \
857         paddq    %%mm4,     %%mm1;      \
858         movd     28(%%edi), %%mm5;      \
859         paddq    %%mm5,     %%mm3;      \
860         movd     %%mm1,     20(%%edi);  \
861         psrlq    $32,       %%mm1;      \
862         paddq    %%mm6,     %%mm1;      \
863         movd     %%mm1,     24(%%edi);  \
864         psrlq    $32,       %%mm1;      \
865         paddq    %%mm3,     %%mm1;      \
866         movd     %%mm1,     28(%%edi);  \
867         addl     $32,       %%edi;      \
868         addl     $32,       %%esi;      \
869         psrlq    $32,       %%mm1;      \
870         movd     %%mm1,     %%ecx;      \
871         "
872
873 #define MULADDC_STOP            \
874         "                       \
875         emms;                   \
876         movl   %4, %%ebx;       \
877         movl   %%ecx, %1;       \
878         movl   %%edi, %2;       \
879         movl   %%esi, %3;       \
880         "                       \
881         : "=m" (t), "=m" (c), "=m" (d), "=m" (s)        \
882         : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b)   \
883         : "eax", "ecx", "edx", "esi", "edi"             \
884     );
885
886 #else
887
888 #define MULADDC_STOP            \
889         "                       \
890         movl   %4, %%ebx;       \
891         movl   %%ecx, %1;       \
892         movl   %%edi, %2;       \
893         movl   %%esi, %3;       \
894         "                       \
895         : "=m" (t), "=m" (c), "=m" (d), "=m" (s)        \
896         : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b)   \
897         : "eax", "ecx", "edx", "esi", "edi"             \
898     );
899 #endif /* SSE2 */
900 #endif /* i386 */
901
902 #if defined(__amd64__) || defined (__x86_64__)
903
904 #define MULADDC_INIT                            \
905     asm( "movq   %0, %%rsi      " :: "m" (s));  \
906     asm( "movq   %0, %%rdi      " :: "m" (d));  \
907     asm( "movq   %0, %%rcx      " :: "m" (c));  \
908     asm( "movq   %0, %%rbx      " :: "m" (b));  \
909     asm( "xorq   %r8, %r8       " );
910
911 #define MULADDC_CORE                            \
912     asm( "movq  (%rsi),%rax     " );            \
913     asm( "mulq   %rbx           " );            \
914     asm( "addq   $8,   %rsi     " );            \
915     asm( "addq   %rcx, %rax     " );            \
916     asm( "movq   %r8,  %rcx     " );            \
917     asm( "adcq   $0,   %rdx     " );            \
918     asm( "nop                   " );            \
919     asm( "addq   %rax, (%rdi)   " );            \
920     asm( "adcq   %rdx, %rcx     " );            \
921     asm( "addq   $8,   %rdi     " );
922
923 #define MULADDC_STOP                            \
924     asm( "movq   %%rcx, %0      " : "=m" (c));  \
925     asm( "movq   %%rdi, %0      " : "=m" (d));  \
926     asm( "movq   %%rsi, %0      " : "=m" (s) :: \
927     "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" );
928
929 #endif /* AMD64 */
930
931 #if defined(__mc68020__) || defined(__mcpu32__)
932
933 #define MULADDC_INIT                            \
934     asm( "movl   %0, %%a2       " :: "m" (s));  \
935     asm( "movl   %0, %%a3       " :: "m" (d));  \
936     asm( "movl   %0, %%d3       " :: "m" (c));  \
937     asm( "movl   %0, %%d2       " :: "m" (b));  \
938     asm( "moveq  #0, %d0        " );
939
940 #define MULADDC_CORE                            \
941     asm( "movel  %a2@+, %d1     " );            \
942     asm( "mulul  %d2, %d4:%d1   " );            \
943     asm( "addl   %d3, %d1       " );            \
944     asm( "addxl  %d0, %d4       " );            \
945     asm( "moveq  #0,  %d3       " );            \
946     asm( "addl   %d1, %a3@+     " );            \
947     asm( "addxl  %d4, %d3       " );
948
949 #define MULADDC_STOP                            \
950     asm( "movl   %%d3, %0       " : "=m" (c));  \
951     asm( "movl   %%a3, %0       " : "=m" (d));  \
952     asm( "movl   %%a2, %0       " : "=m" (s) :: \
953     "d0", "d1", "d2", "d3", "d4", "a2", "a3" );
954
955 #define MULADDC_HUIT                            \
956     asm( "movel  %a2@+, %d1     " );            \
957     asm( "mulul  %d2, %d4:%d1   " );            \
958     asm( "addxl  %d3, %d1       " );            \
959     asm( "addxl  %d0, %d4       " );            \
960     asm( "addl   %d1, %a3@+     " );            \
961     asm( "movel  %a2@+, %d1     " );            \
962     asm( "mulul  %d2, %d3:%d1   " );            \
963     asm( "addxl  %d4, %d1       " );            \
964     asm( "addxl  %d0, %d3       " );            \
965     asm( "addl   %d1, %a3@+     " );            \
966     asm( "movel  %a2@+, %d1     " );            \
967     asm( "mulul  %d2, %d4:%d1   " );            \
968     asm( "addxl  %d3, %d1       " );            \
969     asm( "addxl  %d0, %d4       " );            \
970     asm( "addl   %d1, %a3@+     " );            \
971     asm( "movel  %a2@+, %d1     " );            \
972     asm( "mulul  %d2, %d3:%d1   " );            \
973     asm( "addxl  %d4, %d1       " );            \
974     asm( "addxl  %d0, %d3       " );            \
975     asm( "addl   %d1, %a3@+     " );            \
976     asm( "movel  %a2@+, %d1     " );            \
977     asm( "mulul  %d2, %d4:%d1   " );            \
978     asm( "addxl  %d3, %d1       " );            \
979     asm( "addxl  %d0, %d4       " );            \
980     asm( "addl   %d1, %a3@+     " );            \
981     asm( "movel  %a2@+, %d1     " );            \
982     asm( "mulul  %d2, %d3:%d1   " );            \
983     asm( "addxl  %d4, %d1       " );            \
984     asm( "addxl  %d0, %d3       " );            \
985     asm( "addl   %d1, %a3@+     " );            \
986     asm( "movel  %a2@+, %d1     " );            \
987     asm( "mulul  %d2, %d4:%d1   " );            \
988     asm( "addxl  %d3, %d1       " );            \
989     asm( "addxl  %d0, %d4       " );            \
990     asm( "addl   %d1, %a3@+     " );            \
991     asm( "movel  %a2@+, %d1     " );            \
992     asm( "mulul  %d2, %d3:%d1   " );            \
993     asm( "addxl  %d4, %d1       " );            \
994     asm( "addxl  %d0, %d3       " );            \
995     asm( "addl   %d1, %a3@+     " );            \
996     asm( "addxl  %d0, %d3       " );
997
998 #endif /* MC68000 */
999
1000 #if defined(__powerpc__)   || defined(__ppc__)
1001 #if defined(__powerpc64__) || defined(__ppc64__)
1002
1003 #if defined(__MACH__) && defined(__APPLE__)
1004
1005 #define MULADDC_INIT                            \
1006     asm( "ld     r3, %0         " :: "m" (s));  \
1007     asm( "ld     r4, %0         " :: "m" (d));  \
1008     asm( "ld     r5, %0         " :: "m" (c));  \
1009     asm( "ld     r6, %0         " :: "m" (b));  \
1010     asm( "addi   r3, r3, -8     " );            \
1011     asm( "addi   r4, r4, -8     " );            \
1012     asm( "addic  r5, r5,  0     " );
1013
1014 #define MULADDC_CORE                            \
1015     asm( "ldu    r7, 8(r3)      " );            \
1016     asm( "mulld  r8, r7, r6     " );            \
1017     asm( "mulhdu r9, r7, r6     " );            \
1018     asm( "adde   r8, r8, r5     " );            \
1019     asm( "ld     r7, 8(r4)      " );            \
1020     asm( "addze  r5, r9         " );            \
1021     asm( "addc   r8, r8, r7     " );            \
1022     asm( "stdu   r8, 8(r4)      " );
1023
1024 #define MULADDC_STOP                            \
1025     asm( "addze  r5, r5         " );            \
1026     asm( "addi   r4, r4, 8      " );            \
1027     asm( "addi   r3, r3, 8      " );            \
1028     asm( "std    r5, %0         " : "=m" (c));  \
1029     asm( "std    r4, %0         " : "=m" (d));  \
1030     asm( "std    r3, %0         " : "=m" (s) :: \
1031     "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
1032
1033 #else
1034
1035 #define MULADDC_INIT                            \
1036     asm( "ld     %%r3, %0       " :: "m" (s));  \
1037     asm( "ld     %%r4, %0       " :: "m" (d));  \
1038     asm( "ld     %%r5, %0       " :: "m" (c));  \
1039     asm( "ld     %%r6, %0       " :: "m" (b));  \
1040     asm( "addi   %r3, %r3, -8   " );            \
1041     asm( "addi   %r4, %r4, -8   " );            \
1042     asm( "addic  %r5, %r5,  0   " );
1043
1044 #define MULADDC_CORE                            \
1045     asm( "ldu    %r7, 8(%r3)    " );            \
1046     asm( "mulld  %r8, %r7, %r6  " );            \
1047     asm( "mulhdu %r9, %r7, %r6  " );            \
1048     asm( "adde   %r8, %r8, %r5  " );            \
1049     asm( "ld     %r7, 8(%r4)    " );            \
1050     asm( "addze  %r5, %r9       " );            \
1051     asm( "addc   %r8, %r8, %r7  " );            \
1052     asm( "stdu   %r8, 8(%r4)    " );
1053
1054 #define MULADDC_STOP                            \
1055     asm( "addze  %r5, %r5       " );            \
1056     asm( "addi   %r4, %r4, 8    " );            \
1057     asm( "addi   %r3, %r3, 8    " );            \
1058     asm( "std    %%r5, %0       " : "=m" (c));  \
1059     asm( "std    %%r4, %0       " : "=m" (d));  \
1060     asm( "std    %%r3, %0       " : "=m" (s) :: \
1061     "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
1062
1063 #endif
1064
1065 #else /* PPC32 */
1066
1067 #if defined(__MACH__) && defined(__APPLE__)
1068
1069 #define MULADDC_INIT                            \
1070     asm( "lwz    r3, %0         " :: "m" (s));  \
1071     asm( "lwz    r4, %0         " :: "m" (d));  \
1072     asm( "lwz    r5, %0         " :: "m" (c));  \
1073     asm( "lwz    r6, %0         " :: "m" (b));  \
1074     asm( "addi   r3, r3, -4     " );            \
1075     asm( "addi   r4, r4, -4     " );            \
1076     asm( "addic  r5, r5,  0     " );
1077
1078 #define MULADDC_CORE                            \
1079     asm( "lwzu   r7, 4(r3)      " );            \
1080     asm( "mullw  r8, r7, r6     " );            \
1081     asm( "mulhwu r9, r7, r6     " );            \
1082     asm( "adde   r8, r8, r5     " );            \
1083     asm( "lwz    r7, 4(r4)      " );            \
1084     asm( "addze  r5, r9         " );            \
1085     asm( "addc   r8, r8, r7     " );            \
1086     asm( "stwu   r8, 4(r4)      " );
1087
1088 #define MULADDC_STOP                            \
1089     asm( "addze  r5, r5         " );            \
1090     asm( "addi   r4, r4, 4      " );            \
1091     asm( "addi   r3, r3, 4      " );            \
1092     asm( "stw    r5, %0         " : "=m" (c));  \
1093     asm( "stw    r4, %0         " : "=m" (d));  \
1094     asm( "stw    r3, %0         " : "=m" (s) :: \
1095     "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
1096
1097 #else
1098
1099 #define MULADDC_INIT                            \
1100     asm( "lwz    %%r3, %0       " :: "m" (s));  \
1101     asm( "lwz    %%r4, %0       " :: "m" (d));  \
1102     asm( "lwz    %%r5, %0       " :: "m" (c));  \
1103     asm( "lwz    %%r6, %0       " :: "m" (b));  \
1104     asm( "addi   %r3, %r3, -4   " );            \
1105     asm( "addi   %r4, %r4, -4   " );            \
1106     asm( "addic  %r5, %r5,  0   " );
1107
1108 #define MULADDC_CORE                            \
1109     asm( "lwzu   %r7, 4(%r3)    " );            \
1110     asm( "mullw  %r8, %r7, %r6  " );            \
1111     asm( "mulhwu %r9, %r7, %r6  " );            \
1112     asm( "adde   %r8, %r8, %r5  " );            \
1113     asm( "lwz    %r7, 4(%r4)    " );            \
1114     asm( "addze  %r5, %r9       " );            \
1115     asm( "addc   %r8, %r8, %r7  " );            \
1116     asm( "stwu   %r8, 4(%r4)    " );
1117
1118 #define MULADDC_STOP                            \
1119     asm( "addze  %r5, %r5       " );            \
1120     asm( "addi   %r4, %r4, 4    " );            \
1121     asm( "addi   %r3, %r3, 4    " );            \
1122     asm( "stw    %%r5, %0       " : "=m" (c));  \
1123     asm( "stw    %%r4, %0       " : "=m" (d));  \
1124     asm( "stw    %%r3, %0       " : "=m" (s) :: \
1125     "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
1126
1127 #endif
1128
1129 #endif /* PPC32 */
1130 #endif /* PPC64 */
1131
1132 #if defined(__sparc__)
1133
1134 #define MULADDC_INIT                            \
1135     asm( "ld     %0, %%o0       " :: "m" (s));  \
1136     asm( "ld     %0, %%o1       " :: "m" (d));  \
1137     asm( "ld     %0, %%o2       " :: "m" (c));  \
1138     asm( "ld     %0, %%o3       " :: "m" (b));
1139
1140 #define MULADDC_CORE                            \
1141     asm( "ld    [%o0], %o4      " );            \
1142     asm( "inc      4,  %o0      " );            \
1143     asm( "ld    [%o1], %o5      " );            \
1144     asm( "umul   %o3,  %o4, %o4 " );            \
1145     asm( "addcc  %o4,  %o2, %o4 " );            \
1146     asm( "rd      %y,  %g1      " );            \
1147     asm( "addx   %g1,    0, %g1 " );            \
1148     asm( "addcc  %o4,  %o5, %o4 " );            \
1149     asm( "st     %o4, [%o1]     " );            \
1150     asm( "addx   %g1,    0, %o2 " );            \
1151     asm( "inc      4,  %o1      " );
1152
1153 #define MULADDC_STOP                            \
1154     asm( "st     %%o2, %0       " : "=m" (c));  \
1155     asm( "st     %%o1, %0       " : "=m" (d));  \
1156     asm( "st     %%o0, %0       " : "=m" (s) :: \
1157     "g1", "o0", "o1", "o2", "o3", "o4", "o5" );
1158
1159 #endif /* SPARCv8 */
1160
1161 #if defined(__microblaze__) || defined(microblaze)
1162
1163 #define MULADDC_INIT                            \
1164     asm( "lwi   r3,   %0        " :: "m" (s));  \
1165     asm( "lwi   r4,   %0        " :: "m" (d));  \
1166     asm( "lwi   r5,   %0        " :: "m" (c));  \
1167     asm( "lwi   r6,   %0        " :: "m" (b));  \
1168     asm( "andi  r7,   r6, 0xffff" );            \
1169     asm( "bsrli r6,   r6, 16    " );
1170
1171 #define MULADDC_CORE                            \
1172     asm( "lhui  r8,   r3,   0   " );            \
1173     asm( "addi  r3,   r3,   2   " );            \
1174     asm( "lhui  r9,   r3,   0   " );            \
1175     asm( "addi  r3,   r3,   2   " );            \
1176     asm( "mul   r10,  r9,  r6   " );            \
1177     asm( "mul   r11,  r8,  r7   " );            \
1178     asm( "mul   r12,  r9,  r7   " );            \
1179     asm( "mul   r13,  r8,  r6   " );            \
1180     asm( "bsrli  r8, r10,  16   " );            \
1181     asm( "bsrli  r9, r11,  16   " );            \
1182     asm( "add   r13, r13,  r8   " );            \
1183     asm( "add   r13, r13,  r9   " );            \
1184     asm( "bslli r10, r10,  16   " );            \
1185     asm( "bslli r11, r11,  16   " );            \
1186     asm( "add   r12, r12, r10   " );            \
1187     asm( "addc  r13, r13,  r0   " );            \
1188     asm( "add   r12, r12, r11   " );            \
1189     asm( "addc  r13, r13,  r0   " );            \
1190     asm( "lwi   r10,  r4,   0   " );            \
1191     asm( "add   r12, r12, r10   " );            \
1192     asm( "addc  r13, r13,  r0   " );            \
1193     asm( "add   r12, r12,  r5   " );            \
1194     asm( "addc   r5, r13,  r0   " );            \
1195     asm( "swi   r12,  r4,   0   " );            \
1196     asm( "addi   r4,  r4,   4   " );
1197
1198 #define MULADDC_STOP                            \
1199     asm( "swi   r5,   %0        " : "=m" (c));  \
1200     asm( "swi   r4,   %0        " : "=m" (d));  \
1201     asm( "swi   r3,   %0        " : "=m" (s) :: \
1202      "r3", "r4" , "r5" , "r6" , "r7" , "r8" ,   \
1203      "r9", "r10", "r11", "r12", "r13" );
1204
1205 #endif /* MicroBlaze */
1206
1207 #if defined(__tricore__)
1208
1209 #define MULADDC_INIT                            \
1210     asm( "ld.a   %%a2, %0       " :: "m" (s));  \
1211     asm( "ld.a   %%a3, %0       " :: "m" (d));  \
1212     asm( "ld.w   %%d4, %0       " :: "m" (c));  \
1213     asm( "ld.w   %%d1, %0       " :: "m" (b));  \
1214     asm( "xor    %d5, %d5       " );
1215
1216 #define MULADDC_CORE                            \
1217     asm( "ld.w   %d0,   [%a2+]      " );        \
1218     asm( "madd.u %e2, %e4, %d0, %d1 " );        \
1219     asm( "ld.w   %d0,   [%a3]       " );        \
1220     asm( "addx   %d2,    %d2,  %d0  " );        \
1221     asm( "addc   %d3,    %d3,    0  " );        \
1222     asm( "mov    %d4,    %d3        " );        \
1223     asm( "st.w  [%a3+],  %d2        " );
1224
1225 #define MULADDC_STOP                            \
1226     asm( "st.w   %0, %%d4       " : "=m" (c));  \
1227     asm( "st.a   %0, %%a3       " : "=m" (d));  \
1228     asm( "st.a   %0, %%a2       " : "=m" (s) :: \
1229     "d0", "d1", "e2", "d4", "a2", "a3" );
1230
1231 #endif /* TriCore */
1232
1233 #if defined(__arm__)
1234
1235 #define MULADDC_INIT                            \
1236     asm( "ldr    r0, %0         " :: "m" (s));  \
1237     asm( "ldr    r1, %0         " :: "m" (d));  \
1238     asm( "ldr    r2, %0         " :: "m" (c));  \
1239     asm( "ldr    r3, %0         " :: "m" (b));
1240
1241 #define MULADDC_CORE                            \
1242     asm( "ldr    r4, [r0], #4   " );            \
1243     asm( "mov    r5, #0         " );            \
1244     asm( "ldr    r6, [r1]       " );            \
1245     asm( "umlal  r2, r5, r3, r4 " );            \
1246     asm( "adds   r7, r6, r2     " );            \
1247     asm( "adc    r2, r5, #0     " );            \
1248     asm( "str    r7, [r1], #4   " );
1249
1250 #define MULADDC_STOP                            \
1251     asm( "str    r2, %0         " : "=m" (c));  \
1252     asm( "str    r1, %0         " : "=m" (d));  \
1253     asm( "str    r0, %0         " : "=m" (s) :: \
1254     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" );
1255
1256 #endif /* ARMv3 */
1257
1258 #if defined(__alpha__)
1259
1260 #define MULADDC_INIT                            \
1261     asm( "ldq    $1, %0         " :: "m" (s));  \
1262     asm( "ldq    $2, %0         " :: "m" (d));  \
1263     asm( "ldq    $3, %0         " :: "m" (c));  \
1264     asm( "ldq    $4, %0         " :: "m" (b));
1265
1266 #define MULADDC_CORE                            \
1267     asm( "ldq    $6,  0($1)     " );            \
1268     asm( "addq   $1,  8, $1     " );            \
1269     asm( "mulq   $6, $4, $7     " );            \
1270     asm( "umulh  $6, $4, $6     " );            \
1271     asm( "addq   $7, $3, $7     " );            \
1272     asm( "cmpult $7, $3, $3     " );            \
1273     asm( "ldq    $5,  0($2)     " );            \
1274     asm( "addq   $7, $5, $7     " );            \
1275     asm( "cmpult $7, $5, $5     " );            \
1276     asm( "stq    $7,  0($2)     " );            \
1277     asm( "addq   $2,  8, $2     " );            \
1278     asm( "addq   $6, $3, $3     " );            \
1279     asm( "addq   $5, $3, $3     " );
1280
1281 #define MULADDC_STOP                            \
1282     asm( "stq    $3, %0         " : "=m" (c));  \
1283     asm( "stq    $2, %0         " : "=m" (d));  \
1284     asm( "stq    $1, %0         " : "=m" (s) :: \
1285     "$1", "$2", "$3", "$4", "$5", "$6", "$7" );
1286
1287 #endif /* Alpha */
1288
1289 #if defined(__mips__)
1290
1291 #define MULADDC_INIT                            \
1292     asm( "lw     $10, %0        " :: "m" (s));  \
1293     asm( "lw     $11, %0        " :: "m" (d));  \
1294     asm( "lw     $12, %0        " :: "m" (c));  \
1295     asm( "lw     $13, %0        " :: "m" (b));
1296
1297 #define MULADDC_CORE                            \
1298     asm( "lw     $14, 0($10)    " );            \
1299     asm( "multu  $13, $14       " );            \
1300     asm( "addi   $10, $10, 4    " );            \
1301     asm( "mflo   $14            " );            \
1302     asm( "mfhi   $9             " );            \
1303     asm( "addu   $14, $12, $14  " );            \
1304     asm( "lw     $15, 0($11)    " );            \
1305     asm( "sltu   $12, $14, $12  " );            \
1306     asm( "addu   $15, $14, $15  " );            \
1307     asm( "sltu   $14, $15, $14  " );            \
1308     asm( "addu   $12, $12, $9   " );            \
1309     asm( "sw     $15, 0($11)    " );            \
1310     asm( "addu   $12, $12, $14  " );            \
1311     asm( "addi   $11, $11, 4    " );
1312
1313 #define MULADDC_STOP                            \
1314     asm( "sw     $12, %0        " : "=m" (c));  \
1315     asm( "sw     $11, %0        " : "=m" (d));  \
1316     asm( "sw     $10, %0        " : "=m" (s) :: \
1317     "$9", "$10", "$11", "$12", "$13", "$14", "$15" );
1318
1319 #endif /* MIPS */
1320 #endif /* GNUC */
1321
1322 #if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
1323
1324 #define MULADDC_INIT                            \
1325     __asm   mov     esi, s                      \
1326     __asm   mov     edi, d                      \
1327     __asm   mov     ecx, c                      \
1328     __asm   mov     ebx, b
1329
1330 #define MULADDC_CORE                            \
1331     __asm   lodsd                               \
1332     __asm   mul     ebx                         \
1333     __asm   add     eax, ecx                    \
1334     __asm   adc     edx, 0                      \
1335     __asm   add     eax, [edi]                  \
1336     __asm   adc     edx, 0                      \
1337     __asm   mov     ecx, edx                    \
1338     __asm   stosd
1339
1340 #if defined(POLARSSL_HAVE_SSE2)
1341
1342 #define EMIT __asm _emit
1343
1344 #define MULADDC_HUIT                            \
1345     EMIT 0x0F  EMIT 0x6E  EMIT 0xC9             \
1346     EMIT 0x0F  EMIT 0x6E  EMIT 0xC3             \
1347     EMIT 0x0F  EMIT 0x6E  EMIT 0x1F             \
1348     EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
1349     EMIT 0x0F  EMIT 0x6E  EMIT 0x16             \
1350     EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
1351     EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x04  \
1352     EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
1353     EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x08  \
1354     EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
1355     EMIT 0x0F  EMIT 0x6E  EMIT 0x7E  EMIT 0x0C  \
1356     EMIT 0x0F  EMIT 0xF4  EMIT 0xF8             \
1357     EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
1358     EMIT 0x0F  EMIT 0x6E  EMIT 0x5F  EMIT 0x04  \
1359     EMIT 0x0F  EMIT 0xD4  EMIT 0xDC             \
1360     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x08  \
1361     EMIT 0x0F  EMIT 0xD4  EMIT 0xEE             \
1362     EMIT 0x0F  EMIT 0x6E  EMIT 0x67  EMIT 0x0C  \
1363     EMIT 0x0F  EMIT 0xD4  EMIT 0xFC             \
1364     EMIT 0x0F  EMIT 0x7E  EMIT 0x0F             \
1365     EMIT 0x0F  EMIT 0x6E  EMIT 0x56  EMIT 0x10  \
1366     EMIT 0x0F  EMIT 0xF4  EMIT 0xD0             \
1367     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
1368     EMIT 0x0F  EMIT 0x6E  EMIT 0x66  EMIT 0x14  \
1369     EMIT 0x0F  EMIT 0xF4  EMIT 0xE0             \
1370     EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
1371     EMIT 0x0F  EMIT 0x6E  EMIT 0x76  EMIT 0x18  \
1372     EMIT 0x0F  EMIT 0xF4  EMIT 0xF0             \
1373     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x04  \
1374     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
1375     EMIT 0x0F  EMIT 0x6E  EMIT 0x5E  EMIT 0x1C  \
1376     EMIT 0x0F  EMIT 0xF4  EMIT 0xD8             \
1377     EMIT 0x0F  EMIT 0xD4  EMIT 0xCD             \
1378     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x10  \
1379     EMIT 0x0F  EMIT 0xD4  EMIT 0xD5             \
1380     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x08  \
1381     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
1382     EMIT 0x0F  EMIT 0xD4  EMIT 0xCF             \
1383     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x14  \
1384     EMIT 0x0F  EMIT 0xD4  EMIT 0xE5             \
1385     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x0C  \
1386     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
1387     EMIT 0x0F  EMIT 0xD4  EMIT 0xCA             \
1388     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x18  \
1389     EMIT 0x0F  EMIT 0xD4  EMIT 0xF5             \
1390     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x10  \
1391     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
1392     EMIT 0x0F  EMIT 0xD4  EMIT 0xCC             \
1393     EMIT 0x0F  EMIT 0x6E  EMIT 0x6F  EMIT 0x1C  \
1394     EMIT 0x0F  EMIT 0xD4  EMIT 0xDD             \
1395     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x14  \
1396     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
1397     EMIT 0x0F  EMIT 0xD4  EMIT 0xCE             \
1398     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x18  \
1399     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
1400     EMIT 0x0F  EMIT 0xD4  EMIT 0xCB             \
1401     EMIT 0x0F  EMIT 0x7E  EMIT 0x4F  EMIT 0x1C  \
1402     EMIT 0x83  EMIT 0xC7  EMIT 0x20             \
1403     EMIT 0x83  EMIT 0xC6  EMIT 0x20             \
1404     EMIT 0x0F  EMIT 0x73  EMIT 0xD1  EMIT 0x20  \
1405     EMIT 0x0F  EMIT 0x7E  EMIT 0xC9
1406
1407 #define MULADDC_STOP                            \
1408     EMIT 0x0F  EMIT 0x77                        \
1409     __asm   mov     c, ecx                      \
1410     __asm   mov     d, edi                      \
1411     __asm   mov     s, esi                      \
1412
1413 #else
1414
1415 #define MULADDC_STOP                            \
1416     __asm   mov     c, ecx                      \
1417     __asm   mov     d, edi                      \
1418     __asm   mov     s, esi                      \
1419
1420 #endif /* SSE2 */
1421 #endif /* MSVC */
1422
1423 #endif /* POLARSSL_HAVE_ASM */
1424
1425 #if !defined(MULADDC_CORE)
1426 #if defined(POLARSSL_HAVE_LONGLONG)
1427
1428 #define MULADDC_INIT                    \
1429 {                                       \
1430     t_dbl r;                            \
1431     t_int r0, r1;
1432
1433 #define MULADDC_CORE                    \
1434     r   = *(s++) * (t_dbl) b;           \
1435     r0  = r;                            \
1436     r1  = r >> biL;                     \
1437     r0 += c;  r1 += (r0 <  c);          \
1438     r0 += *d; r1 += (r0 < *d);          \
1439     c = r1; *(d++) = r0;
1440
1441 #define MULADDC_STOP                    \
1442 }
1443
1444 #else
1445 #define MULADDC_INIT                    \
1446 {                                       \
1447     t_int s0, s1, b0, b1;               \
1448     t_int r0, r1, rx, ry;               \
1449     b0 = ( b << biH ) >> biH;           \
1450     b1 = ( b >> biH );
1451
1452 #define MULADDC_CORE                    \
1453     s0 = ( *s << biH ) >> biH;          \
1454     s1 = ( *s >> biH ); s++;            \
1455     rx = s0 * b1; r0 = s0 * b0;         \
1456     ry = s1 * b0; r1 = s1 * b1;         \
1457     r1 += ( rx >> biH );                \
1458     r1 += ( ry >> biH );                \
1459     rx <<= biH; ry <<= biH;             \
1460     r0 += rx; r1 += (r0 < rx);          \
1461     r0 += ry; r1 += (r0 < ry);          \
1462     r0 +=  c; r1 += (r0 <  c);          \
1463     r0 += *d; r1 += (r0 < *d);          \
1464     c = r1; *(d++) = r0;
1465
1466 #define MULADDC_STOP                    \
1467 }
1468
1469 #endif /* C (generic)  */
1470 #endif /* C (longlong) */
1471
1472 #endif /* bn_mul.h */