29ba1224e36b5e2bece27a2c89ff4ef31603d38d
[openssl.git] / crypto / bn / asm / x86_64-mont.pl
1 #!/usr/bin/env perl
2
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9
10 # October 2005.
11 #
12 # Montgomery multiplication routine for x86_64. While it gives modest
13 # 9% improvement of rsa4096 sign on Opteron, rsa512 sign runs more
14 # than twice, >2x, as fast. Most common rsa1024 sign is improved by
15 # respectful 50%. It remains to be seen if loop unrolling and
16 # dedicated squaring routine can provide further improvement...
17
18 # July 2011.
19 #
20 # Add dedicated squaring procedure. Performance improvement varies
21 # from platform to platform, but in average it's ~5%/15%/25%/33%
22 # for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively.
23
24 # August 2011.
25 #
26 # Unroll and modulo-schedule inner loops in such manner that they
27 # are "fallen through" for input lengths of 8, which is critical for
28 # 1024-bit RSA *sign*. Average performance improvement in comparison
29 # to *initial* version of this module from 2005 is ~0%/30%/40%/45%
30 # for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively.
31
32 # June 2013.
33 #
34 # Optimize reduction in squaring procedure and improve 1024+-bit RSA
35 # sign performance by 10-16% on Intel Sandy Bridge and later
36 # (virtually same on non-Intel processors).
37
38 # August 2013.
39 #
40 # Add MULX/ADOX/ADCX code path.
41
42 $flavour = shift;
43 $output  = shift;
44 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
45
46 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
47
48 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
49 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
50 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
51 die "can't locate x86_64-xlate.pl";
52
53 open OUT,"| \"$^X\" $xlate $flavour $output";
54 *STDOUT=*OUT;
55
56 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
57                 =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
58         $addx = ($1>=2.23);
59 }
60
61 if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
62             `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
63         $addx = ($1>=2.10);
64 }
65
66 if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
67             `ml64 2>&1` =~ /Version ([0-9]+)\./) {
68         $addx = ($1>=12);
69 }
70
71 if (!$addx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9])\.([0-9]+)/) {
72         my $ver = $2 + $3/100.0;        # 3.1->3.01, 3.10->3.10
73         $addx = ($ver>=3.03);
74 }
75
76 # int bn_mul_mont(
77 $rp="%rdi";     # BN_ULONG *rp,
78 $ap="%rsi";     # const BN_ULONG *ap,
79 $bp="%rdx";     # const BN_ULONG *bp,
80 $np="%rcx";     # const BN_ULONG *np,
81 $n0="%r8";      # const BN_ULONG *n0,
82 $num="%r9";     # int num);
83 $lo0="%r10";
84 $hi0="%r11";
85 $hi1="%r13";
86 $i="%r14";
87 $j="%r15";
88 $m0="%rbx";
89 $m1="%rbp";
90
91 $code=<<___;
92 .text
93
94 .extern OPENSSL_ia32cap_P
95
96 .globl  bn_mul_mont
97 .type   bn_mul_mont,\@function,6
98 .align  16
99 bn_mul_mont:
100         test    \$3,${num}d
101         jnz     .Lmul_enter
102         cmp     \$8,${num}d
103         jb      .Lmul_enter
104 ___
105 $code.=<<___ if ($addx);
106         mov     OPENSSL_ia32cap_P+8(%rip),%r11d
107 ___
108 $code.=<<___;
109         cmp     $ap,$bp
110         jne     .Lmul4x_enter
111         test    \$7,${num}d
112         jz      .Lsqr8x_enter
113         jmp     .Lmul4x_enter
114
115 .align  16
116 .Lmul_enter:
117         push    %rbx
118         push    %rbp
119         push    %r12
120         push    %r13
121         push    %r14
122         push    %r15
123
124         mov     ${num}d,${num}d
125         lea     2($num),%r10
126         mov     %rsp,%r11
127         neg     %r10
128         lea     (%rsp,%r10,8),%rsp      # tp=alloca(8*(num+2))
129         and     \$-1024,%rsp            # minimize TLB usage
130
131         mov     %r11,8(%rsp,$num,8)     # tp[num+1]=%rsp
132 .Lmul_body:
133         mov     $bp,%r12                # reassign $bp
134 ___
135                 $bp="%r12";
136 $code.=<<___;
137         mov     ($n0),$n0               # pull n0[0] value
138         mov     ($bp),$m0               # m0=bp[0]
139         mov     ($ap),%rax
140
141         xor     $i,$i                   # i=0
142         xor     $j,$j                   # j=0
143
144         mov     $n0,$m1
145         mulq    $m0                     # ap[0]*bp[0]
146         mov     %rax,$lo0
147         mov     ($np),%rax
148
149         imulq   $lo0,$m1                # "tp[0]"*n0
150         mov     %rdx,$hi0
151
152         mulq    $m1                     # np[0]*m1
153         add     %rax,$lo0               # discarded
154         mov     8($ap),%rax
155         adc     \$0,%rdx
156         mov     %rdx,$hi1
157
158         lea     1($j),$j                # j++
159         jmp     .L1st_enter
160
161 .align  16
162 .L1st:
163         add     %rax,$hi1
164         mov     ($ap,$j,8),%rax
165         adc     \$0,%rdx
166         add     $hi0,$hi1               # np[j]*m1+ap[j]*bp[0]
167         mov     $lo0,$hi0
168         adc     \$0,%rdx
169         mov     $hi1,-16(%rsp,$j,8)     # tp[j-1]
170         mov     %rdx,$hi1
171
172 .L1st_enter:
173         mulq    $m0                     # ap[j]*bp[0]
174         add     %rax,$hi0
175         mov     ($np,$j,8),%rax
176         adc     \$0,%rdx
177         lea     1($j),$j                # j++
178         mov     %rdx,$lo0
179
180         mulq    $m1                     # np[j]*m1
181         cmp     $num,$j
182         jne     .L1st
183
184         add     %rax,$hi1
185         mov     ($ap),%rax              # ap[0]
186         adc     \$0,%rdx
187         add     $hi0,$hi1               # np[j]*m1+ap[j]*bp[0]
188         adc     \$0,%rdx
189         mov     $hi1,-16(%rsp,$j,8)     # tp[j-1]
190         mov     %rdx,$hi1
191         mov     $lo0,$hi0
192
193         xor     %rdx,%rdx
194         add     $hi0,$hi1
195         adc     \$0,%rdx
196         mov     $hi1,-8(%rsp,$num,8)
197         mov     %rdx,(%rsp,$num,8)      # store upmost overflow bit
198
199         lea     1($i),$i                # i++
200         jmp     .Louter
201 .align  16
202 .Louter:
203         mov     ($bp,$i,8),$m0          # m0=bp[i]
204         xor     $j,$j                   # j=0
205         mov     $n0,$m1
206         mov     (%rsp),$lo0
207         mulq    $m0                     # ap[0]*bp[i]
208         add     %rax,$lo0               # ap[0]*bp[i]+tp[0]
209         mov     ($np),%rax
210         adc     \$0,%rdx
211
212         imulq   $lo0,$m1                # tp[0]*n0
213         mov     %rdx,$hi0
214
215         mulq    $m1                     # np[0]*m1
216         add     %rax,$lo0               # discarded
217         mov     8($ap),%rax
218         adc     \$0,%rdx
219         mov     8(%rsp),$lo0            # tp[1]
220         mov     %rdx,$hi1
221
222         lea     1($j),$j                # j++
223         jmp     .Linner_enter
224
225 .align  16
226 .Linner:
227         add     %rax,$hi1
228         mov     ($ap,$j,8),%rax
229         adc     \$0,%rdx
230         add     $lo0,$hi1               # np[j]*m1+ap[j]*bp[i]+tp[j]
231         mov     (%rsp,$j,8),$lo0
232         adc     \$0,%rdx
233         mov     $hi1,-16(%rsp,$j,8)     # tp[j-1]
234         mov     %rdx,$hi1
235
236 .Linner_enter:
237         mulq    $m0                     # ap[j]*bp[i]
238         add     %rax,$hi0
239         mov     ($np,$j,8),%rax
240         adc     \$0,%rdx
241         add     $hi0,$lo0               # ap[j]*bp[i]+tp[j]
242         mov     %rdx,$hi0
243         adc     \$0,$hi0
244         lea     1($j),$j                # j++
245
246         mulq    $m1                     # np[j]*m1
247         cmp     $num,$j
248         jne     .Linner
249
250         add     %rax,$hi1
251         mov     ($ap),%rax              # ap[0]
252         adc     \$0,%rdx
253         add     $lo0,$hi1               # np[j]*m1+ap[j]*bp[i]+tp[j]
254         mov     (%rsp,$j,8),$lo0
255         adc     \$0,%rdx
256         mov     $hi1,-16(%rsp,$j,8)     # tp[j-1]
257         mov     %rdx,$hi1
258
259         xor     %rdx,%rdx
260         add     $hi0,$hi1
261         adc     \$0,%rdx
262         add     $lo0,$hi1               # pull upmost overflow bit
263         adc     \$0,%rdx
264         mov     $hi1,-8(%rsp,$num,8)
265         mov     %rdx,(%rsp,$num,8)      # store upmost overflow bit
266
267         lea     1($i),$i                # i++
268         cmp     $num,$i
269         jb      .Louter
270
271         xor     $i,$i                   # i=0 and clear CF!
272         mov     (%rsp),%rax             # tp[0]
273         lea     (%rsp),$ap              # borrow ap for tp
274         mov     $num,$j                 # j=num
275         jmp     .Lsub
276 .align  16
277 .Lsub:  sbb     ($np,$i,8),%rax
278         mov     %rax,($rp,$i,8)         # rp[i]=tp[i]-np[i]
279         mov     8($ap,$i,8),%rax        # tp[i+1]
280         lea     1($i),$i                # i++
281         dec     $j                      # doesnn't affect CF!
282         jnz     .Lsub
283
284         sbb     \$0,%rax                # handle upmost overflow bit
285         xor     $i,$i
286         and     %rax,$ap
287         not     %rax
288         mov     $rp,$np
289         and     %rax,$np
290         mov     $num,$j                 # j=num
291         or      $np,$ap                 # ap=borrow?tp:rp
292 .align  16
293 .Lcopy:                                 # copy or in-place refresh
294         mov     ($ap,$i,8),%rax
295         mov     $i,(%rsp,$i,8)          # zap temporary vector
296         mov     %rax,($rp,$i,8)         # rp[i]=tp[i]
297         lea     1($i),$i
298         sub     \$1,$j
299         jnz     .Lcopy
300
301         mov     8(%rsp,$num,8),%rsi     # restore %rsp
302         mov     \$1,%rax
303         mov     (%rsi),%r15
304         mov     8(%rsi),%r14
305         mov     16(%rsi),%r13
306         mov     24(%rsi),%r12
307         mov     32(%rsi),%rbp
308         mov     40(%rsi),%rbx
309         lea     48(%rsi),%rsp
310 .Lmul_epilogue:
311         ret
312 .size   bn_mul_mont,.-bn_mul_mont
313 ___
314 {{{
315 my @A=("%r10","%r11");
316 my @N=("%r13","%rdi");
317 $code.=<<___;
318 .type   bn_mul4x_mont,\@function,6
319 .align  16
320 bn_mul4x_mont:
321 .Lmul4x_enter:
322 ___
323 $code.=<<___ if ($addx);
324         and     \$0x80100,%r11d
325         cmp     \$0x80100,%r11d
326         je      .Lmulx4x_enter
327 ___
328 $code.=<<___;
329         push    %rbx
330         push    %rbp
331         push    %r12
332         push    %r13
333         push    %r14
334         push    %r15
335
336         mov     ${num}d,${num}d
337         lea     4($num),%r10
338         mov     %rsp,%r11
339         neg     %r10
340         lea     (%rsp,%r10,8),%rsp      # tp=alloca(8*(num+4))
341         and     \$-1024,%rsp            # minimize TLB usage
342
343         mov     %r11,8(%rsp,$num,8)     # tp[num+1]=%rsp
344 .Lmul4x_body:
345         mov     $rp,16(%rsp,$num,8)     # tp[num+2]=$rp
346         mov     %rdx,%r12               # reassign $bp
347 ___
348                 $bp="%r12";
349 $code.=<<___;
350         mov     ($n0),$n0               # pull n0[0] value
351         mov     ($bp),$m0               # m0=bp[0]
352         mov     ($ap),%rax
353
354         xor     $i,$i                   # i=0
355         xor     $j,$j                   # j=0
356
357         mov     $n0,$m1
358         mulq    $m0                     # ap[0]*bp[0]
359         mov     %rax,$A[0]
360         mov     ($np),%rax
361
362         imulq   $A[0],$m1               # "tp[0]"*n0
363         mov     %rdx,$A[1]
364
365         mulq    $m1                     # np[0]*m1
366         add     %rax,$A[0]              # discarded
367         mov     8($ap),%rax
368         adc     \$0,%rdx
369         mov     %rdx,$N[1]
370
371         mulq    $m0
372         add     %rax,$A[1]
373         mov     8($np),%rax
374         adc     \$0,%rdx
375         mov     %rdx,$A[0]
376
377         mulq    $m1
378         add     %rax,$N[1]
379         mov     16($ap),%rax
380         adc     \$0,%rdx
381         add     $A[1],$N[1]
382         lea     4($j),$j                # j++
383         adc     \$0,%rdx
384         mov     $N[1],(%rsp)
385         mov     %rdx,$N[0]
386         jmp     .L1st4x
387 .align  16
388 .L1st4x:
389         mulq    $m0                     # ap[j]*bp[0]
390         add     %rax,$A[0]
391         mov     -16($np,$j,8),%rax
392         adc     \$0,%rdx
393         mov     %rdx,$A[1]
394
395         mulq    $m1                     # np[j]*m1
396         add     %rax,$N[0]
397         mov     -8($ap,$j,8),%rax
398         adc     \$0,%rdx
399         add     $A[0],$N[0]             # np[j]*m1+ap[j]*bp[0]
400         adc     \$0,%rdx
401         mov     $N[0],-24(%rsp,$j,8)    # tp[j-1]
402         mov     %rdx,$N[1]
403
404         mulq    $m0                     # ap[j]*bp[0]
405         add     %rax,$A[1]
406         mov     -8($np,$j,8),%rax
407         adc     \$0,%rdx
408         mov     %rdx,$A[0]
409
410         mulq    $m1                     # np[j]*m1
411         add     %rax,$N[1]
412         mov     ($ap,$j,8),%rax
413         adc     \$0,%rdx
414         add     $A[1],$N[1]             # np[j]*m1+ap[j]*bp[0]
415         adc     \$0,%rdx
416         mov     $N[1],-16(%rsp,$j,8)    # tp[j-1]
417         mov     %rdx,$N[0]
418
419         mulq    $m0                     # ap[j]*bp[0]
420         add     %rax,$A[0]
421         mov     ($np,$j,8),%rax
422         adc     \$0,%rdx
423         mov     %rdx,$A[1]
424
425         mulq    $m1                     # np[j]*m1
426         add     %rax,$N[0]
427         mov     8($ap,$j,8),%rax
428         adc     \$0,%rdx
429         add     $A[0],$N[0]             # np[j]*m1+ap[j]*bp[0]
430         adc     \$0,%rdx
431         mov     $N[0],-8(%rsp,$j,8)     # tp[j-1]
432         mov     %rdx,$N[1]
433
434         mulq    $m0                     # ap[j]*bp[0]
435         add     %rax,$A[1]
436         mov     8($np,$j,8),%rax
437         adc     \$0,%rdx
438         lea     4($j),$j                # j++
439         mov     %rdx,$A[0]
440
441         mulq    $m1                     # np[j]*m1
442         add     %rax,$N[1]
443         mov     -16($ap,$j,8),%rax
444         adc     \$0,%rdx
445         add     $A[1],$N[1]             # np[j]*m1+ap[j]*bp[0]
446         adc     \$0,%rdx
447         mov     $N[1],-32(%rsp,$j,8)    # tp[j-1]
448         mov     %rdx,$N[0]
449         cmp     $num,$j
450         jb      .L1st4x
451
452         mulq    $m0                     # ap[j]*bp[0]
453         add     %rax,$A[0]
454         mov     -16($np,$j,8),%rax
455         adc     \$0,%rdx
456         mov     %rdx,$A[1]
457
458         mulq    $m1                     # np[j]*m1
459         add     %rax,$N[0]
460         mov     -8($ap,$j,8),%rax
461         adc     \$0,%rdx
462         add     $A[0],$N[0]             # np[j]*m1+ap[j]*bp[0]
463         adc     \$0,%rdx
464         mov     $N[0],-24(%rsp,$j,8)    # tp[j-1]
465         mov     %rdx,$N[1]
466
467         mulq    $m0                     # ap[j]*bp[0]
468         add     %rax,$A[1]
469         mov     -8($np,$j,8),%rax
470         adc     \$0,%rdx
471         mov     %rdx,$A[0]
472
473         mulq    $m1                     # np[j]*m1
474         add     %rax,$N[1]
475         mov     ($ap),%rax              # ap[0]
476         adc     \$0,%rdx
477         add     $A[1],$N[1]             # np[j]*m1+ap[j]*bp[0]
478         adc     \$0,%rdx
479         mov     $N[1],-16(%rsp,$j,8)    # tp[j-1]
480         mov     %rdx,$N[0]
481
482         xor     $N[1],$N[1]
483         add     $A[0],$N[0]
484         adc     \$0,$N[1]
485         mov     $N[0],-8(%rsp,$j,8)
486         mov     $N[1],(%rsp,$j,8)       # store upmost overflow bit
487
488         lea     1($i),$i                # i++
489 .align  4
490 .Louter4x:
491         mov     ($bp,$i,8),$m0          # m0=bp[i]
492         xor     $j,$j                   # j=0
493         mov     (%rsp),$A[0]
494         mov     $n0,$m1
495         mulq    $m0                     # ap[0]*bp[i]
496         add     %rax,$A[0]              # ap[0]*bp[i]+tp[0]
497         mov     ($np),%rax
498         adc     \$0,%rdx
499
500         imulq   $A[0],$m1               # tp[0]*n0
501         mov     %rdx,$A[1]
502
503         mulq    $m1                     # np[0]*m1
504         add     %rax,$A[0]              # "$N[0]", discarded
505         mov     8($ap),%rax
506         adc     \$0,%rdx
507         mov     %rdx,$N[1]
508
509         mulq    $m0                     # ap[j]*bp[i]
510         add     %rax,$A[1]
511         mov     8($np),%rax
512         adc     \$0,%rdx
513         add     8(%rsp),$A[1]           # +tp[1]
514         adc     \$0,%rdx
515         mov     %rdx,$A[0]
516
517         mulq    $m1                     # np[j]*m1
518         add     %rax,$N[1]
519         mov     16($ap),%rax
520         adc     \$0,%rdx
521         add     $A[1],$N[1]             # np[j]*m1+ap[j]*bp[i]+tp[j]
522         lea     4($j),$j                # j+=2
523         adc     \$0,%rdx
524         mov     $N[1],(%rsp)            # tp[j-1]
525         mov     %rdx,$N[0]
526         jmp     .Linner4x
527 .align  16
528 .Linner4x:
529         mulq    $m0                     # ap[j]*bp[i]
530         add     %rax,$A[0]
531         mov     -16($np,$j,8),%rax
532         adc     \$0,%rdx
533         add     -16(%rsp,$j,8),$A[0]    # ap[j]*bp[i]+tp[j]
534         adc     \$0,%rdx
535         mov     %rdx,$A[1]
536
537         mulq    $m1                     # np[j]*m1
538         add     %rax,$N[0]
539         mov     -8($ap,$j,8),%rax
540         adc     \$0,%rdx
541         add     $A[0],$N[0]
542         adc     \$0,%rdx
543         mov     $N[0],-24(%rsp,$j,8)    # tp[j-1]
544         mov     %rdx,$N[1]
545
546         mulq    $m0                     # ap[j]*bp[i]
547         add     %rax,$A[1]
548         mov     -8($np,$j,8),%rax
549         adc     \$0,%rdx
550         add     -8(%rsp,$j,8),$A[1]
551         adc     \$0,%rdx
552         mov     %rdx,$A[0]
553
554         mulq    $m1                     # np[j]*m1
555         add     %rax,$N[1]
556         mov     ($ap,$j,8),%rax
557         adc     \$0,%rdx
558         add     $A[1],$N[1]
559         adc     \$0,%rdx
560         mov     $N[1],-16(%rsp,$j,8)    # tp[j-1]
561         mov     %rdx,$N[0]
562
563         mulq    $m0                     # ap[j]*bp[i]
564         add     %rax,$A[0]
565         mov     ($np,$j,8),%rax
566         adc     \$0,%rdx
567         add     (%rsp,$j,8),$A[0]       # ap[j]*bp[i]+tp[j]
568         adc     \$0,%rdx
569         mov     %rdx,$A[1]
570
571         mulq    $m1                     # np[j]*m1
572         add     %rax,$N[0]
573         mov     8($ap,$j,8),%rax
574         adc     \$0,%rdx
575         add     $A[0],$N[0]
576         adc     \$0,%rdx
577         mov     $N[0],-8(%rsp,$j,8)     # tp[j-1]
578         mov     %rdx,$N[1]
579
580         mulq    $m0                     # ap[j]*bp[i]
581         add     %rax,$A[1]
582         mov     8($np,$j,8),%rax
583         adc     \$0,%rdx
584         add     8(%rsp,$j,8),$A[1]
585         adc     \$0,%rdx
586         lea     4($j),$j                # j++
587         mov     %rdx,$A[0]
588
589         mulq    $m1                     # np[j]*m1
590         add     %rax,$N[1]
591         mov     -16($ap,$j,8),%rax
592         adc     \$0,%rdx
593         add     $A[1],$N[1]
594         adc     \$0,%rdx
595         mov     $N[1],-32(%rsp,$j,8)    # tp[j-1]
596         mov     %rdx,$N[0]
597         cmp     $num,$j
598         jb      .Linner4x
599
600         mulq    $m0                     # ap[j]*bp[i]
601         add     %rax,$A[0]
602         mov     -16($np,$j,8),%rax
603         adc     \$0,%rdx
604         add     -16(%rsp,$j,8),$A[0]    # ap[j]*bp[i]+tp[j]
605         adc     \$0,%rdx
606         mov     %rdx,$A[1]
607
608         mulq    $m1                     # np[j]*m1
609         add     %rax,$N[0]
610         mov     -8($ap,$j,8),%rax
611         adc     \$0,%rdx
612         add     $A[0],$N[0]
613         adc     \$0,%rdx
614         mov     $N[0],-24(%rsp,$j,8)    # tp[j-1]
615         mov     %rdx,$N[1]
616
617         mulq    $m0                     # ap[j]*bp[i]
618         add     %rax,$A[1]
619         mov     -8($np,$j,8),%rax
620         adc     \$0,%rdx
621         add     -8(%rsp,$j,8),$A[1]
622         adc     \$0,%rdx
623         lea     1($i),$i                # i++
624         mov     %rdx,$A[0]
625
626         mulq    $m1                     # np[j]*m1
627         add     %rax,$N[1]
628         mov     ($ap),%rax              # ap[0]
629         adc     \$0,%rdx
630         add     $A[1],$N[1]
631         adc     \$0,%rdx
632         mov     $N[1],-16(%rsp,$j,8)    # tp[j-1]
633         mov     %rdx,$N[0]
634
635         xor     $N[1],$N[1]
636         add     $A[0],$N[0]
637         adc     \$0,$N[1]
638         add     (%rsp,$num,8),$N[0]     # pull upmost overflow bit
639         adc     \$0,$N[1]
640         mov     $N[0],-8(%rsp,$j,8)
641         mov     $N[1],(%rsp,$j,8)       # store upmost overflow bit
642
643         cmp     $num,$i
644         jb      .Louter4x
645 ___
646 {
647 my @ri=("%rax","%rdx",$m0,$m1);
648 $code.=<<___;
649         mov     16(%rsp,$num,8),$rp     # restore $rp
650         mov     0(%rsp),@ri[0]          # tp[0]
651         pxor    %xmm0,%xmm0
652         mov     8(%rsp),@ri[1]          # tp[1]
653         shr     \$2,$num                # num/=4
654         lea     (%rsp),$ap              # borrow ap for tp
655         xor     $i,$i                   # i=0 and clear CF!
656
657         sub     0($np),@ri[0]
658         mov     16($ap),@ri[2]          # tp[2]
659         mov     24($ap),@ri[3]          # tp[3]
660         sbb     8($np),@ri[1]
661         lea     -1($num),$j             # j=num/4-1
662         jmp     .Lsub4x
663 .align  16
664 .Lsub4x:
665         mov     @ri[0],0($rp,$i,8)      # rp[i]=tp[i]-np[i]
666         mov     @ri[1],8($rp,$i,8)      # rp[i]=tp[i]-np[i]
667         sbb     16($np,$i,8),@ri[2]
668         mov     32($ap,$i,8),@ri[0]     # tp[i+1]
669         mov     40($ap,$i,8),@ri[1]
670         sbb     24($np,$i,8),@ri[3]
671         mov     @ri[2],16($rp,$i,8)     # rp[i]=tp[i]-np[i]
672         mov     @ri[3],24($rp,$i,8)     # rp[i]=tp[i]-np[i]
673         sbb     32($np,$i,8),@ri[0]
674         mov     48($ap,$i,8),@ri[2]
675         mov     56($ap,$i,8),@ri[3]
676         sbb     40($np,$i,8),@ri[1]
677         lea     4($i),$i                # i++
678         dec     $j                      # doesnn't affect CF!
679         jnz     .Lsub4x
680
681         mov     @ri[0],0($rp,$i,8)      # rp[i]=tp[i]-np[i]
682         mov     32($ap,$i,8),@ri[0]     # load overflow bit
683         sbb     16($np,$i,8),@ri[2]
684         mov     @ri[1],8($rp,$i,8)      # rp[i]=tp[i]-np[i]
685         sbb     24($np,$i,8),@ri[3]
686         mov     @ri[2],16($rp,$i,8)     # rp[i]=tp[i]-np[i]
687
688         sbb     \$0,@ri[0]              # handle upmost overflow bit
689         mov     @ri[3],24($rp,$i,8)     # rp[i]=tp[i]-np[i]
690         xor     $i,$i                   # i=0
691         and     @ri[0],$ap
692         not     @ri[0]
693         mov     $rp,$np
694         and     @ri[0],$np
695         lea     -1($num),$j
696         or      $np,$ap                 # ap=borrow?tp:rp
697
698         movdqu  ($ap),%xmm1
699         movdqa  %xmm0,(%rsp)
700         movdqu  %xmm1,($rp)
701         jmp     .Lcopy4x
702 .align  16
703 .Lcopy4x:                                       # copy or in-place refresh
704         movdqu  16($ap,$i),%xmm2
705         movdqu  32($ap,$i),%xmm1
706         movdqa  %xmm0,16(%rsp,$i)
707         movdqu  %xmm2,16($rp,$i)
708         movdqa  %xmm0,32(%rsp,$i)
709         movdqu  %xmm1,32($rp,$i)
710         lea     32($i),$i
711         dec     $j
712         jnz     .Lcopy4x
713
714         shl     \$2,$num
715         movdqu  16($ap,$i),%xmm2
716         movdqa  %xmm0,16(%rsp,$i)
717         movdqu  %xmm2,16($rp,$i)
718 ___
719 }
720 $code.=<<___;
721         mov     8(%rsp,$num,8),%rsi     # restore %rsp
722         mov     \$1,%rax
723         mov     (%rsi),%r15
724         mov     8(%rsi),%r14
725         mov     16(%rsi),%r13
726         mov     24(%rsi),%r12
727         mov     32(%rsi),%rbp
728         mov     40(%rsi),%rbx
729         lea     48(%rsi),%rsp
730 .Lmul4x_epilogue:
731         ret
732 .size   bn_mul4x_mont,.-bn_mul4x_mont
733 ___
734 }}}
735 \f{{{
736 ######################################################################
737 # void bn_sqr8x_mont(
738 my $rptr="%rdi";        # const BN_ULONG *rptr,
739 my $aptr="%rsi";        # const BN_ULONG *aptr,
740 my $bptr="%rdx";        # not used
741 my $nptr="%rcx";        # const BN_ULONG *nptr,
742 my $n0  ="%r8";         # const BN_ULONG *n0);
743 my $num ="%r9";         # int num, has to be divisible by 8
744
745 my ($i,$j,$tptr)=("%rbp","%rcx",$rptr);
746 my @A0=("%r10","%r11");
747 my @A1=("%r12","%r13");
748 my ($a0,$a1,$ai)=("%r14","%r15","%rbx");
749
750 $code.=<<___    if ($addx);
751 .extern bn_sqrx8x_internal              # see x86_64-mont5 module
752 ___
753 $code.=<<___;
754 .extern bn_sqr8x_internal               # see x86_64-mont5 module
755
756 .type   bn_sqr8x_mont,\@function,6
757 .align  32
758 bn_sqr8x_mont:
759 .Lsqr8x_enter:
760         mov     %rsp,%rax
761         push    %rbx
762         push    %rbp
763         push    %r12
764         push    %r13
765         push    %r14
766         push    %r15
767
768         mov     ${num}d,%r10d
769         shl     \$3,${num}d             # convert $num to bytes
770         shl     \$3+2,%r10              # 4*$num
771         neg     $num
772
773         ##############################################################
774         # ensure that stack frame doesn't alias with $aptr modulo
775         # 4096. this is done to allow memory disambiguation logic
776         # do its job.
777         #
778         lea     -64(%rsp,$num,2),%r11
779         mov     ($n0),$n0               # *n0
780         sub     $aptr,%r11
781         and     \$4095,%r11
782         cmp     %r11,%r10
783         jb      .Lsqr8x_sp_alt
784         sub     %r11,%rsp               # align with $aptr
785         lea     -64(%rsp,$num,2),%rsp   # alloca(frame+2*$num)
786         jmp     .Lsqr8x_sp_done
787
788 .align  32
789 .Lsqr8x_sp_alt:
790         lea     4096-64(,$num,2),%r10   # 4096-frame-2*$num
791         lea     -64(%rsp,$num,2),%rsp   # alloca(frame+2*$num)
792         sub     %r10,%r11
793         mov     \$0,%r10
794         cmovc   %r10,%r11
795         sub     %r11,%rsp
796 .Lsqr8x_sp_done:
797         and     \$-64,%rsp
798         mov     $num,%r10
799         neg     $num
800
801         mov     $n0,  32(%rsp)
802         mov     %rax, 40(%rsp)          # save original %rsp
803 .Lsqr8x_body:
804
805         movq    $nptr, %xmm2            # save pointer to modulus
806         pxor    %xmm0,%xmm0
807         movq    $rptr,%xmm1             # save $rptr
808         movq    %r10, %xmm3             # -$num
809 ___
810 $code.=<<___ if ($addx);
811         mov     OPENSSL_ia32cap_P+8(%rip),%eax
812         and     \$0x80100,%eax
813         cmp     \$0x80100,%eax
814         jne     .Lsqr8x_nox
815
816         call    bn_sqrx8x_internal      # see x86_64-mont5 module
817                                         # %rax  top-most carry
818                                         # %rbp  nptr
819                                         # %rcx  -8*num
820                                         # %r8   end of tp[2*num]
821         lea     (%r8,%rcx),%rbx
822         mov     %rcx,$num
823         mov     %rcx,%rdx
824         movq    %xmm1,$rptr
825         sar     \$3+2,%rcx              # %cf=0
826         jmp     .Lsqr8x_sub
827
828 .align  32
829 .Lsqr8x_nox:
830 ___
831 $code.=<<___;
832         call    bn_sqr8x_internal       # see x86_64-mont5 module
833                                         # %rax  top-most carry
834                                         # %rbp  nptr
835                                         # %r8   -8*num
836                                         # %rdi  end of tp[2*num]
837         lea     (%rdi,$num),%rbx
838         mov     $num,%rcx
839         mov     $num,%rdx
840         movq    %xmm1,$rptr
841         sar     \$3+2,%rcx              # %cf=0
842         jmp     .Lsqr8x_sub
843
844 .align  32
845 .Lsqr8x_sub:
846         mov     8*0(%rbx),%r12
847         mov     8*1(%rbx),%r13
848         mov     8*2(%rbx),%r14
849         mov     8*3(%rbx),%r15
850         lea     8*4(%rbx),%rbx
851         sbb     8*0(%rbp),%r12
852         sbb     8*1(%rbp),%r13
853         sbb     8*2(%rbp),%r14
854         sbb     8*3(%rbp),%r15
855         lea     8*4(%rbp),%rbp
856         mov     %r12,8*0($rptr)
857         mov     %r13,8*1($rptr)
858         mov     %r14,8*2($rptr)
859         mov     %r15,8*3($rptr)
860         lea     8*4($rptr),$rptr
861         inc     %rcx                    # preserves %cf
862         jnz     .Lsqr8x_sub
863
864         sbb     \$0,%rax                # top-most carry
865         lea     (%rbx,$num),%rbx        # rewind
866         lea     ($rptr,$num),$rptr      # rewind
867
868         movq    %rax,%xmm1
869         pxor    %xmm0,%xmm0
870         pshufd  \$0,%xmm1,%xmm1
871         mov     40(%rsp),%rsi           # restore %rsp
872         jmp     .Lsqr8x_cond_copy
873
874 .align  32
875 .Lsqr8x_cond_copy:
876         movdqa  16*0(%rbx),%xmm2
877         movdqa  16*1(%rbx),%xmm3
878         lea     16*2(%rbx),%rbx
879         movdqu  16*0($rptr),%xmm4
880         movdqu  16*1($rptr),%xmm5
881         lea     16*2($rptr),$rptr
882         movdqa  %xmm0,-16*2(%rbx)       # zero tp
883         movdqa  %xmm0,-16*1(%rbx)
884         movdqa  %xmm0,-16*2(%rbx,%rdx)
885         movdqa  %xmm0,-16*1(%rbx,%rdx)
886         pcmpeqd %xmm1,%xmm0
887         pand    %xmm1,%xmm2
888         pand    %xmm1,%xmm3
889         pand    %xmm0,%xmm4
890         pand    %xmm0,%xmm5
891         pxor    %xmm0,%xmm0
892         por     %xmm2,%xmm4
893         por     %xmm3,%xmm5
894         movdqu  %xmm4,-16*2($rptr)
895         movdqu  %xmm5,-16*1($rptr)
896         add     \$32,$num
897         jnz     .Lsqr8x_cond_copy
898
899         mov     \$1,%rax
900         mov     -48(%rsi),%r15
901         mov     -40(%rsi),%r14
902         mov     -32(%rsi),%r13
903         mov     -24(%rsi),%r12
904         mov     -16(%rsi),%rbp
905         mov     -8(%rsi),%rbx
906         lea     (%rsi),%rsp
907 .Lsqr8x_epilogue:
908         ret
909 .size   bn_sqr8x_mont,.-bn_sqr8x_mont
910 ___
911 }}}
912 \f
913 if ($addx) {{{
914 my $bp="%rdx";  # original value
915
916 $code.=<<___;
917 .type   bn_mulx4x_mont,\@function,6
918 .align  32
919 bn_mulx4x_mont:
920 .Lmulx4x_enter:
921         mov     %rsp,%rax
922         push    %rbx
923         push    %rbp
924         push    %r12
925         push    %r13
926         push    %r14
927         push    %r15
928
929         shl     \$3,${num}d             # convert $num to bytes
930         .byte   0x67
931         xor     %r10,%r10
932         sub     $num,%r10               # -$num
933         mov     ($n0),$n0               # *n0
934         lea     -72(%rsp,%r10),%rsp     # alloca(frame+$num+8)
935         lea     ($bp,$num),%r10
936         and     \$-128,%rsp
937         ##############################################################
938         # Stack layout
939         # +0    num
940         # +8    off-loaded &b[i]
941         # +16   end of b[num]
942         # +24   saved n0
943         # +32   saved rp
944         # +40   saved %rsp
945         # +48   inner counter
946         # +56
947         # +64   tmp[num+1]
948         #
949         mov     $num,0(%rsp)            # save $num
950         shr     \$5,$num
951         mov     %r10,16(%rsp)           # end of b[num]
952         sub     \$1,$num
953         mov     $n0, 24(%rsp)           # save *n0
954         mov     $rp, 32(%rsp)           # save $rp
955         mov     %rax,40(%rsp)           # save original %rsp
956         mov     $num,48(%rsp)           # inner counter
957         jmp     .Lmulx4x_body
958
959 .align  32
960 .Lmulx4x_body:
961 ___
962 my ($aptr, $bptr, $nptr, $tptr, $mi,  $bi,  $zero, $num)=
963    ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax");
964 my $rptr=$bptr;
965 $code.=<<___;
966         lea     8($bp),$bptr
967         mov     ($bp),%rdx              # b[0], $bp==%rdx actually
968         lea     64+32(%rsp),$tptr
969         mov     %rdx,$bi
970
971         mulx    0*8($aptr),$mi,%rax     # a[0]*b[0]
972         mulx    1*8($aptr),%r11,%r14    # a[1]*b[0]
973         add     %rax,%r11
974         mov     $bptr,8(%rsp)           # off-load &b[i]
975         mulx    2*8($aptr),%r12,%r13    # ...
976         adc     %r14,%r12
977         adc     \$0,%r13
978
979         mov     $mi,$bptr               # borrow $bptr
980         imulq   24(%rsp),$mi            # "t[0]"*n0
981         xor     $zero,$zero             # cf=0, of=0
982
983         mulx    3*8($aptr),%rax,%r14
984          mov    $mi,%rdx
985         lea     4*8($aptr),$aptr
986         adcx    %rax,%r13
987         adcx    $zero,%r14              # cf=0
988
989         mulx    0*8($nptr),%rax,%r10
990         adcx    %rax,$bptr              # discarded
991         adox    %r11,%r10
992         mulx    1*8($nptr),%rax,%r11
993         adcx    %rax,%r10
994         adox    %r12,%r11
995         .byte   0xc4,0x62,0xfb,0xf6,0xa1,0x10,0x00,0x00,0x00    # mulx  2*8($nptr),%rax,%r12
996         mov     48(%rsp),$bptr          # counter value
997         mov     %r10,-4*8($tptr)
998         adcx    %rax,%r11
999         adox    %r13,%r12
1000         mulx    3*8($nptr),%rax,%r15
1001          mov    $bi,%rdx
1002         mov     %r11,-3*8($tptr)
1003         adcx    %rax,%r12
1004         adox    $zero,%r15              # of=0
1005         lea     4*8($nptr),$nptr
1006         mov     %r12,-2*8($tptr)
1007
1008         jmp     .Lmulx4x_1st
1009
1010 .align  32
1011 .Lmulx4x_1st:
1012         adcx    $zero,%r15              # cf=0, modulo-scheduled
1013         mulx    0*8($aptr),%r10,%rax    # a[4]*b[0]
1014         adcx    %r14,%r10
1015         mulx    1*8($aptr),%r11,%r14    # a[5]*b[0]
1016         adcx    %rax,%r11
1017         mulx    2*8($aptr),%r12,%rax    # ...
1018         adcx    %r14,%r12
1019         mulx    3*8($aptr),%r13,%r14
1020          .byte  0x67,0x67
1021          mov    $mi,%rdx
1022         adcx    %rax,%r13
1023         adcx    $zero,%r14              # cf=0
1024         lea     4*8($aptr),$aptr
1025         lea     4*8($tptr),$tptr
1026
1027         adox    %r15,%r10
1028         mulx    0*8($nptr),%rax,%r15
1029         adcx    %rax,%r10
1030         adox    %r15,%r11
1031         mulx    1*8($nptr),%rax,%r15
1032         adcx    %rax,%r11
1033         adox    %r15,%r12
1034         mulx    2*8($nptr),%rax,%r15
1035         mov     %r10,-5*8($tptr)
1036         adcx    %rax,%r12
1037         mov     %r11,-4*8($tptr)
1038         adox    %r15,%r13
1039         mulx    3*8($nptr),%rax,%r15
1040          mov    $bi,%rdx
1041         mov     %r12,-3*8($tptr)
1042         adcx    %rax,%r13
1043         adox    $zero,%r15
1044         lea     4*8($nptr),$nptr
1045         mov     %r13,-2*8($tptr)
1046
1047         dec     $bptr                   # of=0, pass cf
1048         jnz     .Lmulx4x_1st
1049
1050         mov     0(%rsp),$num            # load num
1051         mov     8(%rsp),$bptr           # re-load &b[i]
1052         adc     $zero,%r15              # modulo-scheduled
1053         add     %r15,%r14
1054         sbb     %r15,%r15               # top-most carry
1055         mov     %r14,-1*8($tptr)
1056         jmp     .Lmulx4x_outer
1057
1058 .align  32
1059 .Lmulx4x_outer:
1060         mov     ($bptr),%rdx            # b[i]
1061         lea     8($bptr),$bptr          # b++
1062         sub     $num,$aptr              # rewind $aptr
1063         mov     %r15,($tptr)            # save top-most carry
1064         lea     64+4*8(%rsp),$tptr
1065         sub     $num,$nptr              # rewind $nptr
1066
1067         mulx    0*8($aptr),$mi,%r11     # a[0]*b[i]
1068         xor     %ebp,%ebp               # xor   $zero,$zero     # cf=0, of=0
1069         mov     %rdx,$bi
1070         mulx    1*8($aptr),%r14,%r12    # a[1]*b[i]
1071         adox    -4*8($tptr),$mi
1072         adcx    %r14,%r11
1073         mulx    2*8($aptr),%r15,%r13    # ...
1074         adox    -3*8($tptr),%r11
1075         adcx    %r15,%r12
1076         adox    $zero,%r12
1077         adcx    $zero,%r13
1078
1079         mov     $bptr,8(%rsp)           # off-load &b[i]
1080         .byte   0x67
1081         mov     $mi,%r15
1082         imulq   24(%rsp),$mi            # "t[0]"*n0
1083         xor     %ebp,%ebp               # xor   $zero,$zero     # cf=0, of=0
1084
1085         mulx    3*8($aptr),%rax,%r14
1086          mov    $mi,%rdx
1087         adox    -2*8($tptr),%r12
1088         adcx    %rax,%r13
1089         adox    -1*8($tptr),%r13
1090         adcx    $zero,%r14
1091         lea     4*8($aptr),$aptr
1092         adox    $zero,%r14
1093
1094         mulx    0*8($nptr),%rax,%r10
1095         adcx    %rax,%r15               # discarded
1096         adox    %r11,%r10
1097         mulx    1*8($nptr),%rax,%r11
1098         adcx    %rax,%r10
1099         adox    %r12,%r11
1100         mulx    2*8($nptr),%rax,%r12
1101         mov     %r10,-4*8($tptr)
1102         adcx    %rax,%r11
1103         adox    %r13,%r12
1104         mulx    3*8($nptr),%rax,%r15
1105          mov    $bi,%rdx
1106         mov     %r11,-3*8($tptr)
1107         lea     4*8($nptr),$nptr
1108         adcx    %rax,%r12
1109         adox    $zero,%r15              # of=0
1110         mov     48(%rsp),$bptr          # counter value
1111         mov     %r12,-2*8($tptr)
1112
1113         jmp     .Lmulx4x_inner
1114
1115 .align  32
1116 .Lmulx4x_inner:
1117         mulx    0*8($aptr),%r10,%rax    # a[4]*b[i]
1118         adcx    $zero,%r15              # cf=0, modulo-scheduled
1119         adox    %r14,%r10
1120         mulx    1*8($aptr),%r11,%r14    # a[5]*b[i]
1121         adcx    0*8($tptr),%r10
1122         adox    %rax,%r11
1123         mulx    2*8($aptr),%r12,%rax    # ...
1124         adcx    1*8($tptr),%r11
1125         adox    %r14,%r12
1126         mulx    3*8($aptr),%r13,%r14
1127          mov    $mi,%rdx
1128         adcx    2*8($tptr),%r12
1129         adox    %rax,%r13
1130         adcx    3*8($tptr),%r13
1131         adox    $zero,%r14              # of=0
1132         lea     4*8($aptr),$aptr
1133         lea     4*8($tptr),$tptr
1134         adcx    $zero,%r14              # cf=0
1135
1136         adox    %r15,%r10
1137         mulx    0*8($nptr),%rax,%r15
1138         adcx    %rax,%r10
1139         adox    %r15,%r11
1140         mulx    1*8($nptr),%rax,%r15
1141         adcx    %rax,%r11
1142         adox    %r15,%r12
1143         mulx    2*8($nptr),%rax,%r15
1144         mov     %r10,-5*8($tptr)
1145         adcx    %rax,%r12
1146         adox    %r15,%r13
1147         mulx    3*8($nptr),%rax,%r15
1148          mov    $bi,%rdx
1149         mov     %r11,-4*8($tptr)
1150         mov     %r12,-3*8($tptr)
1151         adcx    %rax,%r13
1152         adox    $zero,%r15
1153         lea     4*8($nptr),$nptr
1154         mov     %r13,-2*8($tptr)
1155
1156         dec     $bptr                   # of=0, pass cf
1157         jnz     .Lmulx4x_inner
1158
1159         mov     0(%rsp),$num            # load num
1160         mov     8(%rsp),$bptr           # re-load &b[i]
1161         adc     $zero,%r15              # modulo-scheduled
1162         sub     0*8($tptr),$zero        # pull top-most carry
1163         adc     %r15,%r14
1164         sbb     %r15,%r15               # top-most carry
1165         mov     %r14,-1*8($tptr)
1166
1167         cmp     16(%rsp),$bptr
1168         jne     .Lmulx4x_outer
1169
1170         lea     64(%rsp),$tptr
1171         sub     $num,$nptr              # rewind $nptr
1172         neg     %r15
1173         mov     $num,%rdx
1174         shr     \$3+2,$num              # %cf=0
1175         mov     32(%rsp),$rptr          # restore rp
1176         jmp     .Lmulx4x_sub
1177
1178 .align  32
1179 .Lmulx4x_sub:
1180         mov     8*0($tptr),%r11
1181         mov     8*1($tptr),%r12
1182         mov     8*2($tptr),%r13
1183         mov     8*3($tptr),%r14
1184         lea     8*4($tptr),$tptr
1185         sbb     8*0($nptr),%r11
1186         sbb     8*1($nptr),%r12
1187         sbb     8*2($nptr),%r13
1188         sbb     8*3($nptr),%r14
1189         lea     8*4($nptr),$nptr
1190         mov     %r11,8*0($rptr)
1191         mov     %r12,8*1($rptr)
1192         mov     %r13,8*2($rptr)
1193         mov     %r14,8*3($rptr)
1194         lea     8*4($rptr),$rptr
1195         dec     $num                    # preserves %cf
1196         jnz     .Lmulx4x_sub
1197
1198         sbb     \$0,%r15                # top-most carry
1199         lea     64(%rsp),$tptr
1200         sub     %rdx,$rptr              # rewind
1201
1202         movq    %r15,%xmm1
1203         pxor    %xmm0,%xmm0
1204         pshufd  \$0,%xmm1,%xmm1
1205         mov     40(%rsp),%rsi           # restore %rsp
1206         jmp     .Lmulx4x_cond_copy
1207
1208 .align  32
1209 .Lmulx4x_cond_copy:
1210         movdqa  16*0($tptr),%xmm2
1211         movdqa  16*1($tptr),%xmm3
1212         lea     16*2($tptr),$tptr
1213         movdqu  16*0($rptr),%xmm4
1214         movdqu  16*1($rptr),%xmm5
1215         lea     16*2($rptr),$rptr
1216         movdqa  %xmm0,-16*2($tptr)      # zero tp
1217         movdqa  %xmm0,-16*1($tptr)
1218         pcmpeqd %xmm1,%xmm0
1219         pand    %xmm1,%xmm2
1220         pand    %xmm1,%xmm3
1221         pand    %xmm0,%xmm4
1222         pand    %xmm0,%xmm5
1223         pxor    %xmm0,%xmm0
1224         por     %xmm2,%xmm4
1225         por     %xmm3,%xmm5
1226         movdqu  %xmm4,-16*2($rptr)
1227         movdqu  %xmm5,-16*1($rptr)
1228         sub     \$32,%rdx
1229         jnz     .Lmulx4x_cond_copy
1230
1231         mov     %rdx,($tptr)
1232
1233         mov     \$1,%rax
1234         mov     -48(%rsi),%r15
1235         mov     -40(%rsi),%r14
1236         mov     -32(%rsi),%r13
1237         mov     -24(%rsi),%r12
1238         mov     -16(%rsi),%rbp
1239         mov     -8(%rsi),%rbx
1240         lea     (%rsi),%rsp
1241 .Lmulx4x_epilogue:
1242         ret
1243 .size   bn_mulx4x_mont,.-bn_mulx4x_mont
1244 ___
1245 }}}
1246 $code.=<<___;
1247 .asciz  "Montgomery Multiplication for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
1248 .align  16
1249 ___
1250
1251 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1252 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
1253 if ($win64) {
1254 $rec="%rcx";
1255 $frame="%rdx";
1256 $context="%r8";
1257 $disp="%r9";
1258
1259 $code.=<<___;
1260 .extern __imp_RtlVirtualUnwind
1261 .type   mul_handler,\@abi-omnipotent
1262 .align  16
1263 mul_handler:
1264         push    %rsi
1265         push    %rdi
1266         push    %rbx
1267         push    %rbp
1268         push    %r12
1269         push    %r13
1270         push    %r14
1271         push    %r15
1272         pushfq
1273         sub     \$64,%rsp
1274
1275         mov     120($context),%rax      # pull context->Rax
1276         mov     248($context),%rbx      # pull context->Rip
1277
1278         mov     8($disp),%rsi           # disp->ImageBase
1279         mov     56($disp),%r11          # disp->HandlerData
1280
1281         mov     0(%r11),%r10d           # HandlerData[0]
1282         lea     (%rsi,%r10),%r10        # end of prologue label
1283         cmp     %r10,%rbx               # context->Rip<end of prologue label
1284         jb      .Lcommon_seh_tail
1285
1286         mov     152($context),%rax      # pull context->Rsp
1287
1288         mov     4(%r11),%r10d           # HandlerData[1]
1289         lea     (%rsi,%r10),%r10        # epilogue label
1290         cmp     %r10,%rbx               # context->Rip>=epilogue label
1291         jae     .Lcommon_seh_tail
1292
1293         mov     192($context),%r10      # pull $num
1294         mov     8(%rax,%r10,8),%rax     # pull saved stack pointer
1295         lea     48(%rax),%rax
1296
1297         mov     -8(%rax),%rbx
1298         mov     -16(%rax),%rbp
1299         mov     -24(%rax),%r12
1300         mov     -32(%rax),%r13
1301         mov     -40(%rax),%r14
1302         mov     -48(%rax),%r15
1303         mov     %rbx,144($context)      # restore context->Rbx
1304         mov     %rbp,160($context)      # restore context->Rbp
1305         mov     %r12,216($context)      # restore context->R12
1306         mov     %r13,224($context)      # restore context->R13
1307         mov     %r14,232($context)      # restore context->R14
1308         mov     %r15,240($context)      # restore context->R15
1309
1310         jmp     .Lcommon_seh_tail
1311 .size   mul_handler,.-mul_handler
1312
1313 .type   sqr_handler,\@abi-omnipotent
1314 .align  16
1315 sqr_handler:
1316         push    %rsi
1317         push    %rdi
1318         push    %rbx
1319         push    %rbp
1320         push    %r12
1321         push    %r13
1322         push    %r14
1323         push    %r15
1324         pushfq
1325         sub     \$64,%rsp
1326
1327         mov     120($context),%rax      # pull context->Rax
1328         mov     248($context),%rbx      # pull context->Rip
1329
1330         mov     8($disp),%rsi           # disp->ImageBase
1331         mov     56($disp),%r11          # disp->HandlerData
1332
1333         mov     0(%r11),%r10d           # HandlerData[0]
1334         lea     (%rsi,%r10),%r10        # end of prologue label
1335         cmp     %r10,%rbx               # context->Rip<.Lsqr_body
1336         jb      .Lcommon_seh_tail
1337
1338         mov     152($context),%rax      # pull context->Rsp
1339
1340         mov     4(%r11),%r10d           # HandlerData[1]
1341         lea     (%rsi,%r10),%r10        # epilogue label
1342         cmp     %r10,%rbx               # context->Rip>=.Lsqr_epilogue
1343         jae     .Lcommon_seh_tail
1344
1345         mov     40(%rax),%rax           # pull saved stack pointer
1346
1347         mov     -8(%rax),%rbx
1348         mov     -16(%rax),%rbp
1349         mov     -24(%rax),%r12
1350         mov     -32(%rax),%r13
1351         mov     -40(%rax),%r14
1352         mov     -48(%rax),%r15
1353         mov     %rbx,144($context)      # restore context->Rbx
1354         mov     %rbp,160($context)      # restore context->Rbp
1355         mov     %r12,216($context)      # restore context->R12
1356         mov     %r13,224($context)      # restore context->R13
1357         mov     %r14,232($context)      # restore context->R14
1358         mov     %r15,240($context)      # restore context->R15
1359
1360 .Lcommon_seh_tail:
1361         mov     8(%rax),%rdi
1362         mov     16(%rax),%rsi
1363         mov     %rax,152($context)      # restore context->Rsp
1364         mov     %rsi,168($context)      # restore context->Rsi
1365         mov     %rdi,176($context)      # restore context->Rdi
1366
1367         mov     40($disp),%rdi          # disp->ContextRecord
1368         mov     $context,%rsi           # context
1369         mov     \$154,%ecx              # sizeof(CONTEXT)
1370         .long   0xa548f3fc              # cld; rep movsq
1371
1372         mov     $disp,%rsi
1373         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
1374         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
1375         mov     0(%rsi),%r8             # arg3, disp->ControlPc
1376         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
1377         mov     40(%rsi),%r10           # disp->ContextRecord
1378         lea     56(%rsi),%r11           # &disp->HandlerData
1379         lea     24(%rsi),%r12           # &disp->EstablisherFrame
1380         mov     %r10,32(%rsp)           # arg5
1381         mov     %r11,40(%rsp)           # arg6
1382         mov     %r12,48(%rsp)           # arg7
1383         mov     %rcx,56(%rsp)           # arg8, (NULL)
1384         call    *__imp_RtlVirtualUnwind(%rip)
1385
1386         mov     \$1,%eax                # ExceptionContinueSearch
1387         add     \$64,%rsp
1388         popfq
1389         pop     %r15
1390         pop     %r14
1391         pop     %r13
1392         pop     %r12
1393         pop     %rbp
1394         pop     %rbx
1395         pop     %rdi
1396         pop     %rsi
1397         ret
1398 .size   sqr_handler,.-sqr_handler
1399
1400 .section        .pdata
1401 .align  4
1402         .rva    .LSEH_begin_bn_mul_mont
1403         .rva    .LSEH_end_bn_mul_mont
1404         .rva    .LSEH_info_bn_mul_mont
1405
1406         .rva    .LSEH_begin_bn_mul4x_mont
1407         .rva    .LSEH_end_bn_mul4x_mont
1408         .rva    .LSEH_info_bn_mul4x_mont
1409
1410         .rva    .LSEH_begin_bn_sqr8x_mont
1411         .rva    .LSEH_end_bn_sqr8x_mont
1412         .rva    .LSEH_info_bn_sqr8x_mont
1413 ___
1414 $code.=<<___ if ($addx);
1415         .rva    .LSEH_begin_bn_mulx4x_mont
1416         .rva    .LSEH_end_bn_mulx4x_mont
1417         .rva    .LSEH_info_bn_mulx4x_mont
1418 ___
1419 $code.=<<___;
1420 .section        .xdata
1421 .align  8
1422 .LSEH_info_bn_mul_mont:
1423         .byte   9,0,0,0
1424         .rva    mul_handler
1425         .rva    .Lmul_body,.Lmul_epilogue       # HandlerData[]
1426 .LSEH_info_bn_mul4x_mont:
1427         .byte   9,0,0,0
1428         .rva    mul_handler
1429         .rva    .Lmul4x_body,.Lmul4x_epilogue   # HandlerData[]
1430 .LSEH_info_bn_sqr8x_mont:
1431         .byte   9,0,0,0
1432         .rva    sqr_handler
1433         .rva    .Lsqr8x_body,.Lsqr8x_epilogue   # HandlerData[]
1434 ___
1435 $code.=<<___ if ($addx);
1436 .LSEH_info_bn_mulx4x_mont:
1437         .byte   9,0,0,0
1438         .rva    sqr_handler
1439         .rva    .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[]
1440 ___
1441 }
1442
1443 print $code;
1444 close STDOUT;