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