ec/asm/ecp_nistz256-x86_64.pl: add CFI directives.
[oweals/openssl.git] / crypto / ec / asm / ecp_nistz256-x86_64.pl
1 #! /usr/bin/env perl
2 # Copyright 2014-2016 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 #                                                                            #
12 # Copyright 2014 Intel Corporation                                           #
13 #                                                                            #
14 # Licensed under the Apache License, Version 2.0 (the "License");            #
15 # you may not use this file except in compliance with the License.           #
16 # You may obtain a copy of the License at                                    #
17 #                                                                            #
18 #    http://www.apache.org/licenses/LICENSE-2.0                              #
19 #                                                                            #
20 # Unless required by applicable law or agreed to in writing, software        #
21 # distributed under the License is distributed on an "AS IS" BASIS,          #
22 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
23 # See the License for the specific language governing permissions and        #
24 # limitations under the License.                                             #
25 #                                                                            #
26 ##############################################################################
27 #                                                                            #
28 #  Developers and authors:                                                   #
29 #  Shay Gueron (1, 2), and Vlad Krasnov (1)                                  #
30 #  (1) Intel Corporation, Israel Development Center                          #
31 #  (2) University of Haifa                                                   #
32 #  Reference:                                                                #
33 #  S.Gueron and V.Krasnov, "Fast Prime Field Elliptic Curve Cryptography with#
34 #                           256 Bit Primes"                                  #
35 #                                                                            #
36 ##############################################################################
37
38 # Further optimization by <appro@openssl.org>:
39 #
40 #               this/original   with/without -DECP_NISTZ256_ASM(*)
41 # Opteron       +12-49%         +110-150%
42 # Bulldozer     +14-45%         +175-210%
43 # P4            +18-46%         n/a :-(
44 # Westmere      +12-34%         +80-87%
45 # Sandy Bridge  +9-35%          +110-120%
46 # Ivy Bridge    +9-35%          +110-125%
47 # Haswell       +8-37%          +140-160%
48 # Broadwell     +18-58%         +145-210%
49 # Atom          +15-50%         +130-180%
50 # VIA Nano      +43-160%        +300-480%
51 #
52 # (*)   "without -DECP_NISTZ256_ASM" refers to build with
53 #       "enable-ec_nistp_64_gcc_128";
54 #
55 # Ranges denote minimum and maximum improvement coefficients depending
56 # on benchmark. Lower coefficients are for ECDSA sign, relatively fastest
57 # server-side operation. Keep in mind that +100% means 2x improvement.
58
59 $flavour = shift;
60 $output  = shift;
61 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
62
63 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
64
65 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
66 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
67 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
68 die "can't locate x86_64-xlate.pl";
69
70 open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
71 *STDOUT=*OUT;
72
73 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
74                 =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
75         $avx = ($1>=2.19) + ($1>=2.22);
76         $addx = ($1>=2.23);
77 }
78
79 if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
80             `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
81         $avx = ($1>=2.09) + ($1>=2.10);
82         $addx = ($1>=2.10);
83 }
84
85 if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
86             `ml64 2>&1` =~ /Version ([0-9]+)\./) {
87         $avx = ($1>=10) + ($1>=11);
88         $addx = ($1>=12);
89 }
90
91 if (!$addx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9])\.([0-9]+)/) {
92         my $ver = $2 + $3/100.0;        # 3.1->3.01, 3.10->3.10
93         $avx = ($ver>=3.0) + ($ver>=3.01);
94         $addx = ($ver>=3.03);
95 }
96
97 $code.=<<___;
98 .text
99 .extern OPENSSL_ia32cap_P
100
101 # The polynomial
102 .align 64
103 .Lpoly:
104 .quad 0xffffffffffffffff, 0x00000000ffffffff, 0x0000000000000000, 0xffffffff00000001
105
106 # 2^512 mod P precomputed for NIST P256 polynomial
107 .LRR:
108 .quad 0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd
109
110 .LOne:
111 .long 1,1,1,1,1,1,1,1
112 .LTwo:
113 .long 2,2,2,2,2,2,2,2
114 .LThree:
115 .long 3,3,3,3,3,3,3,3
116 .LONE_mont:
117 .quad 0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe
118 ___
119
120 {
121 ################################################################################
122 # void ecp_nistz256_mul_by_2(uint64_t res[4], uint64_t a[4]);
123
124 my ($a0,$a1,$a2,$a3)=map("%r$_",(8..11));
125 my ($t0,$t1,$t2,$t3,$t4)=("%rax","%rdx","%rcx","%r12","%r13");
126 my ($r_ptr,$a_ptr,$b_ptr)=("%rdi","%rsi","%rdx");
127
128 $code.=<<___;
129
130 .globl  ecp_nistz256_mul_by_2
131 .type   ecp_nistz256_mul_by_2,\@function,2
132 .align  64
133 ecp_nistz256_mul_by_2:
134 .cfi_startproc
135         push    %r12
136 .cfi_push       %r12
137         push    %r13
138 .cfi_push       %r13
139 .Lmul_by_2_body:
140
141         mov     8*0($a_ptr), $a0
142         xor     $t4,$t4
143         mov     8*1($a_ptr), $a1
144         add     $a0, $a0                # a0:a3+a0:a3
145         mov     8*2($a_ptr), $a2
146         adc     $a1, $a1
147         mov     8*3($a_ptr), $a3
148         lea     .Lpoly(%rip), $a_ptr
149          mov    $a0, $t0
150         adc     $a2, $a2
151         adc     $a3, $a3
152          mov    $a1, $t1
153         adc     \$0, $t4
154
155         sub     8*0($a_ptr), $a0
156          mov    $a2, $t2
157         sbb     8*1($a_ptr), $a1
158         sbb     8*2($a_ptr), $a2
159          mov    $a3, $t3
160         sbb     8*3($a_ptr), $a3
161         sbb     \$0, $t4
162
163         cmovc   $t0, $a0
164         cmovc   $t1, $a1
165         mov     $a0, 8*0($r_ptr)
166         cmovc   $t2, $a2
167         mov     $a1, 8*1($r_ptr)
168         cmovc   $t3, $a3
169         mov     $a2, 8*2($r_ptr)
170         mov     $a3, 8*3($r_ptr)
171
172         mov     0(%rsp),%r13
173 .cfi_restore    %r13
174         mov     8(%rsp),%r12
175 .cfi_restore    %r12
176         lea     16(%rsp),%rsp
177 .cfi_adjust_cfa_offset  -16
178 .Lmul_by_2_epilogue:
179         ret
180 .cfi_endproc
181 .size   ecp_nistz256_mul_by_2,.-ecp_nistz256_mul_by_2
182
183 ################################################################################
184 # void ecp_nistz256_div_by_2(uint64_t res[4], uint64_t a[4]);
185 .globl  ecp_nistz256_div_by_2
186 .type   ecp_nistz256_div_by_2,\@function,2
187 .align  32
188 ecp_nistz256_div_by_2:
189 .cfi_startproc
190         push    %r12
191 .cfi_push       %r12
192         push    %r13
193 .cfi_push       %r13
194 .Ldiv_by_2_body:
195
196         mov     8*0($a_ptr), $a0
197         mov     8*1($a_ptr), $a1
198         mov     8*2($a_ptr), $a2
199          mov    $a0, $t0
200         mov     8*3($a_ptr), $a3
201         lea     .Lpoly(%rip), $a_ptr
202
203          mov    $a1, $t1
204         xor     $t4, $t4
205         add     8*0($a_ptr), $a0
206          mov    $a2, $t2
207         adc     8*1($a_ptr), $a1
208         adc     8*2($a_ptr), $a2
209          mov    $a3, $t3
210         adc     8*3($a_ptr), $a3
211         adc     \$0, $t4
212         xor     $a_ptr, $a_ptr          # borrow $a_ptr
213         test    \$1, $t0
214
215         cmovz   $t0, $a0
216         cmovz   $t1, $a1
217         cmovz   $t2, $a2
218         cmovz   $t3, $a3
219         cmovz   $a_ptr, $t4
220
221         mov     $a1, $t0                # a0:a3>>1
222         shr     \$1, $a0
223         shl     \$63, $t0
224         mov     $a2, $t1
225         shr     \$1, $a1
226         or      $t0, $a0
227         shl     \$63, $t1
228         mov     $a3, $t2
229         shr     \$1, $a2
230         or      $t1, $a1
231         shl     \$63, $t2
232         shr     \$1, $a3
233         shl     \$63, $t4
234         or      $t2, $a2
235         or      $t4, $a3
236
237         mov     $a0, 8*0($r_ptr)
238         mov     $a1, 8*1($r_ptr)
239         mov     $a2, 8*2($r_ptr)
240         mov     $a3, 8*3($r_ptr)
241
242         mov     0(%rsp),%r13
243 .cfi_restore    %r13
244         mov     8(%rsp),%r12
245 .cfi_restore    %r12
246         lea     16(%rsp),%rsp
247 .cfi_adjust_cfa_offset  -16
248 .Ldiv_by_2_epilogue:
249         ret
250 .cfi_endproc
251 .size   ecp_nistz256_div_by_2,.-ecp_nistz256_div_by_2
252
253 ################################################################################
254 # void ecp_nistz256_mul_by_3(uint64_t res[4], uint64_t a[4]);
255 .globl  ecp_nistz256_mul_by_3
256 .type   ecp_nistz256_mul_by_3,\@function,2
257 .align  32
258 ecp_nistz256_mul_by_3:
259 .cfi_startproc
260         push    %r12
261 .cfi_push       %r12
262         push    %r13
263 .cfi_push       %r13
264 .Lmul_by_3_body:
265
266         mov     8*0($a_ptr), $a0
267         xor     $t4, $t4
268         mov     8*1($a_ptr), $a1
269         add     $a0, $a0                # a0:a3+a0:a3
270         mov     8*2($a_ptr), $a2
271         adc     $a1, $a1
272         mov     8*3($a_ptr), $a3
273          mov    $a0, $t0
274         adc     $a2, $a2
275         adc     $a3, $a3
276          mov    $a1, $t1
277         adc     \$0, $t4
278
279         sub     \$-1, $a0
280          mov    $a2, $t2
281         sbb     .Lpoly+8*1(%rip), $a1
282         sbb     \$0, $a2
283          mov    $a3, $t3
284         sbb     .Lpoly+8*3(%rip), $a3
285         sbb     \$0, $t4
286
287         cmovc   $t0, $a0
288         cmovc   $t1, $a1
289         cmovc   $t2, $a2
290         cmovc   $t3, $a3
291
292         xor     $t4, $t4
293         add     8*0($a_ptr), $a0        # a0:a3+=a_ptr[0:3]
294         adc     8*1($a_ptr), $a1
295          mov    $a0, $t0
296         adc     8*2($a_ptr), $a2
297         adc     8*3($a_ptr), $a3
298          mov    $a1, $t1
299         adc     \$0, $t4
300
301         sub     \$-1, $a0
302          mov    $a2, $t2
303         sbb     .Lpoly+8*1(%rip), $a1
304         sbb     \$0, $a2
305          mov    $a3, $t3
306         sbb     .Lpoly+8*3(%rip), $a3
307         sbb     \$0, $t4
308
309         cmovc   $t0, $a0
310         cmovc   $t1, $a1
311         mov     $a0, 8*0($r_ptr)
312         cmovc   $t2, $a2
313         mov     $a1, 8*1($r_ptr)
314         cmovc   $t3, $a3
315         mov     $a2, 8*2($r_ptr)
316         mov     $a3, 8*3($r_ptr)
317
318         mov     0(%rsp),%r13
319 .cfi_restore    %r13
320         mov     8(%rsp),%r12
321 .cfi_restore    %r12
322         lea     16(%rsp),%rsp
323 .cfi_adjust_cfa_offset  -16
324 .Lmul_by_3_epilogue:
325         ret
326 .cfi_endproc
327 .size   ecp_nistz256_mul_by_3,.-ecp_nistz256_mul_by_3
328
329 ################################################################################
330 # void ecp_nistz256_add(uint64_t res[4], uint64_t a[4], uint64_t b[4]);
331 .globl  ecp_nistz256_add
332 .type   ecp_nistz256_add,\@function,3
333 .align  32
334 ecp_nistz256_add:
335 .cfi_startproc
336         push    %r12
337 .cfi_push       %r12
338         push    %r13
339 .cfi_push       %r13
340 .Ladd_body:
341
342         mov     8*0($a_ptr), $a0
343         xor     $t4, $t4
344         mov     8*1($a_ptr), $a1
345         mov     8*2($a_ptr), $a2
346         mov     8*3($a_ptr), $a3
347         lea     .Lpoly(%rip), $a_ptr
348
349         add     8*0($b_ptr), $a0
350         adc     8*1($b_ptr), $a1
351          mov    $a0, $t0
352         adc     8*2($b_ptr), $a2
353         adc     8*3($b_ptr), $a3
354          mov    $a1, $t1
355         adc     \$0, $t4
356
357         sub     8*0($a_ptr), $a0
358          mov    $a2, $t2
359         sbb     8*1($a_ptr), $a1
360         sbb     8*2($a_ptr), $a2
361          mov    $a3, $t3
362         sbb     8*3($a_ptr), $a3
363         sbb     \$0, $t4
364
365         cmovc   $t0, $a0
366         cmovc   $t1, $a1
367         mov     $a0, 8*0($r_ptr)
368         cmovc   $t2, $a2
369         mov     $a1, 8*1($r_ptr)
370         cmovc   $t3, $a3
371         mov     $a2, 8*2($r_ptr)
372         mov     $a3, 8*3($r_ptr)
373
374         mov     0(%rsp),%r13
375 .cfi_restore    %r13
376         mov     8(%rsp),%r12
377 .cfi_restore    %r12
378         lea     16(%rsp),%rsp
379 .cfi_adjust_cfa_offset  -16
380 .Ladd_epilogue:
381         ret
382 .cfi_endproc
383 .size   ecp_nistz256_add,.-ecp_nistz256_add
384
385 ################################################################################
386 # void ecp_nistz256_sub(uint64_t res[4], uint64_t a[4], uint64_t b[4]);
387 .globl  ecp_nistz256_sub
388 .type   ecp_nistz256_sub,\@function,3
389 .align  32
390 ecp_nistz256_sub:
391 .cfi_startproc
392         push    %r12
393 .cfi_push       %r12
394         push    %r13
395 .cfi_push       %r13
396 .Lsub_body:
397
398         mov     8*0($a_ptr), $a0
399         xor     $t4, $t4
400         mov     8*1($a_ptr), $a1
401         mov     8*2($a_ptr), $a2
402         mov     8*3($a_ptr), $a3
403         lea     .Lpoly(%rip), $a_ptr
404
405         sub     8*0($b_ptr), $a0
406         sbb     8*1($b_ptr), $a1
407          mov    $a0, $t0
408         sbb     8*2($b_ptr), $a2
409         sbb     8*3($b_ptr), $a3
410          mov    $a1, $t1
411         sbb     \$0, $t4
412
413         add     8*0($a_ptr), $a0
414          mov    $a2, $t2
415         adc     8*1($a_ptr), $a1
416         adc     8*2($a_ptr), $a2
417          mov    $a3, $t3
418         adc     8*3($a_ptr), $a3
419         test    $t4, $t4
420
421         cmovz   $t0, $a0
422         cmovz   $t1, $a1
423         mov     $a0, 8*0($r_ptr)
424         cmovz   $t2, $a2
425         mov     $a1, 8*1($r_ptr)
426         cmovz   $t3, $a3
427         mov     $a2, 8*2($r_ptr)
428         mov     $a3, 8*3($r_ptr)
429
430         mov     0(%rsp),%r13
431 .cfi_restore    %r13
432         mov     8(%rsp),%r12
433 .cfi_restore    %r12
434         lea     16(%rsp),%rsp
435 .cfi_adjust_cfa_offset  -16
436 .Lsub_epilogue:
437         ret
438 .cfi_endproc
439 .size   ecp_nistz256_sub,.-ecp_nistz256_sub
440
441 ################################################################################
442 # void ecp_nistz256_neg(uint64_t res[4], uint64_t a[4]);
443 .globl  ecp_nistz256_neg
444 .type   ecp_nistz256_neg,\@function,2
445 .align  32
446 ecp_nistz256_neg:
447 .cfi_startproc
448         push    %r12
449 .cfi_push       %r12
450         push    %r13
451 .cfi_push       %r13
452 .Lneg_body:
453
454         xor     $a0, $a0
455         xor     $a1, $a1
456         xor     $a2, $a2
457         xor     $a3, $a3
458         xor     $t4, $t4
459
460         sub     8*0($a_ptr), $a0
461         sbb     8*1($a_ptr), $a1
462         sbb     8*2($a_ptr), $a2
463          mov    $a0, $t0
464         sbb     8*3($a_ptr), $a3
465         lea     .Lpoly(%rip), $a_ptr
466          mov    $a1, $t1
467         sbb     \$0, $t4
468
469         add     8*0($a_ptr), $a0
470          mov    $a2, $t2
471         adc     8*1($a_ptr), $a1
472         adc     8*2($a_ptr), $a2
473          mov    $a3, $t3
474         adc     8*3($a_ptr), $a3
475         test    $t4, $t4
476
477         cmovz   $t0, $a0
478         cmovz   $t1, $a1
479         mov     $a0, 8*0($r_ptr)
480         cmovz   $t2, $a2
481         mov     $a1, 8*1($r_ptr)
482         cmovz   $t3, $a3
483         mov     $a2, 8*2($r_ptr)
484         mov     $a3, 8*3($r_ptr)
485
486         mov     0(%rsp),%r13
487 .cfi_restore    %r13
488         mov     8(%rsp),%r12
489 .cfi_restore    %r12
490         lea     16(%rsp),%rsp
491 .cfi_adjust_cfa_offset  -16
492 .Lneg_epilogue:
493         ret
494 .cfi_endproc
495 .size   ecp_nistz256_neg,.-ecp_nistz256_neg
496 ___
497 }
498 {
499 my ($r_ptr,$a_ptr,$b_org,$b_ptr)=("%rdi","%rsi","%rdx","%rbx");
500 my ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("%r$_",(8..15));
501 my ($t0,$t1,$t2,$t3,$t4)=("%rcx","%rbp","%rbx","%rdx","%rax");
502 my ($poly1,$poly3)=($acc6,$acc7);
503
504 $code.=<<___;
505 ################################################################################
506 # void ecp_nistz256_to_mont(
507 #   uint64_t res[4],
508 #   uint64_t in[4]);
509 .globl  ecp_nistz256_to_mont
510 .type   ecp_nistz256_to_mont,\@function,2
511 .align  32
512 ecp_nistz256_to_mont:
513 ___
514 $code.=<<___    if ($addx);
515         mov     \$0x80100, %ecx
516         and     OPENSSL_ia32cap_P+8(%rip), %ecx
517 ___
518 $code.=<<___;
519         lea     .LRR(%rip), $b_org
520         jmp     .Lmul_mont
521 .size   ecp_nistz256_to_mont,.-ecp_nistz256_to_mont
522
523 ################################################################################
524 # void ecp_nistz256_mul_mont(
525 #   uint64_t res[4],
526 #   uint64_t a[4],
527 #   uint64_t b[4]);
528
529 .globl  ecp_nistz256_mul_mont
530 .type   ecp_nistz256_mul_mont,\@function,3
531 .align  32
532 ecp_nistz256_mul_mont:
533 .cfi_startproc
534 ___
535 $code.=<<___    if ($addx);
536         mov     \$0x80100, %ecx
537         and     OPENSSL_ia32cap_P+8(%rip), %ecx
538 ___
539 $code.=<<___;
540 .Lmul_mont:
541         push    %rbp
542 .cfi_push       %rbp
543         push    %rbx
544 .cfi_push       %rbx
545         push    %r12
546 .cfi_push       %r12
547         push    %r13
548 .cfi_push       %r13
549         push    %r14
550 .cfi_push       %r14
551         push    %r15
552 .cfi_push       %r15
553 .Lmul_body:
554 ___
555 $code.=<<___    if ($addx);
556         cmp     \$0x80100, %ecx
557         je      .Lmul_montx
558 ___
559 $code.=<<___;
560         mov     $b_org, $b_ptr
561         mov     8*0($b_org), %rax
562         mov     8*0($a_ptr), $acc1
563         mov     8*1($a_ptr), $acc2
564         mov     8*2($a_ptr), $acc3
565         mov     8*3($a_ptr), $acc4
566
567         call    __ecp_nistz256_mul_montq
568 ___
569 $code.=<<___    if ($addx);
570         jmp     .Lmul_mont_done
571
572 .align  32
573 .Lmul_montx:
574         mov     $b_org, $b_ptr
575         mov     8*0($b_org), %rdx
576         mov     8*0($a_ptr), $acc1
577         mov     8*1($a_ptr), $acc2
578         mov     8*2($a_ptr), $acc3
579         mov     8*3($a_ptr), $acc4
580         lea     -128($a_ptr), $a_ptr    # control u-op density
581
582         call    __ecp_nistz256_mul_montx
583 ___
584 $code.=<<___;
585 .Lmul_mont_done:
586         mov     0(%rsp),%r15
587 .cfi_restore    %r15
588         mov     8(%rsp),%r14
589 .cfi_restore    %r14
590         mov     16(%rsp),%r13
591 .cfi_restore    %r13
592         mov     24(%rsp),%r12
593 .cfi_restore    %r12
594         mov     32(%rsp),%rbx
595 .cfi_restore    %rbx
596         mov     40(%rsp),%rbp
597 .cfi_restore    %rbp
598         lea     48(%rsp),%rsp
599 .cfi_adjust_cfa_offset  -48
600 .Lmul_epilogue:
601         ret
602 .cfi_endproc
603 .size   ecp_nistz256_mul_mont,.-ecp_nistz256_mul_mont
604
605 .type   __ecp_nistz256_mul_montq,\@abi-omnipotent
606 .align  32
607 __ecp_nistz256_mul_montq:
608         ########################################################################
609         # Multiply a by b[0]
610         mov     %rax, $t1
611         mulq    $acc1
612         mov     .Lpoly+8*1(%rip),$poly1
613         mov     %rax, $acc0
614         mov     $t1, %rax
615         mov     %rdx, $acc1
616
617         mulq    $acc2
618         mov     .Lpoly+8*3(%rip),$poly3
619         add     %rax, $acc1
620         mov     $t1, %rax
621         adc     \$0, %rdx
622         mov     %rdx, $acc2
623
624         mulq    $acc3
625         add     %rax, $acc2
626         mov     $t1, %rax
627         adc     \$0, %rdx
628         mov     %rdx, $acc3
629
630         mulq    $acc4
631         add     %rax, $acc3
632          mov    $acc0, %rax
633         adc     \$0, %rdx
634         xor     $acc5, $acc5
635         mov     %rdx, $acc4
636
637         ########################################################################
638         # First reduction step
639         # Basically now we want to multiply acc[0] by p256,
640         # and add the result to the acc.
641         # Due to the special form of p256 we do some optimizations
642         #
643         # acc[0] x p256[0..1] = acc[0] x 2^96 - acc[0]
644         # then we add acc[0] and get acc[0] x 2^96
645
646         mov     $acc0, $t1
647         shl     \$32, $acc0
648         mulq    $poly3
649         shr     \$32, $t1
650         add     $acc0, $acc1            # +=acc[0]<<96
651         adc     $t1, $acc2
652         adc     %rax, $acc3
653          mov    8*1($b_ptr), %rax
654         adc     %rdx, $acc4
655         adc     \$0, $acc5
656         xor     $acc0, $acc0
657
658         ########################################################################
659         # Multiply by b[1]
660         mov     %rax, $t1
661         mulq    8*0($a_ptr)
662         add     %rax, $acc1
663         mov     $t1, %rax
664         adc     \$0, %rdx
665         mov     %rdx, $t0
666
667         mulq    8*1($a_ptr)
668         add     $t0, $acc2
669         adc     \$0, %rdx
670         add     %rax, $acc2
671         mov     $t1, %rax
672         adc     \$0, %rdx
673         mov     %rdx, $t0
674
675         mulq    8*2($a_ptr)
676         add     $t0, $acc3
677         adc     \$0, %rdx
678         add     %rax, $acc3
679         mov     $t1, %rax
680         adc     \$0, %rdx
681         mov     %rdx, $t0
682
683         mulq    8*3($a_ptr)
684         add     $t0, $acc4
685         adc     \$0, %rdx
686         add     %rax, $acc4
687          mov    $acc1, %rax
688         adc     %rdx, $acc5
689         adc     \$0, $acc0
690
691         ########################################################################
692         # Second reduction step
693         mov     $acc1, $t1
694         shl     \$32, $acc1
695         mulq    $poly3
696         shr     \$32, $t1
697         add     $acc1, $acc2
698         adc     $t1, $acc3
699         adc     %rax, $acc4
700          mov    8*2($b_ptr), %rax
701         adc     %rdx, $acc5
702         adc     \$0, $acc0
703         xor     $acc1, $acc1
704
705         ########################################################################
706         # Multiply by b[2]
707         mov     %rax, $t1
708         mulq    8*0($a_ptr)
709         add     %rax, $acc2
710         mov     $t1, %rax
711         adc     \$0, %rdx
712         mov     %rdx, $t0
713
714         mulq    8*1($a_ptr)
715         add     $t0, $acc3
716         adc     \$0, %rdx
717         add     %rax, $acc3
718         mov     $t1, %rax
719         adc     \$0, %rdx
720         mov     %rdx, $t0
721
722         mulq    8*2($a_ptr)
723         add     $t0, $acc4
724         adc     \$0, %rdx
725         add     %rax, $acc4
726         mov     $t1, %rax
727         adc     \$0, %rdx
728         mov     %rdx, $t0
729
730         mulq    8*3($a_ptr)
731         add     $t0, $acc5
732         adc     \$0, %rdx
733         add     %rax, $acc5
734          mov    $acc2, %rax
735         adc     %rdx, $acc0
736         adc     \$0, $acc1
737
738         ########################################################################
739         # Third reduction step
740         mov     $acc2, $t1
741         shl     \$32, $acc2
742         mulq    $poly3
743         shr     \$32, $t1
744         add     $acc2, $acc3
745         adc     $t1, $acc4
746         adc     %rax, $acc5
747          mov    8*3($b_ptr), %rax
748         adc     %rdx, $acc0
749         adc     \$0, $acc1
750         xor     $acc2, $acc2
751
752         ########################################################################
753         # Multiply by b[3]
754         mov     %rax, $t1
755         mulq    8*0($a_ptr)
756         add     %rax, $acc3
757         mov     $t1, %rax
758         adc     \$0, %rdx
759         mov     %rdx, $t0
760
761         mulq    8*1($a_ptr)
762         add     $t0, $acc4
763         adc     \$0, %rdx
764         add     %rax, $acc4
765         mov     $t1, %rax
766         adc     \$0, %rdx
767         mov     %rdx, $t0
768
769         mulq    8*2($a_ptr)
770         add     $t0, $acc5
771         adc     \$0, %rdx
772         add     %rax, $acc5
773         mov     $t1, %rax
774         adc     \$0, %rdx
775         mov     %rdx, $t0
776
777         mulq    8*3($a_ptr)
778         add     $t0, $acc0
779         adc     \$0, %rdx
780         add     %rax, $acc0
781          mov    $acc3, %rax
782         adc     %rdx, $acc1
783         adc     \$0, $acc2
784
785         ########################################################################
786         # Final reduction step
787         mov     $acc3, $t1
788         shl     \$32, $acc3
789         mulq    $poly3
790         shr     \$32, $t1
791         add     $acc3, $acc4
792         adc     $t1, $acc5
793          mov    $acc4, $t0
794         adc     %rax, $acc0
795         adc     %rdx, $acc1
796          mov    $acc5, $t1
797         adc     \$0, $acc2
798
799         ########################################################################
800         # Branch-less conditional subtraction of P
801         sub     \$-1, $acc4             # .Lpoly[0]
802          mov    $acc0, $t2
803         sbb     $poly1, $acc5           # .Lpoly[1]
804         sbb     \$0, $acc0              # .Lpoly[2]
805          mov    $acc1, $t3
806         sbb     $poly3, $acc1           # .Lpoly[3]
807         sbb     \$0, $acc2
808
809         cmovc   $t0, $acc4
810         cmovc   $t1, $acc5
811         mov     $acc4, 8*0($r_ptr)
812         cmovc   $t2, $acc0
813         mov     $acc5, 8*1($r_ptr)
814         cmovc   $t3, $acc1
815         mov     $acc0, 8*2($r_ptr)
816         mov     $acc1, 8*3($r_ptr)
817
818         ret
819 .size   __ecp_nistz256_mul_montq,.-__ecp_nistz256_mul_montq
820
821 ################################################################################
822 # void ecp_nistz256_sqr_mont(
823 #   uint64_t res[4],
824 #   uint64_t a[4]);
825
826 # we optimize the square according to S.Gueron and V.Krasnov,
827 # "Speeding up Big-Number Squaring"
828 .globl  ecp_nistz256_sqr_mont
829 .type   ecp_nistz256_sqr_mont,\@function,2
830 .align  32
831 ecp_nistz256_sqr_mont:
832 .cfi_startproc
833 ___
834 $code.=<<___    if ($addx);
835         mov     \$0x80100, %ecx
836         and     OPENSSL_ia32cap_P+8(%rip), %ecx
837 ___
838 $code.=<<___;
839         push    %rbp
840 .cfi_push       %rbp
841         push    %rbx
842 .cfi_push       %rbx
843         push    %r12
844 .cfi_push       %r12
845         push    %r13
846 .cfi_push       %r13
847         push    %r14
848 .cfi_push       %r14
849         push    %r15
850 .cfi_push       %r15
851 .Lsqr_body:
852 ___
853 $code.=<<___    if ($addx);
854         cmp     \$0x80100, %ecx
855         je      .Lsqr_montx
856 ___
857 $code.=<<___;
858         mov     8*0($a_ptr), %rax
859         mov     8*1($a_ptr), $acc6
860         mov     8*2($a_ptr), $acc7
861         mov     8*3($a_ptr), $acc0
862
863         call    __ecp_nistz256_sqr_montq
864 ___
865 $code.=<<___    if ($addx);
866         jmp     .Lsqr_mont_done
867
868 .align  32
869 .Lsqr_montx:
870         mov     8*0($a_ptr), %rdx
871         mov     8*1($a_ptr), $acc6
872         mov     8*2($a_ptr), $acc7
873         mov     8*3($a_ptr), $acc0
874         lea     -128($a_ptr), $a_ptr    # control u-op density
875
876         call    __ecp_nistz256_sqr_montx
877 ___
878 $code.=<<___;
879 .Lsqr_mont_done:
880         mov     0(%rsp),%r15
881 .cfi_restore    %r15
882         mov     8(%rsp),%r14
883 .cfi_restore    %r14
884         mov     16(%rsp),%r13
885 .cfi_restore    %r13
886         mov     24(%rsp),%r12
887 .cfi_restore    %r12
888         mov     32(%rsp),%rbx
889 .cfi_restore    %rbx
890         mov     40(%rsp),%rbp
891 .cfi_restore    %rbp
892         lea     48(%rsp),%rsp
893 .cfi_adjust_cfa_offset  -48
894 .Lsqr_epilogue:
895         ret
896 .cfi_endproc
897 .size   ecp_nistz256_sqr_mont,.-ecp_nistz256_sqr_mont
898
899 .type   __ecp_nistz256_sqr_montq,\@abi-omnipotent
900 .align  32
901 __ecp_nistz256_sqr_montq:
902         mov     %rax, $acc5
903         mulq    $acc6                   # a[1]*a[0]
904         mov     %rax, $acc1
905         mov     $acc7, %rax
906         mov     %rdx, $acc2
907
908         mulq    $acc5                   # a[0]*a[2]
909         add     %rax, $acc2
910         mov     $acc0, %rax
911         adc     \$0, %rdx
912         mov     %rdx, $acc3
913
914         mulq    $acc5                   # a[0]*a[3]
915         add     %rax, $acc3
916          mov    $acc7, %rax
917         adc     \$0, %rdx
918         mov     %rdx, $acc4
919
920         #################################
921         mulq    $acc6                   # a[1]*a[2]
922         add     %rax, $acc3
923         mov     $acc0, %rax
924         adc     \$0, %rdx
925         mov     %rdx, $t1
926
927         mulq    $acc6                   # a[1]*a[3]
928         add     %rax, $acc4
929          mov    $acc0, %rax
930         adc     \$0, %rdx
931         add     $t1, $acc4
932         mov     %rdx, $acc5
933         adc     \$0, $acc5
934
935         #################################
936         mulq    $acc7                   # a[2]*a[3]
937         xor     $acc7, $acc7
938         add     %rax, $acc5
939          mov    8*0($a_ptr), %rax
940         mov     %rdx, $acc6
941         adc     \$0, $acc6
942
943         add     $acc1, $acc1            # acc1:6<<1
944         adc     $acc2, $acc2
945         adc     $acc3, $acc3
946         adc     $acc4, $acc4
947         adc     $acc5, $acc5
948         adc     $acc6, $acc6
949         adc     \$0, $acc7
950
951         mulq    %rax
952         mov     %rax, $acc0
953         mov     8*1($a_ptr), %rax
954         mov     %rdx, $t0
955
956         mulq    %rax
957         add     $t0, $acc1
958         adc     %rax, $acc2
959         mov     8*2($a_ptr), %rax
960         adc     \$0, %rdx
961         mov     %rdx, $t0
962
963         mulq    %rax
964         add     $t0, $acc3
965         adc     %rax, $acc4
966         mov     8*3($a_ptr), %rax
967         adc     \$0, %rdx
968         mov     %rdx, $t0
969
970         mulq    %rax
971         add     $t0, $acc5
972         adc     %rax, $acc6
973          mov    $acc0, %rax
974         adc     %rdx, $acc7
975
976         mov     .Lpoly+8*1(%rip), $a_ptr
977         mov     .Lpoly+8*3(%rip), $t1
978
979         ##########################################
980         # Now the reduction
981         # First iteration
982         mov     $acc0, $t0
983         shl     \$32, $acc0
984         mulq    $t1
985         shr     \$32, $t0
986         add     $acc0, $acc1            # +=acc[0]<<96
987         adc     $t0, $acc2
988         adc     %rax, $acc3
989          mov    $acc1, %rax
990         adc     \$0, %rdx
991
992         ##########################################
993         # Second iteration
994         mov     $acc1, $t0
995         shl     \$32, $acc1
996         mov     %rdx, $acc0
997         mulq    $t1
998         shr     \$32, $t0
999         add     $acc1, $acc2
1000         adc     $t0, $acc3
1001         adc     %rax, $acc0
1002          mov    $acc2, %rax
1003         adc     \$0, %rdx
1004
1005         ##########################################
1006         # Third iteration
1007         mov     $acc2, $t0
1008         shl     \$32, $acc2
1009         mov     %rdx, $acc1
1010         mulq    $t1
1011         shr     \$32, $t0
1012         add     $acc2, $acc3
1013         adc     $t0, $acc0
1014         adc     %rax, $acc1
1015          mov    $acc3, %rax
1016         adc     \$0, %rdx
1017
1018         ###########################################
1019         # Last iteration
1020         mov     $acc3, $t0
1021         shl     \$32, $acc3
1022         mov     %rdx, $acc2
1023         mulq    $t1
1024         shr     \$32, $t0
1025         add     $acc3, $acc0
1026         adc     $t0, $acc1
1027         adc     %rax, $acc2
1028         adc     \$0, %rdx
1029         xor     $acc3, $acc3
1030
1031         ############################################
1032         # Add the rest of the acc
1033         add     $acc0, $acc4
1034         adc     $acc1, $acc5
1035          mov    $acc4, $acc0
1036         adc     $acc2, $acc6
1037         adc     %rdx, $acc7
1038          mov    $acc5, $acc1
1039         adc     \$0, $acc3
1040
1041         sub     \$-1, $acc4             # .Lpoly[0]
1042          mov    $acc6, $acc2
1043         sbb     $a_ptr, $acc5           # .Lpoly[1]
1044         sbb     \$0, $acc6              # .Lpoly[2]
1045          mov    $acc7, $t0
1046         sbb     $t1, $acc7              # .Lpoly[3]
1047         sbb     \$0, $acc3
1048
1049         cmovc   $acc0, $acc4
1050         cmovc   $acc1, $acc5
1051         mov     $acc4, 8*0($r_ptr)
1052         cmovc   $acc2, $acc6
1053         mov     $acc5, 8*1($r_ptr)
1054         cmovc   $t0, $acc7
1055         mov     $acc6, 8*2($r_ptr)
1056         mov     $acc7, 8*3($r_ptr)
1057
1058         ret
1059 .size   __ecp_nistz256_sqr_montq,.-__ecp_nistz256_sqr_montq
1060 ___
1061
1062 if ($addx) {
1063 $code.=<<___;
1064 .type   __ecp_nistz256_mul_montx,\@abi-omnipotent
1065 .align  32
1066 __ecp_nistz256_mul_montx:
1067         ########################################################################
1068         # Multiply by b[0]
1069         mulx    $acc1, $acc0, $acc1
1070         mulx    $acc2, $t0, $acc2
1071         mov     \$32, $poly1
1072         xor     $acc5, $acc5            # cf=0
1073         mulx    $acc3, $t1, $acc3
1074         mov     .Lpoly+8*3(%rip), $poly3
1075         adc     $t0, $acc1
1076         mulx    $acc4, $t0, $acc4
1077          mov    $acc0, %rdx
1078         adc     $t1, $acc2
1079          shlx   $poly1,$acc0,$t1
1080         adc     $t0, $acc3
1081          shrx   $poly1,$acc0,$t0
1082         adc     \$0, $acc4
1083
1084         ########################################################################
1085         # First reduction step
1086         add     $t1, $acc1
1087         adc     $t0, $acc2
1088
1089         mulx    $poly3, $t0, $t1
1090          mov    8*1($b_ptr), %rdx
1091         adc     $t0, $acc3
1092         adc     $t1, $acc4
1093         adc     \$0, $acc5
1094         xor     $acc0, $acc0            # $acc0=0,cf=0,of=0
1095
1096         ########################################################################
1097         # Multiply by b[1]
1098         mulx    8*0+128($a_ptr), $t0, $t1
1099         adcx    $t0, $acc1
1100         adox    $t1, $acc2
1101
1102         mulx    8*1+128($a_ptr), $t0, $t1
1103         adcx    $t0, $acc2
1104         adox    $t1, $acc3
1105
1106         mulx    8*2+128($a_ptr), $t0, $t1
1107         adcx    $t0, $acc3
1108         adox    $t1, $acc4
1109
1110         mulx    8*3+128($a_ptr), $t0, $t1
1111          mov    $acc1, %rdx
1112         adcx    $t0, $acc4
1113          shlx   $poly1, $acc1, $t0
1114         adox    $t1, $acc5
1115          shrx   $poly1, $acc1, $t1
1116
1117         adcx    $acc0, $acc5
1118         adox    $acc0, $acc0
1119         adc     \$0, $acc0
1120
1121         ########################################################################
1122         # Second reduction step
1123         add     $t0, $acc2
1124         adc     $t1, $acc3
1125
1126         mulx    $poly3, $t0, $t1
1127          mov    8*2($b_ptr), %rdx
1128         adc     $t0, $acc4
1129         adc     $t1, $acc5
1130         adc     \$0, $acc0
1131         xor     $acc1 ,$acc1            # $acc1=0,cf=0,of=0
1132
1133         ########################################################################
1134         # Multiply by b[2]
1135         mulx    8*0+128($a_ptr), $t0, $t1
1136         adcx    $t0, $acc2
1137         adox    $t1, $acc3
1138
1139         mulx    8*1+128($a_ptr), $t0, $t1
1140         adcx    $t0, $acc3
1141         adox    $t1, $acc4
1142
1143         mulx    8*2+128($a_ptr), $t0, $t1
1144         adcx    $t0, $acc4
1145         adox    $t1, $acc5
1146
1147         mulx    8*3+128($a_ptr), $t0, $t1
1148          mov    $acc2, %rdx
1149         adcx    $t0, $acc5
1150          shlx   $poly1, $acc2, $t0
1151         adox    $t1, $acc0
1152          shrx   $poly1, $acc2, $t1
1153
1154         adcx    $acc1, $acc0
1155         adox    $acc1, $acc1
1156         adc     \$0, $acc1
1157
1158         ########################################################################
1159         # Third reduction step
1160         add     $t0, $acc3
1161         adc     $t1, $acc4
1162
1163         mulx    $poly3, $t0, $t1
1164          mov    8*3($b_ptr), %rdx
1165         adc     $t0, $acc5
1166         adc     $t1, $acc0
1167         adc     \$0, $acc1
1168         xor     $acc2, $acc2            # $acc2=0,cf=0,of=0
1169
1170         ########################################################################
1171         # Multiply by b[3]
1172         mulx    8*0+128($a_ptr), $t0, $t1
1173         adcx    $t0, $acc3
1174         adox    $t1, $acc4
1175
1176         mulx    8*1+128($a_ptr), $t0, $t1
1177         adcx    $t0, $acc4
1178         adox    $t1, $acc5
1179
1180         mulx    8*2+128($a_ptr), $t0, $t1
1181         adcx    $t0, $acc5
1182         adox    $t1, $acc0
1183
1184         mulx    8*3+128($a_ptr), $t0, $t1
1185          mov    $acc3, %rdx
1186         adcx    $t0, $acc0
1187          shlx   $poly1, $acc3, $t0
1188         adox    $t1, $acc1
1189          shrx   $poly1, $acc3, $t1
1190
1191         adcx    $acc2, $acc1
1192         adox    $acc2, $acc2
1193         adc     \$0, $acc2
1194
1195         ########################################################################
1196         # Fourth reduction step
1197         add     $t0, $acc4
1198         adc     $t1, $acc5
1199
1200         mulx    $poly3, $t0, $t1
1201          mov    $acc4, $t2
1202         mov     .Lpoly+8*1(%rip), $poly1
1203         adc     $t0, $acc0
1204          mov    $acc5, $t3
1205         adc     $t1, $acc1
1206         adc     \$0, $acc2
1207
1208         ########################################################################
1209         # Branch-less conditional subtraction of P
1210         xor     %eax, %eax
1211          mov    $acc0, $t0
1212         sbb     \$-1, $acc4             # .Lpoly[0]
1213         sbb     $poly1, $acc5           # .Lpoly[1]
1214         sbb     \$0, $acc0              # .Lpoly[2]
1215          mov    $acc1, $t1
1216         sbb     $poly3, $acc1           # .Lpoly[3]
1217         sbb     \$0, $acc2
1218
1219         cmovc   $t2, $acc4
1220         cmovc   $t3, $acc5
1221         mov     $acc4, 8*0($r_ptr)
1222         cmovc   $t0, $acc0
1223         mov     $acc5, 8*1($r_ptr)
1224         cmovc   $t1, $acc1
1225         mov     $acc0, 8*2($r_ptr)
1226         mov     $acc1, 8*3($r_ptr)
1227
1228         ret
1229 .size   __ecp_nistz256_mul_montx,.-__ecp_nistz256_mul_montx
1230
1231 .type   __ecp_nistz256_sqr_montx,\@abi-omnipotent
1232 .align  32
1233 __ecp_nistz256_sqr_montx:
1234         mulx    $acc6, $acc1, $acc2     # a[0]*a[1]
1235         mulx    $acc7, $t0, $acc3       # a[0]*a[2]
1236         xor     %eax, %eax
1237         adc     $t0, $acc2
1238         mulx    $acc0, $t1, $acc4       # a[0]*a[3]
1239          mov    $acc6, %rdx
1240         adc     $t1, $acc3
1241         adc     \$0, $acc4
1242         xor     $acc5, $acc5            # $acc5=0,cf=0,of=0
1243
1244         #################################
1245         mulx    $acc7, $t0, $t1         # a[1]*a[2]
1246         adcx    $t0, $acc3
1247         adox    $t1, $acc4
1248
1249         mulx    $acc0, $t0, $t1         # a[1]*a[3]
1250          mov    $acc7, %rdx
1251         adcx    $t0, $acc4
1252         adox    $t1, $acc5
1253         adc     \$0, $acc5
1254
1255         #################################
1256         mulx    $acc0, $t0, $acc6       # a[2]*a[3]
1257          mov    8*0+128($a_ptr), %rdx
1258         xor     $acc7, $acc7            # $acc7=0,cf=0,of=0
1259          adcx   $acc1, $acc1            # acc1:6<<1
1260         adox    $t0, $acc5
1261          adcx   $acc2, $acc2
1262         adox    $acc7, $acc6            # of=0
1263
1264         mulx    %rdx, $acc0, $t1
1265         mov     8*1+128($a_ptr), %rdx
1266          adcx   $acc3, $acc3
1267         adox    $t1, $acc1
1268          adcx   $acc4, $acc4
1269         mulx    %rdx, $t0, $t4
1270         mov     8*2+128($a_ptr), %rdx
1271          adcx   $acc5, $acc5
1272         adox    $t0, $acc2
1273          adcx   $acc6, $acc6
1274         .byte   0x67
1275         mulx    %rdx, $t0, $t1
1276         mov     8*3+128($a_ptr), %rdx
1277         adox    $t4, $acc3
1278          adcx   $acc7, $acc7
1279         adox    $t0, $acc4
1280          mov    \$32, $a_ptr
1281         adox    $t1, $acc5
1282         .byte   0x67,0x67
1283         mulx    %rdx, $t0, $t4
1284          mov    $acc0, %rdx
1285         adox    $t0, $acc6
1286          shlx   $a_ptr, $acc0, $t0
1287         adox    $t4, $acc7
1288          shrx   $a_ptr, $acc0, $t4
1289          mov    .Lpoly+8*3(%rip), $t1
1290
1291         # reduction step 1
1292         add     $t0, $acc1
1293         adc     $t4, $acc2
1294
1295         mulx    $t1, $t0, $acc0
1296          mov    $acc1, %rdx
1297         adc     $t0, $acc3
1298          shlx   $a_ptr, $acc1, $t0
1299         adc     \$0, $acc0
1300          shrx   $a_ptr, $acc1, $t4
1301
1302         # reduction step 2
1303         add     $t0, $acc2
1304         adc     $t4, $acc3
1305
1306         mulx    $t1, $t0, $acc1
1307          mov    $acc2, %rdx
1308         adc     $t0, $acc0
1309          shlx   $a_ptr, $acc2, $t0
1310         adc     \$0, $acc1
1311          shrx   $a_ptr, $acc2, $t4
1312
1313         # reduction step 3
1314         add     $t0, $acc3
1315         adc     $t4, $acc0
1316
1317         mulx    $t1, $t0, $acc2
1318          mov    $acc3, %rdx
1319         adc     $t0, $acc1
1320          shlx   $a_ptr, $acc3, $t0
1321         adc     \$0, $acc2
1322          shrx   $a_ptr, $acc3, $t4
1323
1324         # reduction step 4
1325         add     $t0, $acc0
1326         adc     $t4, $acc1
1327
1328         mulx    $t1, $t0, $acc3
1329         adc     $t0, $acc2
1330         adc     \$0, $acc3
1331
1332         xor     $t3, $t3                # cf=0
1333         adc     $acc0, $acc4            # accumulate upper half
1334          mov    .Lpoly+8*1(%rip), $a_ptr
1335         adc     $acc1, $acc5
1336          mov    $acc4, $acc0
1337         adc     $acc2, $acc6
1338         adc     $acc3, $acc7
1339          mov    $acc5, $acc1
1340         adc     \$0, $t3
1341
1342         xor     %eax, %eax              # cf=0
1343         sbb     \$-1, $acc4             # .Lpoly[0]
1344          mov    $acc6, $acc2
1345         sbb     $a_ptr, $acc5           # .Lpoly[1]
1346         sbb     \$0, $acc6              # .Lpoly[2]
1347          mov    $acc7, $acc3
1348         sbb     $t1, $acc7              # .Lpoly[3]
1349         sbb     \$0, $t3
1350
1351         cmovc   $acc0, $acc4
1352         cmovc   $acc1, $acc5
1353         mov     $acc4, 8*0($r_ptr)
1354         cmovc   $acc2, $acc6
1355         mov     $acc5, 8*1($r_ptr)
1356         cmovc   $acc3, $acc7
1357         mov     $acc6, 8*2($r_ptr)
1358         mov     $acc7, 8*3($r_ptr)
1359
1360         ret
1361 .size   __ecp_nistz256_sqr_montx,.-__ecp_nistz256_sqr_montx
1362 ___
1363 }
1364 }
1365 {
1366 my ($r_ptr,$in_ptr)=("%rdi","%rsi");
1367 my ($acc0,$acc1,$acc2,$acc3)=map("%r$_",(8..11));
1368 my ($t0,$t1,$t2)=("%rcx","%r12","%r13");
1369
1370 $code.=<<___;
1371 ################################################################################
1372 # void ecp_nistz256_from_mont(
1373 #   uint64_t res[4],
1374 #   uint64_t in[4]);
1375 # This one performs Montgomery multiplication by 1, so we only need the reduction
1376
1377 .globl  ecp_nistz256_from_mont
1378 .type   ecp_nistz256_from_mont,\@function,2
1379 .align  32
1380 ecp_nistz256_from_mont:
1381 .cfi_startproc
1382         push    %r12
1383 .cfi_push       %r12
1384         push    %r13
1385 .cfi_push       %r13
1386 .Lfrom_body:
1387
1388         mov     8*0($in_ptr), %rax
1389         mov     .Lpoly+8*3(%rip), $t2
1390         mov     8*1($in_ptr), $acc1
1391         mov     8*2($in_ptr), $acc2
1392         mov     8*3($in_ptr), $acc3
1393         mov     %rax, $acc0
1394         mov     .Lpoly+8*1(%rip), $t1
1395
1396         #########################################
1397         # First iteration
1398         mov     %rax, $t0
1399         shl     \$32, $acc0
1400         mulq    $t2
1401         shr     \$32, $t0
1402         add     $acc0, $acc1
1403         adc     $t0, $acc2
1404         adc     %rax, $acc3
1405          mov    $acc1, %rax
1406         adc     \$0, %rdx
1407
1408         #########################################
1409         # Second iteration
1410         mov     $acc1, $t0
1411         shl     \$32, $acc1
1412         mov     %rdx, $acc0
1413         mulq    $t2
1414         shr     \$32, $t0
1415         add     $acc1, $acc2
1416         adc     $t0, $acc3
1417         adc     %rax, $acc0
1418          mov    $acc2, %rax
1419         adc     \$0, %rdx
1420
1421         ##########################################
1422         # Third iteration
1423         mov     $acc2, $t0
1424         shl     \$32, $acc2
1425         mov     %rdx, $acc1
1426         mulq    $t2
1427         shr     \$32, $t0
1428         add     $acc2, $acc3
1429         adc     $t0, $acc0
1430         adc     %rax, $acc1
1431          mov    $acc3, %rax
1432         adc     \$0, %rdx
1433
1434         ###########################################
1435         # Last iteration
1436         mov     $acc3, $t0
1437         shl     \$32, $acc3
1438         mov     %rdx, $acc2
1439         mulq    $t2
1440         shr     \$32, $t0
1441         add     $acc3, $acc0
1442         adc     $t0, $acc1
1443          mov    $acc0, $t0
1444         adc     %rax, $acc2
1445          mov    $acc1, $in_ptr
1446         adc     \$0, %rdx
1447
1448         ###########################################
1449         # Branch-less conditional subtraction
1450         sub     \$-1, $acc0
1451          mov    $acc2, %rax
1452         sbb     $t1, $acc1
1453         sbb     \$0, $acc2
1454          mov    %rdx, $acc3
1455         sbb     $t2, %rdx
1456         sbb     $t2, $t2
1457
1458         cmovnz  $t0, $acc0
1459         cmovnz  $in_ptr, $acc1
1460         mov     $acc0, 8*0($r_ptr)
1461         cmovnz  %rax, $acc2
1462         mov     $acc1, 8*1($r_ptr)
1463         cmovz   %rdx, $acc3
1464         mov     $acc2, 8*2($r_ptr)
1465         mov     $acc3, 8*3($r_ptr)
1466
1467         mov     0(%rsp),%r13
1468 .cfi_restore    %r13
1469         mov     8(%rsp),%r12
1470 .cfi_restore    %r12
1471         lea     16(%rsp),%rsp
1472 .cfi_adjust_cfa_offset  -16
1473 .Lfrom_epilogue:
1474         ret
1475 .cfi_endproc
1476 .size   ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
1477 ___
1478 }
1479 {
1480 my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
1481 my ($ONE,$INDEX,$Ra,$Rb,$Rc,$Rd,$Re,$Rf)=map("%xmm$_",(0..7));
1482 my ($M0,$T0a,$T0b,$T0c,$T0d,$T0e,$T0f,$TMP0)=map("%xmm$_",(8..15));
1483 my ($M1,$T2a,$T2b,$TMP2,$M2,$T2a,$T2b,$TMP2)=map("%xmm$_",(8..15));
1484
1485 $code.=<<___;
1486 ################################################################################
1487 # void ecp_nistz256_scatter_w5(uint64_t *val, uint64_t *in_t, int index);
1488 .globl  ecp_nistz256_scatter_w5
1489 .type   ecp_nistz256_scatter_w5,\@abi-omnipotent
1490 .align  32
1491 ecp_nistz256_scatter_w5:
1492         lea     -3($index,$index,2), $index
1493         movdqa  0x00($in_t), %xmm0
1494         shl     \$5, $index
1495         movdqa  0x10($in_t), %xmm1
1496         movdqa  0x20($in_t), %xmm2
1497         movdqa  0x30($in_t), %xmm3
1498         movdqa  0x40($in_t), %xmm4
1499         movdqa  0x50($in_t), %xmm5
1500         movdqa  %xmm0, 0x00($val,$index)
1501         movdqa  %xmm1, 0x10($val,$index)
1502         movdqa  %xmm2, 0x20($val,$index)
1503         movdqa  %xmm3, 0x30($val,$index)
1504         movdqa  %xmm4, 0x40($val,$index)
1505         movdqa  %xmm5, 0x50($val,$index)
1506
1507         ret
1508 .size   ecp_nistz256_scatter_w5,.-ecp_nistz256_scatter_w5
1509
1510 ################################################################################
1511 # void ecp_nistz256_gather_w5(uint64_t *val, uint64_t *in_t, int index);
1512 .globl  ecp_nistz256_gather_w5
1513 .type   ecp_nistz256_gather_w5,\@abi-omnipotent
1514 .align  32
1515 ecp_nistz256_gather_w5:
1516 ___
1517 $code.=<<___    if ($avx>1);
1518         mov     OPENSSL_ia32cap_P+8(%rip), %eax
1519         test    \$`1<<5`, %eax
1520         jnz     .Lavx2_gather_w5
1521 ___
1522 $code.=<<___    if ($win64);
1523         lea     -0x88(%rsp), %rax
1524 .LSEH_begin_ecp_nistz256_gather_w5:
1525         .byte   0x48,0x8d,0x60,0xe0             #lea    -0x20(%rax), %rsp
1526         .byte   0x0f,0x29,0x70,0xe0             #movaps %xmm6, -0x20(%rax)
1527         .byte   0x0f,0x29,0x78,0xf0             #movaps %xmm7, -0x10(%rax)
1528         .byte   0x44,0x0f,0x29,0x00             #movaps %xmm8, 0(%rax)
1529         .byte   0x44,0x0f,0x29,0x48,0x10        #movaps %xmm9, 0x10(%rax)
1530         .byte   0x44,0x0f,0x29,0x50,0x20        #movaps %xmm10, 0x20(%rax)
1531         .byte   0x44,0x0f,0x29,0x58,0x30        #movaps %xmm11, 0x30(%rax)
1532         .byte   0x44,0x0f,0x29,0x60,0x40        #movaps %xmm12, 0x40(%rax)
1533         .byte   0x44,0x0f,0x29,0x68,0x50        #movaps %xmm13, 0x50(%rax)
1534         .byte   0x44,0x0f,0x29,0x70,0x60        #movaps %xmm14, 0x60(%rax)
1535         .byte   0x44,0x0f,0x29,0x78,0x70        #movaps %xmm15, 0x70(%rax)
1536 ___
1537 $code.=<<___;
1538         movdqa  .LOne(%rip), $ONE
1539         movd    $index, $INDEX
1540
1541         pxor    $Ra, $Ra
1542         pxor    $Rb, $Rb
1543         pxor    $Rc, $Rc
1544         pxor    $Rd, $Rd
1545         pxor    $Re, $Re
1546         pxor    $Rf, $Rf
1547
1548         movdqa  $ONE, $M0
1549         pshufd  \$0, $INDEX, $INDEX
1550
1551         mov     \$16, %rax
1552 .Lselect_loop_sse_w5:
1553
1554         movdqa  $M0, $TMP0
1555         paddd   $ONE, $M0
1556         pcmpeqd $INDEX, $TMP0
1557
1558         movdqa  16*0($in_t), $T0a
1559         movdqa  16*1($in_t), $T0b
1560         movdqa  16*2($in_t), $T0c
1561         movdqa  16*3($in_t), $T0d
1562         movdqa  16*4($in_t), $T0e
1563         movdqa  16*5($in_t), $T0f
1564         lea 16*6($in_t), $in_t
1565
1566         pand    $TMP0, $T0a
1567         pand    $TMP0, $T0b
1568         por     $T0a, $Ra
1569         pand    $TMP0, $T0c
1570         por     $T0b, $Rb
1571         pand    $TMP0, $T0d
1572         por     $T0c, $Rc
1573         pand    $TMP0, $T0e
1574         por     $T0d, $Rd
1575         pand    $TMP0, $T0f
1576         por     $T0e, $Re
1577         por     $T0f, $Rf
1578
1579         dec     %rax
1580         jnz     .Lselect_loop_sse_w5
1581
1582         movdqu  $Ra, 16*0($val)
1583         movdqu  $Rb, 16*1($val)
1584         movdqu  $Rc, 16*2($val)
1585         movdqu  $Rd, 16*3($val)
1586         movdqu  $Re, 16*4($val)
1587         movdqu  $Rf, 16*5($val)
1588 ___
1589 $code.=<<___    if ($win64);
1590         movaps  (%rsp), %xmm6
1591         movaps  0x10(%rsp), %xmm7
1592         movaps  0x20(%rsp), %xmm8
1593         movaps  0x30(%rsp), %xmm9
1594         movaps  0x40(%rsp), %xmm10
1595         movaps  0x50(%rsp), %xmm11
1596         movaps  0x60(%rsp), %xmm12
1597         movaps  0x70(%rsp), %xmm13
1598         movaps  0x80(%rsp), %xmm14
1599         movaps  0x90(%rsp), %xmm15
1600         lea     0xa8(%rsp), %rsp
1601 ___
1602 $code.=<<___;
1603         ret
1604 .LSEH_end_ecp_nistz256_gather_w5:
1605 .size   ecp_nistz256_gather_w5,.-ecp_nistz256_gather_w5
1606
1607 ################################################################################
1608 # void ecp_nistz256_scatter_w7(uint64_t *val, uint64_t *in_t, int index);
1609 .globl  ecp_nistz256_scatter_w7
1610 .type   ecp_nistz256_scatter_w7,\@abi-omnipotent
1611 .align  32
1612 ecp_nistz256_scatter_w7:
1613         movdqu  0x00($in_t), %xmm0
1614         shl     \$6, $index
1615         movdqu  0x10($in_t), %xmm1
1616         movdqu  0x20($in_t), %xmm2
1617         movdqu  0x30($in_t), %xmm3
1618         movdqa  %xmm0, 0x00($val,$index)
1619         movdqa  %xmm1, 0x10($val,$index)
1620         movdqa  %xmm2, 0x20($val,$index)
1621         movdqa  %xmm3, 0x30($val,$index)
1622
1623         ret
1624 .size   ecp_nistz256_scatter_w7,.-ecp_nistz256_scatter_w7
1625
1626 ################################################################################
1627 # void ecp_nistz256_gather_w7(uint64_t *val, uint64_t *in_t, int index);
1628 .globl  ecp_nistz256_gather_w7
1629 .type   ecp_nistz256_gather_w7,\@abi-omnipotent
1630 .align  32
1631 ecp_nistz256_gather_w7:
1632 ___
1633 $code.=<<___    if ($avx>1);
1634         mov     OPENSSL_ia32cap_P+8(%rip), %eax
1635         test    \$`1<<5`, %eax
1636         jnz     .Lavx2_gather_w7
1637 ___
1638 $code.=<<___    if ($win64);
1639         lea     -0x88(%rsp), %rax
1640 .LSEH_begin_ecp_nistz256_gather_w7:
1641         .byte   0x48,0x8d,0x60,0xe0             #lea    -0x20(%rax), %rsp
1642         .byte   0x0f,0x29,0x70,0xe0             #movaps %xmm6, -0x20(%rax)
1643         .byte   0x0f,0x29,0x78,0xf0             #movaps %xmm7, -0x10(%rax)
1644         .byte   0x44,0x0f,0x29,0x00             #movaps %xmm8, 0(%rax)
1645         .byte   0x44,0x0f,0x29,0x48,0x10        #movaps %xmm9, 0x10(%rax)
1646         .byte   0x44,0x0f,0x29,0x50,0x20        #movaps %xmm10, 0x20(%rax)
1647         .byte   0x44,0x0f,0x29,0x58,0x30        #movaps %xmm11, 0x30(%rax)
1648         .byte   0x44,0x0f,0x29,0x60,0x40        #movaps %xmm12, 0x40(%rax)
1649         .byte   0x44,0x0f,0x29,0x68,0x50        #movaps %xmm13, 0x50(%rax)
1650         .byte   0x44,0x0f,0x29,0x70,0x60        #movaps %xmm14, 0x60(%rax)
1651         .byte   0x44,0x0f,0x29,0x78,0x70        #movaps %xmm15, 0x70(%rax)
1652 ___
1653 $code.=<<___;
1654         movdqa  .LOne(%rip), $M0
1655         movd    $index, $INDEX
1656
1657         pxor    $Ra, $Ra
1658         pxor    $Rb, $Rb
1659         pxor    $Rc, $Rc
1660         pxor    $Rd, $Rd
1661
1662         movdqa  $M0, $ONE
1663         pshufd  \$0, $INDEX, $INDEX
1664         mov     \$64, %rax
1665
1666 .Lselect_loop_sse_w7:
1667         movdqa  $M0, $TMP0
1668         paddd   $ONE, $M0
1669         movdqa  16*0($in_t), $T0a
1670         movdqa  16*1($in_t), $T0b
1671         pcmpeqd $INDEX, $TMP0
1672         movdqa  16*2($in_t), $T0c
1673         movdqa  16*3($in_t), $T0d
1674         lea     16*4($in_t), $in_t
1675
1676         pand    $TMP0, $T0a
1677         pand    $TMP0, $T0b
1678         por     $T0a, $Ra
1679         pand    $TMP0, $T0c
1680         por     $T0b, $Rb
1681         pand    $TMP0, $T0d
1682         por     $T0c, $Rc
1683         prefetcht0      255($in_t)
1684         por     $T0d, $Rd
1685
1686         dec     %rax
1687         jnz     .Lselect_loop_sse_w7
1688
1689         movdqu  $Ra, 16*0($val)
1690         movdqu  $Rb, 16*1($val)
1691         movdqu  $Rc, 16*2($val)
1692         movdqu  $Rd, 16*3($val)
1693 ___
1694 $code.=<<___    if ($win64);
1695         movaps  (%rsp), %xmm6
1696         movaps  0x10(%rsp), %xmm7
1697         movaps  0x20(%rsp), %xmm8
1698         movaps  0x30(%rsp), %xmm9
1699         movaps  0x40(%rsp), %xmm10
1700         movaps  0x50(%rsp), %xmm11
1701         movaps  0x60(%rsp), %xmm12
1702         movaps  0x70(%rsp), %xmm13
1703         movaps  0x80(%rsp), %xmm14
1704         movaps  0x90(%rsp), %xmm15
1705         lea     0xa8(%rsp), %rsp
1706 ___
1707 $code.=<<___;
1708         ret
1709 .LSEH_end_ecp_nistz256_gather_w7:
1710 .size   ecp_nistz256_gather_w7,.-ecp_nistz256_gather_w7
1711 ___
1712 }
1713 if ($avx>1) {
1714 my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
1715 my ($TWO,$INDEX,$Ra,$Rb,$Rc)=map("%ymm$_",(0..4));
1716 my ($M0,$T0a,$T0b,$T0c,$TMP0)=map("%ymm$_",(5..9));
1717 my ($M1,$T1a,$T1b,$T1c,$TMP1)=map("%ymm$_",(10..14));
1718
1719 $code.=<<___;
1720 ################################################################################
1721 # void ecp_nistz256_avx2_gather_w5(uint64_t *val, uint64_t *in_t, int index);
1722 .type   ecp_nistz256_avx2_gather_w5,\@abi-omnipotent
1723 .align  32
1724 ecp_nistz256_avx2_gather_w5:
1725 .Lavx2_gather_w5:
1726         vzeroupper
1727 ___
1728 $code.=<<___    if ($win64);
1729         lea     -0x88(%rsp), %rax
1730         mov     %rsp,%r11
1731 .LSEH_begin_ecp_nistz256_avx2_gather_w5:
1732         .byte   0x48,0x8d,0x60,0xe0             # lea   -0x20(%rax), %rsp
1733         .byte   0xc5,0xf8,0x29,0x70,0xe0        # vmovaps %xmm6, -0x20(%rax)
1734         .byte   0xc5,0xf8,0x29,0x78,0xf0        # vmovaps %xmm7, -0x10(%rax)
1735         .byte   0xc5,0x78,0x29,0x40,0x00        # vmovaps %xmm8, 8(%rax)
1736         .byte   0xc5,0x78,0x29,0x48,0x10        # vmovaps %xmm9, 0x10(%rax)
1737         .byte   0xc5,0x78,0x29,0x50,0x20        # vmovaps %xmm10, 0x20(%rax)
1738         .byte   0xc5,0x78,0x29,0x58,0x30        # vmovaps %xmm11, 0x30(%rax)
1739         .byte   0xc5,0x78,0x29,0x60,0x40        # vmovaps %xmm12, 0x40(%rax)
1740         .byte   0xc5,0x78,0x29,0x68,0x50        # vmovaps %xmm13, 0x50(%rax)
1741         .byte   0xc5,0x78,0x29,0x70,0x60        # vmovaps %xmm14, 0x60(%rax)
1742         .byte   0xc5,0x78,0x29,0x78,0x70        # vmovaps %xmm15, 0x70(%rax)
1743 ___
1744 $code.=<<___;
1745         vmovdqa .LTwo(%rip), $TWO
1746
1747         vpxor   $Ra, $Ra, $Ra
1748         vpxor   $Rb, $Rb, $Rb
1749         vpxor   $Rc, $Rc, $Rc
1750
1751         vmovdqa .LOne(%rip), $M0
1752         vmovdqa .LTwo(%rip), $M1
1753
1754         vmovd   $index, %xmm1
1755         vpermd  $INDEX, $Ra, $INDEX
1756
1757         mov     \$8, %rax
1758 .Lselect_loop_avx2_w5:
1759
1760         vmovdqa 32*0($in_t), $T0a
1761         vmovdqa 32*1($in_t), $T0b
1762         vmovdqa 32*2($in_t), $T0c
1763
1764         vmovdqa 32*3($in_t), $T1a
1765         vmovdqa 32*4($in_t), $T1b
1766         vmovdqa 32*5($in_t), $T1c
1767
1768         vpcmpeqd        $INDEX, $M0, $TMP0
1769         vpcmpeqd        $INDEX, $M1, $TMP1
1770
1771         vpaddd  $TWO, $M0, $M0
1772         vpaddd  $TWO, $M1, $M1
1773         lea     32*6($in_t), $in_t
1774
1775         vpand   $TMP0, $T0a, $T0a
1776         vpand   $TMP0, $T0b, $T0b
1777         vpand   $TMP0, $T0c, $T0c
1778         vpand   $TMP1, $T1a, $T1a
1779         vpand   $TMP1, $T1b, $T1b
1780         vpand   $TMP1, $T1c, $T1c
1781
1782         vpxor   $T0a, $Ra, $Ra
1783         vpxor   $T0b, $Rb, $Rb
1784         vpxor   $T0c, $Rc, $Rc
1785         vpxor   $T1a, $Ra, $Ra
1786         vpxor   $T1b, $Rb, $Rb
1787         vpxor   $T1c, $Rc, $Rc
1788
1789         dec %rax
1790         jnz .Lselect_loop_avx2_w5
1791
1792         vmovdqu $Ra, 32*0($val)
1793         vmovdqu $Rb, 32*1($val)
1794         vmovdqu $Rc, 32*2($val)
1795         vzeroupper
1796 ___
1797 $code.=<<___    if ($win64);
1798         movaps  (%rsp), %xmm6
1799         movaps  0x10(%rsp), %xmm7
1800         movaps  0x20(%rsp), %xmm8
1801         movaps  0x30(%rsp), %xmm9
1802         movaps  0x40(%rsp), %xmm10
1803         movaps  0x50(%rsp), %xmm11
1804         movaps  0x60(%rsp), %xmm12
1805         movaps  0x70(%rsp), %xmm13
1806         movaps  0x80(%rsp), %xmm14
1807         movaps  0x90(%rsp), %xmm15
1808         lea     (%r11), %rsp
1809 ___
1810 $code.=<<___;
1811         ret
1812 .LSEH_end_ecp_nistz256_avx2_gather_w5:
1813 .size   ecp_nistz256_avx2_gather_w5,.-ecp_nistz256_avx2_gather_w5
1814 ___
1815 }
1816 if ($avx>1) {
1817 my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
1818 my ($THREE,$INDEX,$Ra,$Rb)=map("%ymm$_",(0..3));
1819 my ($M0,$T0a,$T0b,$TMP0)=map("%ymm$_",(4..7));
1820 my ($M1,$T1a,$T1b,$TMP1)=map("%ymm$_",(8..11));
1821 my ($M2,$T2a,$T2b,$TMP2)=map("%ymm$_",(12..15));
1822
1823 $code.=<<___;
1824
1825 ################################################################################
1826 # void ecp_nistz256_avx2_gather_w7(uint64_t *val, uint64_t *in_t, int index);
1827 .globl  ecp_nistz256_avx2_gather_w7
1828 .type   ecp_nistz256_avx2_gather_w7,\@abi-omnipotent
1829 .align  32
1830 ecp_nistz256_avx2_gather_w7:
1831 .Lavx2_gather_w7:
1832         vzeroupper
1833 ___
1834 $code.=<<___    if ($win64);
1835         mov     %rsp,%r11
1836         lea     -0x88(%rsp), %rax
1837 .LSEH_begin_ecp_nistz256_avx2_gather_w7:
1838         .byte   0x48,0x8d,0x60,0xe0             # lea   -0x20(%rax), %rsp
1839         .byte   0xc5,0xf8,0x29,0x70,0xe0        # vmovaps %xmm6, -0x20(%rax)
1840         .byte   0xc5,0xf8,0x29,0x78,0xf0        # vmovaps %xmm7, -0x10(%rax)
1841         .byte   0xc5,0x78,0x29,0x40,0x00        # vmovaps %xmm8, 8(%rax)
1842         .byte   0xc5,0x78,0x29,0x48,0x10        # vmovaps %xmm9, 0x10(%rax)
1843         .byte   0xc5,0x78,0x29,0x50,0x20        # vmovaps %xmm10, 0x20(%rax)
1844         .byte   0xc5,0x78,0x29,0x58,0x30        # vmovaps %xmm11, 0x30(%rax)
1845         .byte   0xc5,0x78,0x29,0x60,0x40        # vmovaps %xmm12, 0x40(%rax)
1846         .byte   0xc5,0x78,0x29,0x68,0x50        # vmovaps %xmm13, 0x50(%rax)
1847         .byte   0xc5,0x78,0x29,0x70,0x60        # vmovaps %xmm14, 0x60(%rax)
1848         .byte   0xc5,0x78,0x29,0x78,0x70        # vmovaps %xmm15, 0x70(%rax)
1849 ___
1850 $code.=<<___;
1851         vmovdqa .LThree(%rip), $THREE
1852
1853         vpxor   $Ra, $Ra, $Ra
1854         vpxor   $Rb, $Rb, $Rb
1855
1856         vmovdqa .LOne(%rip), $M0
1857         vmovdqa .LTwo(%rip), $M1
1858         vmovdqa .LThree(%rip), $M2
1859
1860         vmovd   $index, %xmm1
1861         vpermd  $INDEX, $Ra, $INDEX
1862         # Skip index = 0, because it is implicitly the point at infinity
1863
1864         mov     \$21, %rax
1865 .Lselect_loop_avx2_w7:
1866
1867         vmovdqa 32*0($in_t), $T0a
1868         vmovdqa 32*1($in_t), $T0b
1869
1870         vmovdqa 32*2($in_t), $T1a
1871         vmovdqa 32*3($in_t), $T1b
1872
1873         vmovdqa 32*4($in_t), $T2a
1874         vmovdqa 32*5($in_t), $T2b
1875
1876         vpcmpeqd        $INDEX, $M0, $TMP0
1877         vpcmpeqd        $INDEX, $M1, $TMP1
1878         vpcmpeqd        $INDEX, $M2, $TMP2
1879
1880         vpaddd  $THREE, $M0, $M0
1881         vpaddd  $THREE, $M1, $M1
1882         vpaddd  $THREE, $M2, $M2
1883         lea     32*6($in_t), $in_t
1884
1885         vpand   $TMP0, $T0a, $T0a
1886         vpand   $TMP0, $T0b, $T0b
1887         vpand   $TMP1, $T1a, $T1a
1888         vpand   $TMP1, $T1b, $T1b
1889         vpand   $TMP2, $T2a, $T2a
1890         vpand   $TMP2, $T2b, $T2b
1891
1892         vpxor   $T0a, $Ra, $Ra
1893         vpxor   $T0b, $Rb, $Rb
1894         vpxor   $T1a, $Ra, $Ra
1895         vpxor   $T1b, $Rb, $Rb
1896         vpxor   $T2a, $Ra, $Ra
1897         vpxor   $T2b, $Rb, $Rb
1898
1899         dec %rax
1900         jnz .Lselect_loop_avx2_w7
1901
1902
1903         vmovdqa 32*0($in_t), $T0a
1904         vmovdqa 32*1($in_t), $T0b
1905
1906         vpcmpeqd        $INDEX, $M0, $TMP0
1907
1908         vpand   $TMP0, $T0a, $T0a
1909         vpand   $TMP0, $T0b, $T0b
1910
1911         vpxor   $T0a, $Ra, $Ra
1912         vpxor   $T0b, $Rb, $Rb
1913
1914         vmovdqu $Ra, 32*0($val)
1915         vmovdqu $Rb, 32*1($val)
1916         vzeroupper
1917 ___
1918 $code.=<<___    if ($win64);
1919         movaps  (%rsp), %xmm6
1920         movaps  0x10(%rsp), %xmm7
1921         movaps  0x20(%rsp), %xmm8
1922         movaps  0x30(%rsp), %xmm9
1923         movaps  0x40(%rsp), %xmm10
1924         movaps  0x50(%rsp), %xmm11
1925         movaps  0x60(%rsp), %xmm12
1926         movaps  0x70(%rsp), %xmm13
1927         movaps  0x80(%rsp), %xmm14
1928         movaps  0x90(%rsp), %xmm15
1929         lea     (%r11), %rsp
1930 ___
1931 $code.=<<___;
1932         ret
1933 .LSEH_end_ecp_nistz256_avx2_gather_w7:
1934 .size   ecp_nistz256_avx2_gather_w7,.-ecp_nistz256_avx2_gather_w7
1935 ___
1936 } else {
1937 $code.=<<___;
1938 .globl  ecp_nistz256_avx2_gather_w7
1939 .type   ecp_nistz256_avx2_gather_w7,\@function,3
1940 .align  32
1941 ecp_nistz256_avx2_gather_w7:
1942         .byte   0x0f,0x0b       # ud2
1943         ret
1944 .size   ecp_nistz256_avx2_gather_w7,.-ecp_nistz256_avx2_gather_w7
1945 ___
1946 }
1947 {{{
1948 ########################################################################
1949 # This block implements higher level point_double, point_add and
1950 # point_add_affine. The key to performance in this case is to allow
1951 # out-of-order execution logic to overlap computations from next step
1952 # with tail processing from current step. By using tailored calling
1953 # sequence we minimize inter-step overhead to give processor better
1954 # shot at overlapping operations...
1955 #
1956 # You will notice that input data is copied to stack. Trouble is that
1957 # there are no registers to spare for holding original pointers and
1958 # reloading them, pointers, would create undesired dependencies on
1959 # effective addresses calculation paths. In other words it's too done
1960 # to favour out-of-order execution logic.
1961 #                                               <appro@openssl.org>
1962
1963 my ($r_ptr,$a_ptr,$b_org,$b_ptr)=("%rdi","%rsi","%rdx","%rbx");
1964 my ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("%r$_",(8..15));
1965 my ($t0,$t1,$t2,$t3,$t4)=("%rax","%rbp","%rcx",$acc4,$acc4);
1966 my ($poly1,$poly3)=($acc6,$acc7);
1967
1968 sub load_for_mul () {
1969 my ($a,$b,$src0) = @_;
1970 my $bias = $src0 eq "%rax" ? 0 : -128;
1971
1972 "       mov     $b, $src0
1973         lea     $b, $b_ptr
1974         mov     8*0+$a, $acc1
1975         mov     8*1+$a, $acc2
1976         lea     $bias+$a, $a_ptr
1977         mov     8*2+$a, $acc3
1978         mov     8*3+$a, $acc4"
1979 }
1980
1981 sub load_for_sqr () {
1982 my ($a,$src0) = @_;
1983 my $bias = $src0 eq "%rax" ? 0 : -128;
1984
1985 "       mov     8*0+$a, $src0
1986         mov     8*1+$a, $acc6
1987         lea     $bias+$a, $a_ptr
1988         mov     8*2+$a, $acc7
1989         mov     8*3+$a, $acc0"
1990 }
1991
1992                                                                         {
1993 ########################################################################
1994 # operate in 4-5-0-1 "name space" that matches multiplication output
1995 #
1996 my ($a0,$a1,$a2,$a3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
1997
1998 $code.=<<___;
1999 .type   __ecp_nistz256_add_toq,\@abi-omnipotent
2000 .align  32
2001 __ecp_nistz256_add_toq:
2002         xor     $t4,$t4
2003         add     8*0($b_ptr), $a0
2004         adc     8*1($b_ptr), $a1
2005          mov    $a0, $t0
2006         adc     8*2($b_ptr), $a2
2007         adc     8*3($b_ptr), $a3
2008          mov    $a1, $t1
2009         adc     \$0, $t4
2010
2011         sub     \$-1, $a0
2012          mov    $a2, $t2
2013         sbb     $poly1, $a1
2014         sbb     \$0, $a2
2015          mov    $a3, $t3
2016         sbb     $poly3, $a3
2017         sbb     \$0, $t4
2018
2019         cmovc   $t0, $a0
2020         cmovc   $t1, $a1
2021         mov     $a0, 8*0($r_ptr)
2022         cmovc   $t2, $a2
2023         mov     $a1, 8*1($r_ptr)
2024         cmovc   $t3, $a3
2025         mov     $a2, 8*2($r_ptr)
2026         mov     $a3, 8*3($r_ptr)
2027
2028         ret
2029 .size   __ecp_nistz256_add_toq,.-__ecp_nistz256_add_toq
2030
2031 .type   __ecp_nistz256_sub_fromq,\@abi-omnipotent
2032 .align  32
2033 __ecp_nistz256_sub_fromq:
2034         sub     8*0($b_ptr), $a0
2035         sbb     8*1($b_ptr), $a1
2036          mov    $a0, $t0
2037         sbb     8*2($b_ptr), $a2
2038         sbb     8*3($b_ptr), $a3
2039          mov    $a1, $t1
2040         sbb     $t4, $t4
2041
2042         add     \$-1, $a0
2043          mov    $a2, $t2
2044         adc     $poly1, $a1
2045         adc     \$0, $a2
2046          mov    $a3, $t3
2047         adc     $poly3, $a3
2048         test    $t4, $t4
2049
2050         cmovz   $t0, $a0
2051         cmovz   $t1, $a1
2052         mov     $a0, 8*0($r_ptr)
2053         cmovz   $t2, $a2
2054         mov     $a1, 8*1($r_ptr)
2055         cmovz   $t3, $a3
2056         mov     $a2, 8*2($r_ptr)
2057         mov     $a3, 8*3($r_ptr)
2058
2059         ret
2060 .size   __ecp_nistz256_sub_fromq,.-__ecp_nistz256_sub_fromq
2061
2062 .type   __ecp_nistz256_subq,\@abi-omnipotent
2063 .align  32
2064 __ecp_nistz256_subq:
2065         sub     $a0, $t0
2066         sbb     $a1, $t1
2067          mov    $t0, $a0
2068         sbb     $a2, $t2
2069         sbb     $a3, $t3
2070          mov    $t1, $a1
2071         sbb     $t4, $t4
2072
2073         add     \$-1, $t0
2074          mov    $t2, $a2
2075         adc     $poly1, $t1
2076         adc     \$0, $t2
2077          mov    $t3, $a3
2078         adc     $poly3, $t3
2079         test    $t4, $t4
2080
2081         cmovnz  $t0, $a0
2082         cmovnz  $t1, $a1
2083         cmovnz  $t2, $a2
2084         cmovnz  $t3, $a3
2085
2086         ret
2087 .size   __ecp_nistz256_subq,.-__ecp_nistz256_subq
2088
2089 .type   __ecp_nistz256_mul_by_2q,\@abi-omnipotent
2090 .align  32
2091 __ecp_nistz256_mul_by_2q:
2092         xor     $t4, $t4
2093         add     $a0, $a0                # a0:a3+a0:a3
2094         adc     $a1, $a1
2095          mov    $a0, $t0
2096         adc     $a2, $a2
2097         adc     $a3, $a3
2098          mov    $a1, $t1
2099         adc     \$0, $t4
2100
2101         sub     \$-1, $a0
2102          mov    $a2, $t2
2103         sbb     $poly1, $a1
2104         sbb     \$0, $a2
2105          mov    $a3, $t3
2106         sbb     $poly3, $a3
2107         sbb     \$0, $t4
2108
2109         cmovc   $t0, $a0
2110         cmovc   $t1, $a1
2111         mov     $a0, 8*0($r_ptr)
2112         cmovc   $t2, $a2
2113         mov     $a1, 8*1($r_ptr)
2114         cmovc   $t3, $a3
2115         mov     $a2, 8*2($r_ptr)
2116         mov     $a3, 8*3($r_ptr)
2117
2118         ret
2119 .size   __ecp_nistz256_mul_by_2q,.-__ecp_nistz256_mul_by_2q
2120 ___
2121                                                                         }
2122 sub gen_double () {
2123     my $x = shift;
2124     my ($src0,$sfx,$bias);
2125     my ($S,$M,$Zsqr,$in_x,$tmp0)=map(32*$_,(0..4));
2126
2127     if ($x ne "x") {
2128         $src0 = "%rax";
2129         $sfx  = "";
2130         $bias = 0;
2131
2132 $code.=<<___;
2133 .globl  ecp_nistz256_point_double
2134 .type   ecp_nistz256_point_double,\@function,2
2135 .align  32
2136 ecp_nistz256_point_double:
2137 .cfi_startproc
2138 ___
2139 $code.=<<___    if ($addx);
2140         mov     \$0x80100, %ecx
2141         and     OPENSSL_ia32cap_P+8(%rip), %ecx
2142         cmp     \$0x80100, %ecx
2143         je      .Lpoint_doublex
2144 ___
2145     } else {
2146         $src0 = "%rdx";
2147         $sfx  = "x";
2148         $bias = 128;
2149
2150 $code.=<<___;
2151 .type   ecp_nistz256_point_doublex,\@function,2
2152 .align  32
2153 ecp_nistz256_point_doublex:
2154 .cfi_startproc
2155 .Lpoint_doublex:
2156 ___
2157     }
2158 $code.=<<___;
2159         push    %rbp
2160 .cfi_push       %rbp
2161         push    %rbx
2162 .cfi_push       %rbx
2163         push    %r12
2164 .cfi_push       %r12
2165         push    %r13
2166 .cfi_push       %r13
2167         push    %r14
2168 .cfi_push       %r14
2169         push    %r15
2170 .cfi_push       %r15
2171         sub     \$32*5+8, %rsp
2172 .cfi_adjust_cfa_offset  32*5+8
2173 .Lpoint_double${x}_body:
2174
2175 .Lpoint_double_shortcut$x:
2176         movdqu  0x00($a_ptr), %xmm0             # copy  *(P256_POINT *)$a_ptr.x
2177         mov     $a_ptr, $b_ptr                  # backup copy
2178         movdqu  0x10($a_ptr), %xmm1
2179          mov    0x20+8*0($a_ptr), $acc4         # load in_y in "5-4-0-1" order
2180          mov    0x20+8*1($a_ptr), $acc5
2181          mov    0x20+8*2($a_ptr), $acc0
2182          mov    0x20+8*3($a_ptr), $acc1
2183          mov    .Lpoly+8*1(%rip), $poly1
2184          mov    .Lpoly+8*3(%rip), $poly3
2185         movdqa  %xmm0, $in_x(%rsp)
2186         movdqa  %xmm1, $in_x+0x10(%rsp)
2187         lea     0x20($r_ptr), $acc2
2188         lea     0x40($r_ptr), $acc3
2189         movq    $r_ptr, %xmm0
2190         movq    $acc2, %xmm1
2191         movq    $acc3, %xmm2
2192
2193         lea     $S(%rsp), $r_ptr
2194         call    __ecp_nistz256_mul_by_2$x       # p256_mul_by_2(S, in_y);
2195
2196         mov     0x40+8*0($a_ptr), $src0
2197         mov     0x40+8*1($a_ptr), $acc6
2198         mov     0x40+8*2($a_ptr), $acc7
2199         mov     0x40+8*3($a_ptr), $acc0
2200         lea     0x40-$bias($a_ptr), $a_ptr
2201         lea     $Zsqr(%rsp), $r_ptr
2202         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Zsqr, in_z);
2203
2204         `&load_for_sqr("$S(%rsp)", "$src0")`
2205         lea     $S(%rsp), $r_ptr
2206         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(S, S);
2207
2208         mov     0x20($b_ptr), $src0             # $b_ptr is still valid
2209         mov     0x40+8*0($b_ptr), $acc1
2210         mov     0x40+8*1($b_ptr), $acc2
2211         mov     0x40+8*2($b_ptr), $acc3
2212         mov     0x40+8*3($b_ptr), $acc4
2213         lea     0x40-$bias($b_ptr), $a_ptr
2214         lea     0x20($b_ptr), $b_ptr
2215         movq    %xmm2, $r_ptr
2216         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_z, in_z, in_y);
2217         call    __ecp_nistz256_mul_by_2$x       # p256_mul_by_2(res_z, res_z);
2218
2219         mov     $in_x+8*0(%rsp), $acc4          # "5-4-0-1" order
2220         mov     $in_x+8*1(%rsp), $acc5
2221         lea     $Zsqr(%rsp), $b_ptr
2222         mov     $in_x+8*2(%rsp), $acc0
2223         mov     $in_x+8*3(%rsp), $acc1
2224         lea     $M(%rsp), $r_ptr
2225         call    __ecp_nistz256_add_to$x         # p256_add(M, in_x, Zsqr);
2226
2227         mov     $in_x+8*0(%rsp), $acc4          # "5-4-0-1" order
2228         mov     $in_x+8*1(%rsp), $acc5
2229         lea     $Zsqr(%rsp), $b_ptr
2230         mov     $in_x+8*2(%rsp), $acc0
2231         mov     $in_x+8*3(%rsp), $acc1
2232         lea     $Zsqr(%rsp), $r_ptr
2233         call    __ecp_nistz256_sub_from$x       # p256_sub(Zsqr, in_x, Zsqr);
2234
2235         `&load_for_sqr("$S(%rsp)", "$src0")`
2236         movq    %xmm1, $r_ptr
2237         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(res_y, S);
2238 ___
2239 {
2240 ######## ecp_nistz256_div_by_2(res_y, res_y); ##########################
2241 # operate in 4-5-6-7 "name space" that matches squaring output
2242 #
2243 my ($poly1,$poly3)=($a_ptr,$t1);
2244 my ($a0,$a1,$a2,$a3,$t3,$t4,$t1)=($acc4,$acc5,$acc6,$acc7,$acc0,$acc1,$acc2);
2245
2246 $code.=<<___;
2247         xor     $t4, $t4
2248         mov     $a0, $t0
2249         add     \$-1, $a0
2250         mov     $a1, $t1
2251         adc     $poly1, $a1
2252         mov     $a2, $t2
2253         adc     \$0, $a2
2254         mov     $a3, $t3
2255         adc     $poly3, $a3
2256         adc     \$0, $t4
2257         xor     $a_ptr, $a_ptr          # borrow $a_ptr
2258         test    \$1, $t0
2259
2260         cmovz   $t0, $a0
2261         cmovz   $t1, $a1
2262         cmovz   $t2, $a2
2263         cmovz   $t3, $a3
2264         cmovz   $a_ptr, $t4
2265
2266         mov     $a1, $t0                # a0:a3>>1
2267         shr     \$1, $a0
2268         shl     \$63, $t0
2269         mov     $a2, $t1
2270         shr     \$1, $a1
2271         or      $t0, $a0
2272         shl     \$63, $t1
2273         mov     $a3, $t2
2274         shr     \$1, $a2
2275         or      $t1, $a1
2276         shl     \$63, $t2
2277         mov     $a0, 8*0($r_ptr)
2278         shr     \$1, $a3
2279         mov     $a1, 8*1($r_ptr)
2280         shl     \$63, $t4
2281         or      $t2, $a2
2282         or      $t4, $a3
2283         mov     $a2, 8*2($r_ptr)
2284         mov     $a3, 8*3($r_ptr)
2285 ___
2286 }
2287 $code.=<<___;
2288         `&load_for_mul("$M(%rsp)", "$Zsqr(%rsp)", "$src0")`
2289         lea     $M(%rsp), $r_ptr
2290         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(M, M, Zsqr);
2291
2292         lea     $tmp0(%rsp), $r_ptr
2293         call    __ecp_nistz256_mul_by_2$x
2294
2295         lea     $M(%rsp), $b_ptr
2296         lea     $M(%rsp), $r_ptr
2297         call    __ecp_nistz256_add_to$x         # p256_mul_by_3(M, M);
2298
2299         `&load_for_mul("$S(%rsp)", "$in_x(%rsp)", "$src0")`
2300         lea     $S(%rsp), $r_ptr
2301         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S, S, in_x);
2302
2303         lea     $tmp0(%rsp), $r_ptr
2304         call    __ecp_nistz256_mul_by_2$x       # p256_mul_by_2(tmp0, S);
2305
2306         `&load_for_sqr("$M(%rsp)", "$src0")`
2307         movq    %xmm0, $r_ptr
2308         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(res_x, M);
2309
2310         lea     $tmp0(%rsp), $b_ptr
2311         mov     $acc6, $acc0                    # harmonize sqr output and sub input
2312         mov     $acc7, $acc1
2313         mov     $a_ptr, $poly1
2314         mov     $t1, $poly3
2315         call    __ecp_nistz256_sub_from$x       # p256_sub(res_x, res_x, tmp0);
2316
2317         mov     $S+8*0(%rsp), $t0
2318         mov     $S+8*1(%rsp), $t1
2319         mov     $S+8*2(%rsp), $t2
2320         mov     $S+8*3(%rsp), $acc2             # "4-5-0-1" order
2321         lea     $S(%rsp), $r_ptr
2322         call    __ecp_nistz256_sub$x            # p256_sub(S, S, res_x);
2323
2324         mov     $M(%rsp), $src0
2325         lea     $M(%rsp), $b_ptr
2326         mov     $acc4, $acc6                    # harmonize sub output and mul input
2327         xor     %ecx, %ecx
2328         mov     $acc4, $S+8*0(%rsp)             # have to save:-(
2329         mov     $acc5, $acc2
2330         mov     $acc5, $S+8*1(%rsp)
2331         cmovz   $acc0, $acc3
2332         mov     $acc0, $S+8*2(%rsp)
2333         lea     $S-$bias(%rsp), $a_ptr
2334         cmovz   $acc1, $acc4
2335         mov     $acc1, $S+8*3(%rsp)
2336         mov     $acc6, $acc1
2337         lea     $S(%rsp), $r_ptr
2338         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S, S, M);
2339
2340         movq    %xmm1, $b_ptr
2341         movq    %xmm1, $r_ptr
2342         call    __ecp_nistz256_sub_from$x       # p256_sub(res_y, S, res_y);
2343
2344         lea     32*5+56(%rsp), %rsi
2345 .cfi_def_cfa    %rsi,8
2346         mov     -48(%rsi),%r15
2347 .cfi_restore    %r15
2348         mov     -40(%rsi),%r14
2349 .cfi_restore    %r14
2350         mov     -32(%rsi),%r13
2351 .cfi_restore    %r13
2352         mov     -24(%rsi),%r12
2353 .cfi_restore    %r12
2354         mov     -16(%rsi),%rbx
2355 .cfi_restore    %rbx
2356         mov     -8(%rsi),%rbp
2357 .cfi_restore    %rbp
2358         lea     (%rsi),%rsp
2359 .cfi_def_cfa_register   %rsp
2360 .Lpoint_double${x}_epilogue:
2361         ret
2362 .cfi_endproc
2363 .size   ecp_nistz256_point_double$sfx,.-ecp_nistz256_point_double$sfx
2364 ___
2365 }
2366 &gen_double("q");
2367
2368 sub gen_add () {
2369     my $x = shift;
2370     my ($src0,$sfx,$bias);
2371     my ($H,$Hsqr,$R,$Rsqr,$Hcub,
2372         $U1,$U2,$S1,$S2,
2373         $res_x,$res_y,$res_z,
2374         $in1_x,$in1_y,$in1_z,
2375         $in2_x,$in2_y,$in2_z)=map(32*$_,(0..17));
2376     my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
2377
2378     if ($x ne "x") {
2379         $src0 = "%rax";
2380         $sfx  = "";
2381         $bias = 0;
2382
2383 $code.=<<___;
2384 .globl  ecp_nistz256_point_add
2385 .type   ecp_nistz256_point_add,\@function,3
2386 .align  32
2387 ecp_nistz256_point_add:
2388 .cfi_startproc
2389 ___
2390 $code.=<<___    if ($addx);
2391         mov     \$0x80100, %ecx
2392         and     OPENSSL_ia32cap_P+8(%rip), %ecx
2393         cmp     \$0x80100, %ecx
2394         je      .Lpoint_addx
2395 ___
2396     } else {
2397         $src0 = "%rdx";
2398         $sfx  = "x";
2399         $bias = 128;
2400
2401 $code.=<<___;
2402 .type   ecp_nistz256_point_addx,\@function,3
2403 .align  32
2404 ecp_nistz256_point_addx:
2405 .cfi_startproc
2406 .Lpoint_addx:
2407 ___
2408     }
2409 $code.=<<___;
2410         push    %rbp
2411 .cfi_push       %rbp
2412         push    %rbx
2413 .cfi_push       %rbx
2414         push    %r12
2415 .cfi_push       %r12
2416         push    %r13
2417 .cfi_push       %r13
2418         push    %r14
2419 .cfi_push       %r14
2420         push    %r15
2421 .cfi_push       %r15
2422         sub     \$32*18+8, %rsp
2423 .cfi_adjust_cfa_offset  32*18+8
2424 .Lpoint_add${x}_body:
2425
2426         movdqu  0x00($a_ptr), %xmm0             # copy  *(P256_POINT *)$a_ptr
2427         movdqu  0x10($a_ptr), %xmm1
2428         movdqu  0x20($a_ptr), %xmm2
2429         movdqu  0x30($a_ptr), %xmm3
2430         movdqu  0x40($a_ptr), %xmm4
2431         movdqu  0x50($a_ptr), %xmm5
2432         mov     $a_ptr, $b_ptr                  # reassign
2433         mov     $b_org, $a_ptr                  # reassign
2434         movdqa  %xmm0, $in1_x(%rsp)
2435         movdqa  %xmm1, $in1_x+0x10(%rsp)
2436         movdqa  %xmm2, $in1_y(%rsp)
2437         movdqa  %xmm3, $in1_y+0x10(%rsp)
2438         movdqa  %xmm4, $in1_z(%rsp)
2439         movdqa  %xmm5, $in1_z+0x10(%rsp)
2440         por     %xmm4, %xmm5
2441
2442         movdqu  0x00($a_ptr), %xmm0             # copy  *(P256_POINT *)$b_ptr
2443          pshufd \$0xb1, %xmm5, %xmm3
2444         movdqu  0x10($a_ptr), %xmm1
2445         movdqu  0x20($a_ptr), %xmm2
2446          por    %xmm3, %xmm5
2447         movdqu  0x30($a_ptr), %xmm3
2448          mov    0x40+8*0($a_ptr), $src0         # load original in2_z
2449          mov    0x40+8*1($a_ptr), $acc6
2450          mov    0x40+8*2($a_ptr), $acc7
2451          mov    0x40+8*3($a_ptr), $acc0
2452         movdqa  %xmm0, $in2_x(%rsp)
2453          pshufd \$0x1e, %xmm5, %xmm4
2454         movdqa  %xmm1, $in2_x+0x10(%rsp)
2455         movdqu  0x40($a_ptr),%xmm0              # in2_z again
2456         movdqu  0x50($a_ptr),%xmm1
2457         movdqa  %xmm2, $in2_y(%rsp)
2458         movdqa  %xmm3, $in2_y+0x10(%rsp)
2459          por    %xmm4, %xmm5
2460          pxor   %xmm4, %xmm4
2461         por     %xmm0, %xmm1
2462          movq   $r_ptr, %xmm0                   # save $r_ptr
2463
2464         lea     0x40-$bias($a_ptr), $a_ptr      # $a_ptr is still valid
2465          mov    $src0, $in2_z+8*0(%rsp)         # make in2_z copy
2466          mov    $acc6, $in2_z+8*1(%rsp)
2467          mov    $acc7, $in2_z+8*2(%rsp)
2468          mov    $acc0, $in2_z+8*3(%rsp)
2469         lea     $Z2sqr(%rsp), $r_ptr            # Z2^2
2470         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Z2sqr, in2_z);
2471
2472         pcmpeqd %xmm4, %xmm5
2473         pshufd  \$0xb1, %xmm1, %xmm4
2474         por     %xmm1, %xmm4
2475         pshufd  \$0, %xmm5, %xmm5               # in1infty
2476         pshufd  \$0x1e, %xmm4, %xmm3
2477         por     %xmm3, %xmm4
2478         pxor    %xmm3, %xmm3
2479         pcmpeqd %xmm3, %xmm4
2480         pshufd  \$0, %xmm4, %xmm4               # in2infty
2481          mov    0x40+8*0($b_ptr), $src0         # load original in1_z
2482          mov    0x40+8*1($b_ptr), $acc6
2483          mov    0x40+8*2($b_ptr), $acc7
2484          mov    0x40+8*3($b_ptr), $acc0
2485         movq    $b_ptr, %xmm1
2486
2487         lea     0x40-$bias($b_ptr), $a_ptr
2488         lea     $Z1sqr(%rsp), $r_ptr            # Z1^2
2489         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Z1sqr, in1_z);
2490
2491         `&load_for_mul("$Z2sqr(%rsp)", "$in2_z(%rsp)", "$src0")`
2492         lea     $S1(%rsp), $r_ptr               # S1 = Z2^3
2493         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S1, Z2sqr, in2_z);
2494
2495         `&load_for_mul("$Z1sqr(%rsp)", "$in1_z(%rsp)", "$src0")`
2496         lea     $S2(%rsp), $r_ptr               # S2 = Z1^3
2497         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, Z1sqr, in1_z);
2498
2499         `&load_for_mul("$S1(%rsp)", "$in1_y(%rsp)", "$src0")`
2500         lea     $S1(%rsp), $r_ptr               # S1 = Y1*Z2^3
2501         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S1, S1, in1_y);
2502
2503         `&load_for_mul("$S2(%rsp)", "$in2_y(%rsp)", "$src0")`
2504         lea     $S2(%rsp), $r_ptr               # S2 = Y2*Z1^3
2505         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, S2, in2_y);
2506
2507         lea     $S1(%rsp), $b_ptr
2508         lea     $R(%rsp), $r_ptr                # R = S2 - S1
2509         call    __ecp_nistz256_sub_from$x       # p256_sub(R, S2, S1);
2510
2511         or      $acc5, $acc4                    # see if result is zero
2512         movdqa  %xmm4, %xmm2
2513         or      $acc0, $acc4
2514         or      $acc1, $acc4
2515         por     %xmm5, %xmm2                    # in1infty || in2infty
2516         movq    $acc4, %xmm3
2517
2518         `&load_for_mul("$Z2sqr(%rsp)", "$in1_x(%rsp)", "$src0")`
2519         lea     $U1(%rsp), $r_ptr               # U1 = X1*Z2^2
2520         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U1, in1_x, Z2sqr);
2521
2522         `&load_for_mul("$Z1sqr(%rsp)", "$in2_x(%rsp)", "$src0")`
2523         lea     $U2(%rsp), $r_ptr               # U2 = X2*Z1^2
2524         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U2, in2_x, Z1sqr);
2525
2526         lea     $U1(%rsp), $b_ptr
2527         lea     $H(%rsp), $r_ptr                # H = U2 - U1
2528         call    __ecp_nistz256_sub_from$x       # p256_sub(H, U2, U1);
2529
2530         or      $acc5, $acc4                    # see if result is zero
2531         or      $acc0, $acc4
2532         or      $acc1, $acc4
2533
2534         .byte   0x3e                            # predict taken
2535         jnz     .Ladd_proceed$x                 # is_equal(U1,U2)?
2536         movq    %xmm2, $acc0
2537         movq    %xmm3, $acc1
2538         test    $acc0, $acc0
2539         jnz     .Ladd_proceed$x                 # (in1infty || in2infty)?
2540         test    $acc1, $acc1
2541         jz      .Ladd_double$x                  # is_equal(S1,S2)?
2542
2543         movq    %xmm0, $r_ptr                   # restore $r_ptr
2544         pxor    %xmm0, %xmm0
2545         movdqu  %xmm0, 0x00($r_ptr)
2546         movdqu  %xmm0, 0x10($r_ptr)
2547         movdqu  %xmm0, 0x20($r_ptr)
2548         movdqu  %xmm0, 0x30($r_ptr)
2549         movdqu  %xmm0, 0x40($r_ptr)
2550         movdqu  %xmm0, 0x50($r_ptr)
2551         jmp     .Ladd_done$x
2552
2553 .align  32
2554 .Ladd_double$x:
2555         movq    %xmm1, $a_ptr                   # restore $a_ptr
2556         movq    %xmm0, $r_ptr                   # restore $r_ptr
2557         add     \$`32*(18-5)`, %rsp             # difference in frame sizes
2558         jmp     .Lpoint_double_shortcut$x
2559
2560 .align  32
2561 .Ladd_proceed$x:
2562         `&load_for_sqr("$R(%rsp)", "$src0")`
2563         lea     $Rsqr(%rsp), $r_ptr             # R^2
2564         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Rsqr, R);
2565
2566         `&load_for_mul("$H(%rsp)", "$in1_z(%rsp)", "$src0")`
2567         lea     $res_z(%rsp), $r_ptr            # Z3 = H*Z1*Z2
2568         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_z, H, in1_z);
2569
2570         `&load_for_sqr("$H(%rsp)", "$src0")`
2571         lea     $Hsqr(%rsp), $r_ptr             # H^2
2572         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Hsqr, H);
2573
2574         `&load_for_mul("$res_z(%rsp)", "$in2_z(%rsp)", "$src0")`
2575         lea     $res_z(%rsp), $r_ptr            # Z3 = H*Z1*Z2
2576         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_z, res_z, in2_z);
2577
2578         `&load_for_mul("$Hsqr(%rsp)", "$H(%rsp)", "$src0")`
2579         lea     $Hcub(%rsp), $r_ptr             # H^3
2580         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(Hcub, Hsqr, H);
2581
2582         `&load_for_mul("$Hsqr(%rsp)", "$U1(%rsp)", "$src0")`
2583         lea     $U2(%rsp), $r_ptr               # U1*H^2
2584         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U2, U1, Hsqr);
2585 ___
2586 {
2587 #######################################################################
2588 # operate in 4-5-0-1 "name space" that matches multiplication output
2589 #
2590 my ($acc0,$acc1,$acc2,$acc3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
2591 my ($poly1, $poly3)=($acc6,$acc7);
2592
2593 $code.=<<___;
2594         #lea    $U2(%rsp), $a_ptr
2595         #lea    $Hsqr(%rsp), $r_ptr     # 2*U1*H^2
2596         #call   __ecp_nistz256_mul_by_2 # ecp_nistz256_mul_by_2(Hsqr, U2);
2597
2598         xor     $t4, $t4
2599         add     $acc0, $acc0            # a0:a3+a0:a3
2600         lea     $Rsqr(%rsp), $a_ptr
2601         adc     $acc1, $acc1
2602          mov    $acc0, $t0
2603         adc     $acc2, $acc2
2604         adc     $acc3, $acc3
2605          mov    $acc1, $t1
2606         adc     \$0, $t4
2607
2608         sub     \$-1, $acc0
2609          mov    $acc2, $t2
2610         sbb     $poly1, $acc1
2611         sbb     \$0, $acc2
2612          mov    $acc3, $t3
2613         sbb     $poly3, $acc3
2614         sbb     \$0, $t4
2615
2616         cmovc   $t0, $acc0
2617         mov     8*0($a_ptr), $t0
2618         cmovc   $t1, $acc1
2619         mov     8*1($a_ptr), $t1
2620         cmovc   $t2, $acc2
2621         mov     8*2($a_ptr), $t2
2622         cmovc   $t3, $acc3
2623         mov     8*3($a_ptr), $t3
2624
2625         call    __ecp_nistz256_sub$x            # p256_sub(res_x, Rsqr, Hsqr);
2626
2627         lea     $Hcub(%rsp), $b_ptr
2628         lea     $res_x(%rsp), $r_ptr
2629         call    __ecp_nistz256_sub_from$x       # p256_sub(res_x, res_x, Hcub);
2630
2631         mov     $U2+8*0(%rsp), $t0
2632         mov     $U2+8*1(%rsp), $t1
2633         mov     $U2+8*2(%rsp), $t2
2634         mov     $U2+8*3(%rsp), $t3
2635         lea     $res_y(%rsp), $r_ptr
2636
2637         call    __ecp_nistz256_sub$x            # p256_sub(res_y, U2, res_x);
2638
2639         mov     $acc0, 8*0($r_ptr)              # save the result, as
2640         mov     $acc1, 8*1($r_ptr)              # __ecp_nistz256_sub doesn't
2641         mov     $acc2, 8*2($r_ptr)
2642         mov     $acc3, 8*3($r_ptr)
2643 ___
2644 }
2645 $code.=<<___;
2646         `&load_for_mul("$S1(%rsp)", "$Hcub(%rsp)", "$src0")`
2647         lea     $S2(%rsp), $r_ptr
2648         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, S1, Hcub);
2649
2650         `&load_for_mul("$R(%rsp)", "$res_y(%rsp)", "$src0")`
2651         lea     $res_y(%rsp), $r_ptr
2652         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_y, R, res_y);
2653
2654         lea     $S2(%rsp), $b_ptr
2655         lea     $res_y(%rsp), $r_ptr
2656         call    __ecp_nistz256_sub_from$x       # p256_sub(res_y, res_y, S2);
2657
2658         movq    %xmm0, $r_ptr           # restore $r_ptr
2659
2660         movdqa  %xmm5, %xmm0            # copy_conditional(res_z, in2_z, in1infty);
2661         movdqa  %xmm5, %xmm1
2662         pandn   $res_z(%rsp), %xmm0
2663         movdqa  %xmm5, %xmm2
2664         pandn   $res_z+0x10(%rsp), %xmm1
2665         movdqa  %xmm5, %xmm3
2666         pand    $in2_z(%rsp), %xmm2
2667         pand    $in2_z+0x10(%rsp), %xmm3
2668         por     %xmm0, %xmm2
2669         por     %xmm1, %xmm3
2670
2671         movdqa  %xmm4, %xmm0            # copy_conditional(res_z, in1_z, in2infty);
2672         movdqa  %xmm4, %xmm1
2673         pandn   %xmm2, %xmm0
2674         movdqa  %xmm4, %xmm2
2675         pandn   %xmm3, %xmm1
2676         movdqa  %xmm4, %xmm3
2677         pand    $in1_z(%rsp), %xmm2
2678         pand    $in1_z+0x10(%rsp), %xmm3
2679         por     %xmm0, %xmm2
2680         por     %xmm1, %xmm3
2681         movdqu  %xmm2, 0x40($r_ptr)
2682         movdqu  %xmm3, 0x50($r_ptr)
2683
2684         movdqa  %xmm5, %xmm0            # copy_conditional(res_x, in2_x, in1infty);
2685         movdqa  %xmm5, %xmm1
2686         pandn   $res_x(%rsp), %xmm0
2687         movdqa  %xmm5, %xmm2
2688         pandn   $res_x+0x10(%rsp), %xmm1
2689         movdqa  %xmm5, %xmm3
2690         pand    $in2_x(%rsp), %xmm2
2691         pand    $in2_x+0x10(%rsp), %xmm3
2692         por     %xmm0, %xmm2
2693         por     %xmm1, %xmm3
2694
2695         movdqa  %xmm4, %xmm0            # copy_conditional(res_x, in1_x, in2infty);
2696         movdqa  %xmm4, %xmm1
2697         pandn   %xmm2, %xmm0
2698         movdqa  %xmm4, %xmm2
2699         pandn   %xmm3, %xmm1
2700         movdqa  %xmm4, %xmm3
2701         pand    $in1_x(%rsp), %xmm2
2702         pand    $in1_x+0x10(%rsp), %xmm3
2703         por     %xmm0, %xmm2
2704         por     %xmm1, %xmm3
2705         movdqu  %xmm2, 0x00($r_ptr)
2706         movdqu  %xmm3, 0x10($r_ptr)
2707
2708         movdqa  %xmm5, %xmm0            # copy_conditional(res_y, in2_y, in1infty);
2709         movdqa  %xmm5, %xmm1
2710         pandn   $res_y(%rsp), %xmm0
2711         movdqa  %xmm5, %xmm2
2712         pandn   $res_y+0x10(%rsp), %xmm1
2713         movdqa  %xmm5, %xmm3
2714         pand    $in2_y(%rsp), %xmm2
2715         pand    $in2_y+0x10(%rsp), %xmm3
2716         por     %xmm0, %xmm2
2717         por     %xmm1, %xmm3
2718
2719         movdqa  %xmm4, %xmm0            # copy_conditional(res_y, in1_y, in2infty);
2720         movdqa  %xmm4, %xmm1
2721         pandn   %xmm2, %xmm0
2722         movdqa  %xmm4, %xmm2
2723         pandn   %xmm3, %xmm1
2724         movdqa  %xmm4, %xmm3
2725         pand    $in1_y(%rsp), %xmm2
2726         pand    $in1_y+0x10(%rsp), %xmm3
2727         por     %xmm0, %xmm2
2728         por     %xmm1, %xmm3
2729         movdqu  %xmm2, 0x20($r_ptr)
2730         movdqu  %xmm3, 0x30($r_ptr)
2731
2732 .Ladd_done$x:
2733         lea     32*18+56(%rsp), %rsi
2734 .cfi_def_cfa    %rsi,8
2735         mov     -48(%rsi),%r15
2736 .cfi_restore    %r15
2737         mov     -40(%rsi),%r14
2738 .cfi_restore    %r14
2739         mov     -32(%rsi),%r13
2740 .cfi_restore    %r13
2741         mov     -24(%rsi),%r12
2742 .cfi_restore    %r12
2743         mov     -16(%rsi),%rbx
2744 .cfi_restore    %rbx
2745         mov     -8(%rsi),%rbp
2746 .cfi_restore    %rbp
2747         lea     (%rsi),%rsp
2748 .cfi_def_cfa_register   %rsp
2749 .Lpoint_add${x}_epilogue:
2750         ret
2751 .cfi_endproc
2752 .size   ecp_nistz256_point_add$sfx,.-ecp_nistz256_point_add$sfx
2753 ___
2754 }
2755 &gen_add("q");
2756
2757 sub gen_add_affine () {
2758     my $x = shift;
2759     my ($src0,$sfx,$bias);
2760     my ($U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr,
2761         $res_x,$res_y,$res_z,
2762         $in1_x,$in1_y,$in1_z,
2763         $in2_x,$in2_y)=map(32*$_,(0..14));
2764     my $Z1sqr = $S2;
2765
2766     if ($x ne "x") {
2767         $src0 = "%rax";
2768         $sfx  = "";
2769         $bias = 0;
2770
2771 $code.=<<___;
2772 .globl  ecp_nistz256_point_add_affine
2773 .type   ecp_nistz256_point_add_affine,\@function,3
2774 .align  32
2775 ecp_nistz256_point_add_affine:
2776 .cfi_startproc
2777 ___
2778 $code.=<<___    if ($addx);
2779         mov     \$0x80100, %ecx
2780         and     OPENSSL_ia32cap_P+8(%rip), %ecx
2781         cmp     \$0x80100, %ecx
2782         je      .Lpoint_add_affinex
2783 ___
2784     } else {
2785         $src0 = "%rdx";
2786         $sfx  = "x";
2787         $bias = 128;
2788
2789 $code.=<<___;
2790 .type   ecp_nistz256_point_add_affinex,\@function,3
2791 .align  32
2792 ecp_nistz256_point_add_affinex:
2793 .cfi_startproc
2794 .Lpoint_add_affinex:
2795 ___
2796     }
2797 $code.=<<___;
2798         push    %rbp
2799 .cfi_push       %rbp
2800         push    %rbx
2801 .cfi_push       %rbx
2802         push    %r12
2803 .cfi_push       %r12
2804         push    %r13
2805 .cfi_push       %r13
2806         push    %r14
2807 .cfi_push       %r14
2808         push    %r15
2809 .cfi_push       %r15
2810         sub     \$32*15+8, %rsp
2811 .cfi_adjust_cfa_offset  32*15+8
2812 .Ladd_affine${x}_body:
2813
2814         movdqu  0x00($a_ptr), %xmm0     # copy  *(P256_POINT *)$a_ptr
2815         mov     $b_org, $b_ptr          # reassign
2816         movdqu  0x10($a_ptr), %xmm1
2817         movdqu  0x20($a_ptr), %xmm2
2818         movdqu  0x30($a_ptr), %xmm3
2819         movdqu  0x40($a_ptr), %xmm4
2820         movdqu  0x50($a_ptr), %xmm5
2821          mov    0x40+8*0($a_ptr), $src0 # load original in1_z
2822          mov    0x40+8*1($a_ptr), $acc6
2823          mov    0x40+8*2($a_ptr), $acc7
2824          mov    0x40+8*3($a_ptr), $acc0
2825         movdqa  %xmm0, $in1_x(%rsp)
2826         movdqa  %xmm1, $in1_x+0x10(%rsp)
2827         movdqa  %xmm2, $in1_y(%rsp)
2828         movdqa  %xmm3, $in1_y+0x10(%rsp)
2829         movdqa  %xmm4, $in1_z(%rsp)
2830         movdqa  %xmm5, $in1_z+0x10(%rsp)
2831         por     %xmm4, %xmm5
2832
2833         movdqu  0x00($b_ptr), %xmm0     # copy  *(P256_POINT_AFFINE *)$b_ptr
2834          pshufd \$0xb1, %xmm5, %xmm3
2835         movdqu  0x10($b_ptr), %xmm1
2836         movdqu  0x20($b_ptr), %xmm2
2837          por    %xmm3, %xmm5
2838         movdqu  0x30($b_ptr), %xmm3
2839         movdqa  %xmm0, $in2_x(%rsp)
2840          pshufd \$0x1e, %xmm5, %xmm4
2841         movdqa  %xmm1, $in2_x+0x10(%rsp)
2842         por     %xmm0, %xmm1
2843          movq   $r_ptr, %xmm0           # save $r_ptr
2844         movdqa  %xmm2, $in2_y(%rsp)
2845         movdqa  %xmm3, $in2_y+0x10(%rsp)
2846         por     %xmm2, %xmm3
2847          por    %xmm4, %xmm5
2848          pxor   %xmm4, %xmm4
2849         por     %xmm1, %xmm3
2850
2851         lea     0x40-$bias($a_ptr), $a_ptr      # $a_ptr is still valid
2852         lea     $Z1sqr(%rsp), $r_ptr            # Z1^2
2853         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Z1sqr, in1_z);
2854
2855         pcmpeqd %xmm4, %xmm5
2856         pshufd  \$0xb1, %xmm3, %xmm4
2857          mov    0x00($b_ptr), $src0             # $b_ptr is still valid
2858          #lea   0x00($b_ptr), $b_ptr
2859          mov    $acc4, $acc1                    # harmonize sqr output and mul input
2860         por     %xmm3, %xmm4
2861         pshufd  \$0, %xmm5, %xmm5               # in1infty
2862         pshufd  \$0x1e, %xmm4, %xmm3
2863          mov    $acc5, $acc2
2864         por     %xmm3, %xmm4
2865         pxor    %xmm3, %xmm3
2866          mov    $acc6, $acc3
2867         pcmpeqd %xmm3, %xmm4
2868         pshufd  \$0, %xmm4, %xmm4               # in2infty
2869
2870         lea     $Z1sqr-$bias(%rsp), $a_ptr
2871         mov     $acc7, $acc4
2872         lea     $U2(%rsp), $r_ptr               # U2 = X2*Z1^2
2873         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U2, Z1sqr, in2_x);
2874
2875         lea     $in1_x(%rsp), $b_ptr
2876         lea     $H(%rsp), $r_ptr                # H = U2 - U1
2877         call    __ecp_nistz256_sub_from$x       # p256_sub(H, U2, in1_x);
2878
2879         `&load_for_mul("$Z1sqr(%rsp)", "$in1_z(%rsp)", "$src0")`
2880         lea     $S2(%rsp), $r_ptr               # S2 = Z1^3
2881         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, Z1sqr, in1_z);
2882
2883         `&load_for_mul("$H(%rsp)", "$in1_z(%rsp)", "$src0")`
2884         lea     $res_z(%rsp), $r_ptr            # Z3 = H*Z1*Z2
2885         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_z, H, in1_z);
2886
2887         `&load_for_mul("$S2(%rsp)", "$in2_y(%rsp)", "$src0")`
2888         lea     $S2(%rsp), $r_ptr               # S2 = Y2*Z1^3
2889         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, S2, in2_y);
2890
2891         lea     $in1_y(%rsp), $b_ptr
2892         lea     $R(%rsp), $r_ptr                # R = S2 - S1
2893         call    __ecp_nistz256_sub_from$x       # p256_sub(R, S2, in1_y);
2894
2895         `&load_for_sqr("$H(%rsp)", "$src0")`
2896         lea     $Hsqr(%rsp), $r_ptr             # H^2
2897         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Hsqr, H);
2898
2899         `&load_for_sqr("$R(%rsp)", "$src0")`
2900         lea     $Rsqr(%rsp), $r_ptr             # R^2
2901         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Rsqr, R);
2902
2903         `&load_for_mul("$H(%rsp)", "$Hsqr(%rsp)", "$src0")`
2904         lea     $Hcub(%rsp), $r_ptr             # H^3
2905         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(Hcub, Hsqr, H);
2906
2907         `&load_for_mul("$Hsqr(%rsp)", "$in1_x(%rsp)", "$src0")`
2908         lea     $U2(%rsp), $r_ptr               # U1*H^2
2909         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U2, in1_x, Hsqr);
2910 ___
2911 {
2912 #######################################################################
2913 # operate in 4-5-0-1 "name space" that matches multiplication output
2914 #
2915 my ($acc0,$acc1,$acc2,$acc3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
2916 my ($poly1, $poly3)=($acc6,$acc7);
2917
2918 $code.=<<___;
2919         #lea    $U2(%rsp), $a_ptr
2920         #lea    $Hsqr(%rsp), $r_ptr     # 2*U1*H^2
2921         #call   __ecp_nistz256_mul_by_2 # ecp_nistz256_mul_by_2(Hsqr, U2);
2922
2923         xor     $t4, $t4
2924         add     $acc0, $acc0            # a0:a3+a0:a3
2925         lea     $Rsqr(%rsp), $a_ptr
2926         adc     $acc1, $acc1
2927          mov    $acc0, $t0
2928         adc     $acc2, $acc2
2929         adc     $acc3, $acc3
2930          mov    $acc1, $t1
2931         adc     \$0, $t4
2932
2933         sub     \$-1, $acc0
2934          mov    $acc2, $t2
2935         sbb     $poly1, $acc1
2936         sbb     \$0, $acc2
2937          mov    $acc3, $t3
2938         sbb     $poly3, $acc3
2939         sbb     \$0, $t4
2940
2941         cmovc   $t0, $acc0
2942         mov     8*0($a_ptr), $t0
2943         cmovc   $t1, $acc1
2944         mov     8*1($a_ptr), $t1
2945         cmovc   $t2, $acc2
2946         mov     8*2($a_ptr), $t2
2947         cmovc   $t3, $acc3
2948         mov     8*3($a_ptr), $t3
2949
2950         call    __ecp_nistz256_sub$x            # p256_sub(res_x, Rsqr, Hsqr);
2951
2952         lea     $Hcub(%rsp), $b_ptr
2953         lea     $res_x(%rsp), $r_ptr
2954         call    __ecp_nistz256_sub_from$x       # p256_sub(res_x, res_x, Hcub);
2955
2956         mov     $U2+8*0(%rsp), $t0
2957         mov     $U2+8*1(%rsp), $t1
2958         mov     $U2+8*2(%rsp), $t2
2959         mov     $U2+8*3(%rsp), $t3
2960         lea     $H(%rsp), $r_ptr
2961
2962         call    __ecp_nistz256_sub$x            # p256_sub(H, U2, res_x);
2963
2964         mov     $acc0, 8*0($r_ptr)              # save the result, as
2965         mov     $acc1, 8*1($r_ptr)              # __ecp_nistz256_sub doesn't
2966         mov     $acc2, 8*2($r_ptr)
2967         mov     $acc3, 8*3($r_ptr)
2968 ___
2969 }
2970 $code.=<<___;
2971         `&load_for_mul("$Hcub(%rsp)", "$in1_y(%rsp)", "$src0")`
2972         lea     $S2(%rsp), $r_ptr
2973         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, Hcub, in1_y);
2974
2975         `&load_for_mul("$H(%rsp)", "$R(%rsp)", "$src0")`
2976         lea     $H(%rsp), $r_ptr
2977         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(H, H, R);
2978
2979         lea     $S2(%rsp), $b_ptr
2980         lea     $res_y(%rsp), $r_ptr
2981         call    __ecp_nistz256_sub_from$x       # p256_sub(res_y, H, S2);
2982
2983         movq    %xmm0, $r_ptr           # restore $r_ptr
2984
2985         movdqa  %xmm5, %xmm0            # copy_conditional(res_z, ONE, in1infty);
2986         movdqa  %xmm5, %xmm1
2987         pandn   $res_z(%rsp), %xmm0
2988         movdqa  %xmm5, %xmm2
2989         pandn   $res_z+0x10(%rsp), %xmm1
2990         movdqa  %xmm5, %xmm3
2991         pand    .LONE_mont(%rip), %xmm2
2992         pand    .LONE_mont+0x10(%rip), %xmm3
2993         por     %xmm0, %xmm2
2994         por     %xmm1, %xmm3
2995
2996         movdqa  %xmm4, %xmm0            # copy_conditional(res_z, in1_z, in2infty);
2997         movdqa  %xmm4, %xmm1
2998         pandn   %xmm2, %xmm0
2999         movdqa  %xmm4, %xmm2
3000         pandn   %xmm3, %xmm1
3001         movdqa  %xmm4, %xmm3
3002         pand    $in1_z(%rsp), %xmm2
3003         pand    $in1_z+0x10(%rsp), %xmm3
3004         por     %xmm0, %xmm2
3005         por     %xmm1, %xmm3
3006         movdqu  %xmm2, 0x40($r_ptr)
3007         movdqu  %xmm3, 0x50($r_ptr)
3008
3009         movdqa  %xmm5, %xmm0            # copy_conditional(res_x, in2_x, in1infty);
3010         movdqa  %xmm5, %xmm1
3011         pandn   $res_x(%rsp), %xmm0
3012         movdqa  %xmm5, %xmm2
3013         pandn   $res_x+0x10(%rsp), %xmm1
3014         movdqa  %xmm5, %xmm3
3015         pand    $in2_x(%rsp), %xmm2
3016         pand    $in2_x+0x10(%rsp), %xmm3
3017         por     %xmm0, %xmm2
3018         por     %xmm1, %xmm3
3019
3020         movdqa  %xmm4, %xmm0            # copy_conditional(res_x, in1_x, in2infty);
3021         movdqa  %xmm4, %xmm1
3022         pandn   %xmm2, %xmm0
3023         movdqa  %xmm4, %xmm2
3024         pandn   %xmm3, %xmm1
3025         movdqa  %xmm4, %xmm3
3026         pand    $in1_x(%rsp), %xmm2
3027         pand    $in1_x+0x10(%rsp), %xmm3
3028         por     %xmm0, %xmm2
3029         por     %xmm1, %xmm3
3030         movdqu  %xmm2, 0x00($r_ptr)
3031         movdqu  %xmm3, 0x10($r_ptr)
3032
3033         movdqa  %xmm5, %xmm0            # copy_conditional(res_y, in2_y, in1infty);
3034         movdqa  %xmm5, %xmm1
3035         pandn   $res_y(%rsp), %xmm0
3036         movdqa  %xmm5, %xmm2
3037         pandn   $res_y+0x10(%rsp), %xmm1
3038         movdqa  %xmm5, %xmm3
3039         pand    $in2_y(%rsp), %xmm2
3040         pand    $in2_y+0x10(%rsp), %xmm3
3041         por     %xmm0, %xmm2
3042         por     %xmm1, %xmm3
3043
3044         movdqa  %xmm4, %xmm0            # copy_conditional(res_y, in1_y, in2infty);
3045         movdqa  %xmm4, %xmm1
3046         pandn   %xmm2, %xmm0
3047         movdqa  %xmm4, %xmm2
3048         pandn   %xmm3, %xmm1
3049         movdqa  %xmm4, %xmm3
3050         pand    $in1_y(%rsp), %xmm2
3051         pand    $in1_y+0x10(%rsp), %xmm3
3052         por     %xmm0, %xmm2
3053         por     %xmm1, %xmm3
3054         movdqu  %xmm2, 0x20($r_ptr)
3055         movdqu  %xmm3, 0x30($r_ptr)
3056
3057         lea     32*15+56(%rsp), %rsi
3058 .cfi_def_cfa    %rsi,8
3059         mov     -48(%rsi),%r15
3060 .cfi_restore    %r15
3061         mov     -40(%rsi),%r14
3062 .cfi_restore    %r14
3063         mov     -32(%rsi),%r13
3064 .cfi_restore    %r13
3065         mov     -24(%rsi),%r12
3066 .cfi_restore    %r12
3067         mov     -16(%rsi),%rbx
3068 .cfi_restore    %rbx
3069         mov     -8(%rsi),%rbp
3070 .cfi_restore    %rbp
3071         lea     (%rsi),%rsp
3072 .cfi_def_cfa_register   %rsp
3073 .Ladd_affine${x}_epilogue:
3074         ret
3075 .cfi_endproc
3076 .size   ecp_nistz256_point_add_affine$sfx,.-ecp_nistz256_point_add_affine$sfx
3077 ___
3078 }
3079 &gen_add_affine("q");
3080
3081 ########################################################################
3082 # AD*X magic
3083 #
3084 if ($addx) {                                                            {
3085 ########################################################################
3086 # operate in 4-5-0-1 "name space" that matches multiplication output
3087 #
3088 my ($a0,$a1,$a2,$a3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
3089
3090 $code.=<<___;
3091 .type   __ecp_nistz256_add_tox,\@abi-omnipotent
3092 .align  32
3093 __ecp_nistz256_add_tox:
3094         xor     $t4, $t4
3095         adc     8*0($b_ptr), $a0
3096         adc     8*1($b_ptr), $a1
3097          mov    $a0, $t0
3098         adc     8*2($b_ptr), $a2
3099         adc     8*3($b_ptr), $a3
3100          mov    $a1, $t1
3101         adc     \$0, $t4
3102
3103         xor     $t3, $t3
3104         sbb     \$-1, $a0
3105          mov    $a2, $t2
3106         sbb     $poly1, $a1
3107         sbb     \$0, $a2
3108          mov    $a3, $t3
3109         sbb     $poly3, $a3
3110         sbb     \$0, $t4
3111
3112         cmovc   $t0, $a0
3113         cmovc   $t1, $a1
3114         mov     $a0, 8*0($r_ptr)
3115         cmovc   $t2, $a2
3116         mov     $a1, 8*1($r_ptr)
3117         cmovc   $t3, $a3
3118         mov     $a2, 8*2($r_ptr)
3119         mov     $a3, 8*3($r_ptr)
3120
3121         ret
3122 .size   __ecp_nistz256_add_tox,.-__ecp_nistz256_add_tox
3123
3124 .type   __ecp_nistz256_sub_fromx,\@abi-omnipotent
3125 .align  32
3126 __ecp_nistz256_sub_fromx:
3127         xor     $t4, $t4
3128         sbb     8*0($b_ptr), $a0
3129         sbb     8*1($b_ptr), $a1
3130          mov    $a0, $t0
3131         sbb     8*2($b_ptr), $a2
3132         sbb     8*3($b_ptr), $a3
3133          mov    $a1, $t1
3134         sbb     \$0, $t4
3135
3136         xor     $t3, $t3
3137         adc     \$-1, $a0
3138          mov    $a2, $t2
3139         adc     $poly1, $a1
3140         adc     \$0, $a2
3141          mov    $a3, $t3
3142         adc     $poly3, $a3
3143
3144         bt      \$0, $t4
3145         cmovnc  $t0, $a0
3146         cmovnc  $t1, $a1
3147         mov     $a0, 8*0($r_ptr)
3148         cmovnc  $t2, $a2
3149         mov     $a1, 8*1($r_ptr)
3150         cmovnc  $t3, $a3
3151         mov     $a2, 8*2($r_ptr)
3152         mov     $a3, 8*3($r_ptr)
3153
3154         ret
3155 .size   __ecp_nistz256_sub_fromx,.-__ecp_nistz256_sub_fromx
3156
3157 .type   __ecp_nistz256_subx,\@abi-omnipotent
3158 .align  32
3159 __ecp_nistz256_subx:
3160         xor     $t4, $t4
3161         sbb     $a0, $t0
3162         sbb     $a1, $t1
3163          mov    $t0, $a0
3164         sbb     $a2, $t2
3165         sbb     $a3, $t3
3166          mov    $t1, $a1
3167         sbb     \$0, $t4
3168
3169         xor     $a3 ,$a3
3170         adc     \$-1, $t0
3171          mov    $t2, $a2
3172         adc     $poly1, $t1
3173         adc     \$0, $t2
3174          mov    $t3, $a3
3175         adc     $poly3, $t3
3176
3177         bt      \$0, $t4
3178         cmovc   $t0, $a0
3179         cmovc   $t1, $a1
3180         cmovc   $t2, $a2
3181         cmovc   $t3, $a3
3182
3183         ret
3184 .size   __ecp_nistz256_subx,.-__ecp_nistz256_subx
3185
3186 .type   __ecp_nistz256_mul_by_2x,\@abi-omnipotent
3187 .align  32
3188 __ecp_nistz256_mul_by_2x:
3189         xor     $t4, $t4
3190         adc     $a0, $a0                # a0:a3+a0:a3
3191         adc     $a1, $a1
3192          mov    $a0, $t0
3193         adc     $a2, $a2
3194         adc     $a3, $a3
3195          mov    $a1, $t1
3196         adc     \$0, $t4
3197
3198         xor     $t3, $t3
3199         sbb     \$-1, $a0
3200          mov    $a2, $t2
3201         sbb     $poly1, $a1
3202         sbb     \$0, $a2
3203          mov    $a3, $t3
3204         sbb     $poly3, $a3
3205         sbb     \$0, $t4
3206
3207         cmovc   $t0, $a0
3208         cmovc   $t1, $a1
3209         mov     $a0, 8*0($r_ptr)
3210         cmovc   $t2, $a2
3211         mov     $a1, 8*1($r_ptr)
3212         cmovc   $t3, $a3
3213         mov     $a2, 8*2($r_ptr)
3214         mov     $a3, 8*3($r_ptr)
3215
3216         ret
3217 .size   __ecp_nistz256_mul_by_2x,.-__ecp_nistz256_mul_by_2x
3218 ___
3219                                                                         }
3220 &gen_double("x");
3221 &gen_add("x");
3222 &gen_add_affine("x");
3223 }
3224 }}}
3225
3226 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
3227 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
3228 if ($win64) {
3229 $rec="%rcx";
3230 $frame="%rdx";
3231 $context="%r8";
3232 $disp="%r9";
3233
3234 $code.=<<___;
3235 .extern __imp_RtlVirtualUnwind
3236
3237 .type   short_handler,\@abi-omnipotent
3238 .align  16
3239 short_handler:
3240         push    %rsi
3241         push    %rdi
3242         push    %rbx
3243         push    %rbp
3244         push    %r12
3245         push    %r13
3246         push    %r14
3247         push    %r15
3248         pushfq
3249         sub     \$64,%rsp
3250
3251         mov     120($context),%rax      # pull context->Rax
3252         mov     248($context),%rbx      # pull context->Rip
3253
3254         mov     8($disp),%rsi           # disp->ImageBase
3255         mov     56($disp),%r11          # disp->HandlerData
3256
3257         mov     0(%r11),%r10d           # HandlerData[0]
3258         lea     (%rsi,%r10),%r10        # end of prologue label
3259         cmp     %r10,%rbx               # context->Rip<end of prologue label
3260         jb      .Lcommon_seh_tail
3261
3262         mov     152($context),%rax      # pull context->Rsp
3263
3264         mov     4(%r11),%r10d           # HandlerData[1]
3265         lea     (%rsi,%r10),%r10        # epilogue label
3266         cmp     %r10,%rbx               # context->Rip>=epilogue label
3267         jae     .Lcommon_seh_tail
3268
3269         lea     16(%rax),%rax
3270
3271         mov     -8(%rax),%r12
3272         mov     -16(%rax),%r13
3273         mov     %r12,216($context)      # restore context->R12
3274         mov     %r13,224($context)      # restore context->R13
3275
3276         jmp     .Lcommon_seh_tail
3277 .size   short_handler,.-short_handler
3278
3279 .type   full_handler,\@abi-omnipotent
3280 .align  16
3281 full_handler:
3282         push    %rsi
3283         push    %rdi
3284         push    %rbx
3285         push    %rbp
3286         push    %r12
3287         push    %r13
3288         push    %r14
3289         push    %r15
3290         pushfq
3291         sub     \$64,%rsp
3292
3293         mov     120($context),%rax      # pull context->Rax
3294         mov     248($context),%rbx      # pull context->Rip
3295
3296         mov     8($disp),%rsi           # disp->ImageBase
3297         mov     56($disp),%r11          # disp->HandlerData
3298
3299         mov     0(%r11),%r10d           # HandlerData[0]
3300         lea     (%rsi,%r10),%r10        # end of prologue label
3301         cmp     %r10,%rbx               # context->Rip<end of prologue label
3302         jb      .Lcommon_seh_tail
3303
3304         mov     152($context),%rax      # pull context->Rsp
3305
3306         mov     4(%r11),%r10d           # HandlerData[1]
3307         lea     (%rsi,%r10),%r10        # epilogue label
3308         cmp     %r10,%rbx               # context->Rip>=epilogue label
3309         jae     .Lcommon_seh_tail
3310
3311         mov     8(%r11),%r10d           # HandlerData[2]
3312         lea     (%rax,%r10),%rax
3313
3314         mov     -8(%rax),%rbp
3315         mov     -16(%rax),%rbx
3316         mov     -24(%rax),%r12
3317         mov     -32(%rax),%r13
3318         mov     -40(%rax),%r14
3319         mov     -48(%rax),%r15
3320         mov     %rbx,144($context)      # restore context->Rbx
3321         mov     %rbp,160($context)      # restore context->Rbp
3322         mov     %r12,216($context)      # restore context->R12
3323         mov     %r13,224($context)      # restore context->R13
3324         mov     %r14,232($context)      # restore context->R14
3325         mov     %r15,240($context)      # restore context->R15
3326
3327 .Lcommon_seh_tail:
3328         mov     8(%rax),%rdi
3329         mov     16(%rax),%rsi
3330         mov     %rax,152($context)      # restore context->Rsp
3331         mov     %rsi,168($context)      # restore context->Rsi
3332         mov     %rdi,176($context)      # restore context->Rdi
3333
3334         mov     40($disp),%rdi          # disp->ContextRecord
3335         mov     $context,%rsi           # context
3336         mov     \$154,%ecx              # sizeof(CONTEXT)
3337         .long   0xa548f3fc              # cld; rep movsq
3338
3339         mov     $disp,%rsi
3340         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
3341         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
3342         mov     0(%rsi),%r8             # arg3, disp->ControlPc
3343         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
3344         mov     40(%rsi),%r10           # disp->ContextRecord
3345         lea     56(%rsi),%r11           # &disp->HandlerData
3346         lea     24(%rsi),%r12           # &disp->EstablisherFrame
3347         mov     %r10,32(%rsp)           # arg5
3348         mov     %r11,40(%rsp)           # arg6
3349         mov     %r12,48(%rsp)           # arg7
3350         mov     %rcx,56(%rsp)           # arg8, (NULL)
3351         call    *__imp_RtlVirtualUnwind(%rip)
3352
3353         mov     \$1,%eax                # ExceptionContinueSearch
3354         add     \$64,%rsp
3355         popfq
3356         pop     %r15
3357         pop     %r14
3358         pop     %r13
3359         pop     %r12
3360         pop     %rbp
3361         pop     %rbx
3362         pop     %rdi
3363         pop     %rsi
3364         ret
3365 .size   full_handler,.-full_handler
3366
3367 .section        .pdata
3368 .align  4
3369         .rva    .LSEH_begin_ecp_nistz256_mul_by_2
3370         .rva    .LSEH_end_ecp_nistz256_mul_by_2
3371         .rva    .LSEH_info_ecp_nistz256_mul_by_2
3372
3373         .rva    .LSEH_begin_ecp_nistz256_div_by_2
3374         .rva    .LSEH_end_ecp_nistz256_div_by_2
3375         .rva    .LSEH_info_ecp_nistz256_div_by_2
3376
3377         .rva    .LSEH_begin_ecp_nistz256_mul_by_3
3378         .rva    .LSEH_end_ecp_nistz256_mul_by_3
3379         .rva    .LSEH_info_ecp_nistz256_mul_by_3
3380
3381         .rva    .LSEH_begin_ecp_nistz256_add
3382         .rva    .LSEH_end_ecp_nistz256_add
3383         .rva    .LSEH_info_ecp_nistz256_add
3384
3385         .rva    .LSEH_begin_ecp_nistz256_sub
3386         .rva    .LSEH_end_ecp_nistz256_sub
3387         .rva    .LSEH_info_ecp_nistz256_sub
3388
3389         .rva    .LSEH_begin_ecp_nistz256_neg
3390         .rva    .LSEH_end_ecp_nistz256_neg
3391         .rva    .LSEH_info_ecp_nistz256_neg
3392
3393         .rva    .LSEH_begin_ecp_nistz256_to_mont
3394         .rva    .LSEH_end_ecp_nistz256_to_mont
3395         .rva    .LSEH_info_ecp_nistz256_to_mont
3396
3397         .rva    .LSEH_begin_ecp_nistz256_mul_mont
3398         .rva    .LSEH_end_ecp_nistz256_mul_mont
3399         .rva    .LSEH_info_ecp_nistz256_mul_mont
3400
3401         .rva    .LSEH_begin_ecp_nistz256_sqr_mont
3402         .rva    .LSEH_end_ecp_nistz256_sqr_mont
3403         .rva    .LSEH_info_ecp_nistz256_sqr_mont
3404
3405         .rva    .LSEH_begin_ecp_nistz256_from_mont
3406         .rva    .LSEH_end_ecp_nistz256_from_mont
3407         .rva    .LSEH_info_ecp_nistz256_from_mont
3408
3409         .rva    .LSEH_begin_ecp_nistz256_gather_w5
3410         .rva    .LSEH_end_ecp_nistz256_gather_w5
3411         .rva    .LSEH_info_ecp_nistz256_gather_wX
3412
3413         .rva    .LSEH_begin_ecp_nistz256_gather_w7
3414         .rva    .LSEH_end_ecp_nistz256_gather_w7
3415         .rva    .LSEH_info_ecp_nistz256_gather_wX
3416 ___
3417 $code.=<<___    if ($avx>1);
3418         .rva    .LSEH_begin_ecp_nistz256_avx2_gather_w5
3419         .rva    .LSEH_end_ecp_nistz256_avx2_gather_w5
3420         .rva    .LSEH_info_ecp_nistz256_avx2_gather_wX
3421
3422         .rva    .LSEH_begin_ecp_nistz256_avx2_gather_w7
3423         .rva    .LSEH_end_ecp_nistz256_avx2_gather_w7
3424         .rva    .LSEH_info_ecp_nistz256_avx2_gather_wX
3425 ___
3426 $code.=<<___;
3427         .rva    .LSEH_begin_ecp_nistz256_point_double
3428         .rva    .LSEH_end_ecp_nistz256_point_double
3429         .rva    .LSEH_info_ecp_nistz256_point_double
3430
3431         .rva    .LSEH_begin_ecp_nistz256_point_add
3432         .rva    .LSEH_end_ecp_nistz256_point_add
3433         .rva    .LSEH_info_ecp_nistz256_point_add
3434
3435         .rva    .LSEH_begin_ecp_nistz256_point_add_affine
3436         .rva    .LSEH_end_ecp_nistz256_point_add_affine
3437         .rva    .LSEH_info_ecp_nistz256_point_add_affine
3438 ___
3439 $code.=<<___ if ($addx);
3440         .rva    .LSEH_begin_ecp_nistz256_point_doublex
3441         .rva    .LSEH_end_ecp_nistz256_point_doublex
3442         .rva    .LSEH_info_ecp_nistz256_point_doublex
3443
3444         .rva    .LSEH_begin_ecp_nistz256_point_addx
3445         .rva    .LSEH_end_ecp_nistz256_point_addx
3446         .rva    .LSEH_info_ecp_nistz256_point_addx
3447
3448         .rva    .LSEH_begin_ecp_nistz256_point_add_affinex
3449         .rva    .LSEH_end_ecp_nistz256_point_add_affinex
3450         .rva    .LSEH_info_ecp_nistz256_point_add_affinex
3451 ___
3452 $code.=<<___;
3453
3454 .section        .xdata
3455 .align  8
3456 .LSEH_info_ecp_nistz256_mul_by_2:
3457         .byte   9,0,0,0
3458         .rva    short_handler
3459         .rva    .Lmul_by_2_body,.Lmul_by_2_epilogue     # HandlerData[]
3460 .LSEH_info_ecp_nistz256_div_by_2:
3461         .byte   9,0,0,0
3462         .rva    short_handler
3463         .rva    .Ldiv_by_2_body,.Ldiv_by_2_epilogue     # HandlerData[]
3464 .LSEH_info_ecp_nistz256_mul_by_3:
3465         .byte   9,0,0,0
3466         .rva    short_handler
3467         .rva    .Lmul_by_3_body,.Lmul_by_3_epilogue     # HandlerData[]
3468 .LSEH_info_ecp_nistz256_add:
3469         .byte   9,0,0,0
3470         .rva    short_handler
3471         .rva    .Ladd_body,.Ladd_epilogue               # HandlerData[]
3472 .LSEH_info_ecp_nistz256_sub:
3473         .byte   9,0,0,0
3474         .rva    short_handler
3475         .rva    .Lsub_body,.Lsub_epilogue               # HandlerData[]
3476 .LSEH_info_ecp_nistz256_neg:
3477         .byte   9,0,0,0
3478         .rva    short_handler
3479         .rva    .Lneg_body,.Lneg_epilogue               # HandlerData[]
3480 .LSEH_info_ecp_nistz256_to_mont:
3481         .byte   9,0,0,0
3482         .rva    full_handler
3483         .rva    .Lmul_body,.Lmul_epilogue               # HandlerData[]
3484         .long   48,0
3485 .LSEH_info_ecp_nistz256_mul_mont:
3486         .byte   9,0,0,0
3487         .rva    full_handler
3488         .rva    .Lmul_body,.Lmul_epilogue               # HandlerData[]
3489         .long   48,0
3490 .LSEH_info_ecp_nistz256_sqr_mont:
3491         .byte   9,0,0,0
3492         .rva    full_handler
3493         .rva    .Lsqr_body,.Lsqr_epilogue               # HandlerData[]
3494         .long   48,0
3495 .LSEH_info_ecp_nistz256_from_mont:
3496         .byte   9,0,0,0
3497         .rva    short_handler
3498         .rva    .Lfrom_body,.Lfrom_epilogue             # HandlerData[]
3499 .LSEH_info_ecp_nistz256_gather_wX:
3500         .byte   0x01,0x33,0x16,0x00
3501         .byte   0x33,0xf8,0x09,0x00     #movaps 0x90(rsp),xmm15
3502         .byte   0x2e,0xe8,0x08,0x00     #movaps 0x80(rsp),xmm14
3503         .byte   0x29,0xd8,0x07,0x00     #movaps 0x70(rsp),xmm13
3504         .byte   0x24,0xc8,0x06,0x00     #movaps 0x60(rsp),xmm12
3505         .byte   0x1f,0xb8,0x05,0x00     #movaps 0x50(rsp),xmm11
3506         .byte   0x1a,0xa8,0x04,0x00     #movaps 0x40(rsp),xmm10
3507         .byte   0x15,0x98,0x03,0x00     #movaps 0x30(rsp),xmm9
3508         .byte   0x10,0x88,0x02,0x00     #movaps 0x20(rsp),xmm8
3509         .byte   0x0c,0x78,0x01,0x00     #movaps 0x10(rsp),xmm7
3510         .byte   0x08,0x68,0x00,0x00     #movaps 0x00(rsp),xmm6
3511         .byte   0x04,0x01,0x15,0x00     #sub    rsp,0xa8
3512         .align  8
3513 ___
3514 $code.=<<___    if ($avx>1);
3515 .LSEH_info_ecp_nistz256_avx2_gather_wX:
3516         .byte   0x01,0x36,0x17,0x0b
3517         .byte   0x36,0xf8,0x09,0x00     # vmovaps 0x90(rsp),xmm15
3518         .byte   0x31,0xe8,0x08,0x00     # vmovaps 0x80(rsp),xmm14
3519         .byte   0x2c,0xd8,0x07,0x00     # vmovaps 0x70(rsp),xmm13
3520         .byte   0x27,0xc8,0x06,0x00     # vmovaps 0x60(rsp),xmm12
3521         .byte   0x22,0xb8,0x05,0x00     # vmovaps 0x50(rsp),xmm11
3522         .byte   0x1d,0xa8,0x04,0x00     # vmovaps 0x40(rsp),xmm10
3523         .byte   0x18,0x98,0x03,0x00     # vmovaps 0x30(rsp),xmm9
3524         .byte   0x13,0x88,0x02,0x00     # vmovaps 0x20(rsp),xmm8
3525         .byte   0x0e,0x78,0x01,0x00     # vmovaps 0x10(rsp),xmm7
3526         .byte   0x09,0x68,0x00,0x00     # vmovaps 0x00(rsp),xmm6
3527         .byte   0x04,0x01,0x15,0x00     # sub     rsp,0xa8
3528         .byte   0x00,0xb3,0x00,0x00     # set_frame r11
3529         .align  8
3530 ___
3531 $code.=<<___;
3532 .LSEH_info_ecp_nistz256_point_double:
3533         .byte   9,0,0,0
3534         .rva    full_handler
3535         .rva    .Lpoint_doubleq_body,.Lpoint_doubleq_epilogue   # HandlerData[]
3536         .long   32*5+56,0
3537 .LSEH_info_ecp_nistz256_point_add:
3538         .byte   9,0,0,0
3539         .rva    full_handler
3540         .rva    .Lpoint_addq_body,.Lpoint_addq_epilogue         # HandlerData[]
3541         .long   32*18+56,0
3542 .LSEH_info_ecp_nistz256_point_add_affine:
3543         .byte   9,0,0,0
3544         .rva    full_handler
3545         .rva    .Ladd_affineq_body,.Ladd_affineq_epilogue       # HandlerData[]
3546         .long   32*15+56,0
3547 ___
3548 $code.=<<___ if ($addx);
3549 .align  8
3550 .LSEH_info_ecp_nistz256_point_doublex:
3551         .byte   9,0,0,0
3552         .rva    full_handler
3553         .rva    .Lpoint_doublex_body,.Lpoint_doublex_epilogue   # HandlerData[]
3554         .long   32*5+56,0
3555 .LSEH_info_ecp_nistz256_point_addx:
3556         .byte   9,0,0,0
3557         .rva    full_handler
3558         .rva    .Lpoint_addx_body,.Lpoint_addx_epilogue         # HandlerData[]
3559         .long   32*18+56,0
3560 .LSEH_info_ecp_nistz256_point_add_affinex:
3561         .byte   9,0,0,0
3562         .rva    full_handler
3563         .rva    .Ladd_affinex_body,.Ladd_affinex_epilogue       # HandlerData[]
3564         .long   32*15+56,0
3565 ___
3566 }
3567
3568 ########################################################################
3569 # Convert ecp_nistz256_table.c to layout expected by ecp_nistz_gather_w7
3570 #
3571 open TABLE,"<ecp_nistz256_table.c"              or
3572 open TABLE,"<${dir}../ecp_nistz256_table.c"     or
3573 die "failed to open ecp_nistz256_table.c:",$!;
3574
3575 use integer;
3576
3577 foreach(<TABLE>) {
3578         s/TOBN\(\s*(0x[0-9a-f]+),\s*(0x[0-9a-f]+)\s*\)/push @arr,hex($2),hex($1)/geo;
3579 }
3580 close TABLE;
3581
3582 die "insane number of elements" if ($#arr != 64*16*37-1);
3583
3584 print <<___;
3585 .text
3586 .globl  ecp_nistz256_precomputed
3587 .type   ecp_nistz256_precomputed,\@object
3588 .align  4096
3589 ecp_nistz256_precomputed:
3590 ___
3591 while (@line=splice(@arr,0,16)) {
3592         print ".long\t",join(',',map { sprintf "0x%08x",$_} @line),"\n";
3593 }
3594 print <<___;
3595 .size   ecp_nistz256_precomputed,.-ecp_nistz256_precomputed
3596 ___
3597
3598 $code =~ s/\`([^\`]*)\`/eval $1/gem;
3599 print $code;
3600 close STDOUT;