ec/asm/ecp_nistz256-x86_64.pl: minor sqr_montx cleanup.
[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    .Lpoly+8*3(%rip), %rdx
1285         adox    $t0, $acc6
1286          shlx   $a_ptr, $acc0, $t0
1287         adox    $t4, $acc7
1288          shrx   $a_ptr, $acc0, $t4
1289         mov     %rdx,$t1
1290
1291         # reduction step 1
1292         add     $t0, $acc1
1293         adc     $t4, $acc2
1294
1295         mulx    $acc0, $t0, $acc0
1296         adc     $t0, $acc3
1297          shlx   $a_ptr, $acc1, $t0
1298         adc     \$0, $acc0
1299          shrx   $a_ptr, $acc1, $t4
1300
1301         # reduction step 2
1302         add     $t0, $acc2
1303         adc     $t4, $acc3
1304
1305         mulx    $acc1, $t0, $acc1
1306         adc     $t0, $acc0
1307          shlx   $a_ptr, $acc2, $t0
1308         adc     \$0, $acc1
1309          shrx   $a_ptr, $acc2, $t4
1310
1311         # reduction step 3
1312         add     $t0, $acc3
1313         adc     $t4, $acc0
1314
1315         mulx    $acc2, $t0, $acc2
1316         adc     $t0, $acc1
1317          shlx   $a_ptr, $acc3, $t0
1318         adc     \$0, $acc2
1319          shrx   $a_ptr, $acc3, $t4
1320
1321         # reduction step 4
1322         add     $t0, $acc0
1323         adc     $t4, $acc1
1324
1325         mulx    $acc3, $t0, $acc3
1326         adc     $t0, $acc2
1327         adc     \$0, $acc3
1328
1329         xor     $t3, $t3
1330         add     $acc0, $acc4            # accumulate upper half
1331          mov    .Lpoly+8*1(%rip), $a_ptr
1332         adc     $acc1, $acc5
1333          mov    $acc4, $acc0
1334         adc     $acc2, $acc6
1335         adc     $acc3, $acc7
1336          mov    $acc5, $acc1
1337         adc     \$0, $t3
1338
1339         sub     \$-1, $acc4             # .Lpoly[0]
1340          mov    $acc6, $acc2
1341         sbb     $a_ptr, $acc5           # .Lpoly[1]
1342         sbb     \$0, $acc6              # .Lpoly[2]
1343          mov    $acc7, $acc3
1344         sbb     $t1, $acc7              # .Lpoly[3]
1345         sbb     \$0, $t3
1346
1347         cmovc   $acc0, $acc4
1348         cmovc   $acc1, $acc5
1349         mov     $acc4, 8*0($r_ptr)
1350         cmovc   $acc2, $acc6
1351         mov     $acc5, 8*1($r_ptr)
1352         cmovc   $acc3, $acc7
1353         mov     $acc6, 8*2($r_ptr)
1354         mov     $acc7, 8*3($r_ptr)
1355
1356         ret
1357 .size   __ecp_nistz256_sqr_montx,.-__ecp_nistz256_sqr_montx
1358 ___
1359 }
1360 }
1361 {
1362 my ($r_ptr,$in_ptr)=("%rdi","%rsi");
1363 my ($acc0,$acc1,$acc2,$acc3)=map("%r$_",(8..11));
1364 my ($t0,$t1,$t2)=("%rcx","%r12","%r13");
1365
1366 $code.=<<___;
1367 ################################################################################
1368 # void ecp_nistz256_from_mont(
1369 #   uint64_t res[4],
1370 #   uint64_t in[4]);
1371 # This one performs Montgomery multiplication by 1, so we only need the reduction
1372
1373 .globl  ecp_nistz256_from_mont
1374 .type   ecp_nistz256_from_mont,\@function,2
1375 .align  32
1376 ecp_nistz256_from_mont:
1377 .cfi_startproc
1378         push    %r12
1379 .cfi_push       %r12
1380         push    %r13
1381 .cfi_push       %r13
1382 .Lfrom_body:
1383
1384         mov     8*0($in_ptr), %rax
1385         mov     .Lpoly+8*3(%rip), $t2
1386         mov     8*1($in_ptr), $acc1
1387         mov     8*2($in_ptr), $acc2
1388         mov     8*3($in_ptr), $acc3
1389         mov     %rax, $acc0
1390         mov     .Lpoly+8*1(%rip), $t1
1391
1392         #########################################
1393         # First iteration
1394         mov     %rax, $t0
1395         shl     \$32, $acc0
1396         mulq    $t2
1397         shr     \$32, $t0
1398         add     $acc0, $acc1
1399         adc     $t0, $acc2
1400         adc     %rax, $acc3
1401          mov    $acc1, %rax
1402         adc     \$0, %rdx
1403
1404         #########################################
1405         # Second iteration
1406         mov     $acc1, $t0
1407         shl     \$32, $acc1
1408         mov     %rdx, $acc0
1409         mulq    $t2
1410         shr     \$32, $t0
1411         add     $acc1, $acc2
1412         adc     $t0, $acc3
1413         adc     %rax, $acc0
1414          mov    $acc2, %rax
1415         adc     \$0, %rdx
1416
1417         ##########################################
1418         # Third iteration
1419         mov     $acc2, $t0
1420         shl     \$32, $acc2
1421         mov     %rdx, $acc1
1422         mulq    $t2
1423         shr     \$32, $t0
1424         add     $acc2, $acc3
1425         adc     $t0, $acc0
1426         adc     %rax, $acc1
1427          mov    $acc3, %rax
1428         adc     \$0, %rdx
1429
1430         ###########################################
1431         # Last iteration
1432         mov     $acc3, $t0
1433         shl     \$32, $acc3
1434         mov     %rdx, $acc2
1435         mulq    $t2
1436         shr     \$32, $t0
1437         add     $acc3, $acc0
1438         adc     $t0, $acc1
1439          mov    $acc0, $t0
1440         adc     %rax, $acc2
1441          mov    $acc1, $in_ptr
1442         adc     \$0, %rdx
1443
1444         ###########################################
1445         # Branch-less conditional subtraction
1446         sub     \$-1, $acc0
1447          mov    $acc2, %rax
1448         sbb     $t1, $acc1
1449         sbb     \$0, $acc2
1450          mov    %rdx, $acc3
1451         sbb     $t2, %rdx
1452         sbb     $t2, $t2
1453
1454         cmovnz  $t0, $acc0
1455         cmovnz  $in_ptr, $acc1
1456         mov     $acc0, 8*0($r_ptr)
1457         cmovnz  %rax, $acc2
1458         mov     $acc1, 8*1($r_ptr)
1459         cmovz   %rdx, $acc3
1460         mov     $acc2, 8*2($r_ptr)
1461         mov     $acc3, 8*3($r_ptr)
1462
1463         mov     0(%rsp),%r13
1464 .cfi_restore    %r13
1465         mov     8(%rsp),%r12
1466 .cfi_restore    %r12
1467         lea     16(%rsp),%rsp
1468 .cfi_adjust_cfa_offset  -16
1469 .Lfrom_epilogue:
1470         ret
1471 .cfi_endproc
1472 .size   ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
1473 ___
1474 }
1475 {
1476 my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
1477 my ($ONE,$INDEX,$Ra,$Rb,$Rc,$Rd,$Re,$Rf)=map("%xmm$_",(0..7));
1478 my ($M0,$T0a,$T0b,$T0c,$T0d,$T0e,$T0f,$TMP0)=map("%xmm$_",(8..15));
1479 my ($M1,$T2a,$T2b,$TMP2,$M2,$T2a,$T2b,$TMP2)=map("%xmm$_",(8..15));
1480
1481 $code.=<<___;
1482 ################################################################################
1483 # void ecp_nistz256_scatter_w5(uint64_t *val, uint64_t *in_t, int index);
1484 .globl  ecp_nistz256_scatter_w5
1485 .type   ecp_nistz256_scatter_w5,\@abi-omnipotent
1486 .align  32
1487 ecp_nistz256_scatter_w5:
1488         lea     -3($index,$index,2), $index
1489         movdqa  0x00($in_t), %xmm0
1490         shl     \$5, $index
1491         movdqa  0x10($in_t), %xmm1
1492         movdqa  0x20($in_t), %xmm2
1493         movdqa  0x30($in_t), %xmm3
1494         movdqa  0x40($in_t), %xmm4
1495         movdqa  0x50($in_t), %xmm5
1496         movdqa  %xmm0, 0x00($val,$index)
1497         movdqa  %xmm1, 0x10($val,$index)
1498         movdqa  %xmm2, 0x20($val,$index)
1499         movdqa  %xmm3, 0x30($val,$index)
1500         movdqa  %xmm4, 0x40($val,$index)
1501         movdqa  %xmm5, 0x50($val,$index)
1502
1503         ret
1504 .size   ecp_nistz256_scatter_w5,.-ecp_nistz256_scatter_w5
1505
1506 ################################################################################
1507 # void ecp_nistz256_gather_w5(uint64_t *val, uint64_t *in_t, int index);
1508 .globl  ecp_nistz256_gather_w5
1509 .type   ecp_nistz256_gather_w5,\@abi-omnipotent
1510 .align  32
1511 ecp_nistz256_gather_w5:
1512 ___
1513 $code.=<<___    if ($avx>1);
1514         mov     OPENSSL_ia32cap_P+8(%rip), %eax
1515         test    \$`1<<5`, %eax
1516         jnz     .Lavx2_gather_w5
1517 ___
1518 $code.=<<___    if ($win64);
1519         lea     -0x88(%rsp), %rax
1520 .LSEH_begin_ecp_nistz256_gather_w5:
1521         .byte   0x48,0x8d,0x60,0xe0             #lea    -0x20(%rax), %rsp
1522         .byte   0x0f,0x29,0x70,0xe0             #movaps %xmm6, -0x20(%rax)
1523         .byte   0x0f,0x29,0x78,0xf0             #movaps %xmm7, -0x10(%rax)
1524         .byte   0x44,0x0f,0x29,0x00             #movaps %xmm8, 0(%rax)
1525         .byte   0x44,0x0f,0x29,0x48,0x10        #movaps %xmm9, 0x10(%rax)
1526         .byte   0x44,0x0f,0x29,0x50,0x20        #movaps %xmm10, 0x20(%rax)
1527         .byte   0x44,0x0f,0x29,0x58,0x30        #movaps %xmm11, 0x30(%rax)
1528         .byte   0x44,0x0f,0x29,0x60,0x40        #movaps %xmm12, 0x40(%rax)
1529         .byte   0x44,0x0f,0x29,0x68,0x50        #movaps %xmm13, 0x50(%rax)
1530         .byte   0x44,0x0f,0x29,0x70,0x60        #movaps %xmm14, 0x60(%rax)
1531         .byte   0x44,0x0f,0x29,0x78,0x70        #movaps %xmm15, 0x70(%rax)
1532 ___
1533 $code.=<<___;
1534         movdqa  .LOne(%rip), $ONE
1535         movd    $index, $INDEX
1536
1537         pxor    $Ra, $Ra
1538         pxor    $Rb, $Rb
1539         pxor    $Rc, $Rc
1540         pxor    $Rd, $Rd
1541         pxor    $Re, $Re
1542         pxor    $Rf, $Rf
1543
1544         movdqa  $ONE, $M0
1545         pshufd  \$0, $INDEX, $INDEX
1546
1547         mov     \$16, %rax
1548 .Lselect_loop_sse_w5:
1549
1550         movdqa  $M0, $TMP0
1551         paddd   $ONE, $M0
1552         pcmpeqd $INDEX, $TMP0
1553
1554         movdqa  16*0($in_t), $T0a
1555         movdqa  16*1($in_t), $T0b
1556         movdqa  16*2($in_t), $T0c
1557         movdqa  16*3($in_t), $T0d
1558         movdqa  16*4($in_t), $T0e
1559         movdqa  16*5($in_t), $T0f
1560         lea 16*6($in_t), $in_t
1561
1562         pand    $TMP0, $T0a
1563         pand    $TMP0, $T0b
1564         por     $T0a, $Ra
1565         pand    $TMP0, $T0c
1566         por     $T0b, $Rb
1567         pand    $TMP0, $T0d
1568         por     $T0c, $Rc
1569         pand    $TMP0, $T0e
1570         por     $T0d, $Rd
1571         pand    $TMP0, $T0f
1572         por     $T0e, $Re
1573         por     $T0f, $Rf
1574
1575         dec     %rax
1576         jnz     .Lselect_loop_sse_w5
1577
1578         movdqu  $Ra, 16*0($val)
1579         movdqu  $Rb, 16*1($val)
1580         movdqu  $Rc, 16*2($val)
1581         movdqu  $Rd, 16*3($val)
1582         movdqu  $Re, 16*4($val)
1583         movdqu  $Rf, 16*5($val)
1584 ___
1585 $code.=<<___    if ($win64);
1586         movaps  (%rsp), %xmm6
1587         movaps  0x10(%rsp), %xmm7
1588         movaps  0x20(%rsp), %xmm8
1589         movaps  0x30(%rsp), %xmm9
1590         movaps  0x40(%rsp), %xmm10
1591         movaps  0x50(%rsp), %xmm11
1592         movaps  0x60(%rsp), %xmm12
1593         movaps  0x70(%rsp), %xmm13
1594         movaps  0x80(%rsp), %xmm14
1595         movaps  0x90(%rsp), %xmm15
1596         lea     0xa8(%rsp), %rsp
1597 ___
1598 $code.=<<___;
1599         ret
1600 .LSEH_end_ecp_nistz256_gather_w5:
1601 .size   ecp_nistz256_gather_w5,.-ecp_nistz256_gather_w5
1602
1603 ################################################################################
1604 # void ecp_nistz256_scatter_w7(uint64_t *val, uint64_t *in_t, int index);
1605 .globl  ecp_nistz256_scatter_w7
1606 .type   ecp_nistz256_scatter_w7,\@abi-omnipotent
1607 .align  32
1608 ecp_nistz256_scatter_w7:
1609         movdqu  0x00($in_t), %xmm0
1610         shl     \$6, $index
1611         movdqu  0x10($in_t), %xmm1
1612         movdqu  0x20($in_t), %xmm2
1613         movdqu  0x30($in_t), %xmm3
1614         movdqa  %xmm0, 0x00($val,$index)
1615         movdqa  %xmm1, 0x10($val,$index)
1616         movdqa  %xmm2, 0x20($val,$index)
1617         movdqa  %xmm3, 0x30($val,$index)
1618
1619         ret
1620 .size   ecp_nistz256_scatter_w7,.-ecp_nistz256_scatter_w7
1621
1622 ################################################################################
1623 # void ecp_nistz256_gather_w7(uint64_t *val, uint64_t *in_t, int index);
1624 .globl  ecp_nistz256_gather_w7
1625 .type   ecp_nistz256_gather_w7,\@abi-omnipotent
1626 .align  32
1627 ecp_nistz256_gather_w7:
1628 ___
1629 $code.=<<___    if ($avx>1);
1630         mov     OPENSSL_ia32cap_P+8(%rip), %eax
1631         test    \$`1<<5`, %eax
1632         jnz     .Lavx2_gather_w7
1633 ___
1634 $code.=<<___    if ($win64);
1635         lea     -0x88(%rsp), %rax
1636 .LSEH_begin_ecp_nistz256_gather_w7:
1637         .byte   0x48,0x8d,0x60,0xe0             #lea    -0x20(%rax), %rsp
1638         .byte   0x0f,0x29,0x70,0xe0             #movaps %xmm6, -0x20(%rax)
1639         .byte   0x0f,0x29,0x78,0xf0             #movaps %xmm7, -0x10(%rax)
1640         .byte   0x44,0x0f,0x29,0x00             #movaps %xmm8, 0(%rax)
1641         .byte   0x44,0x0f,0x29,0x48,0x10        #movaps %xmm9, 0x10(%rax)
1642         .byte   0x44,0x0f,0x29,0x50,0x20        #movaps %xmm10, 0x20(%rax)
1643         .byte   0x44,0x0f,0x29,0x58,0x30        #movaps %xmm11, 0x30(%rax)
1644         .byte   0x44,0x0f,0x29,0x60,0x40        #movaps %xmm12, 0x40(%rax)
1645         .byte   0x44,0x0f,0x29,0x68,0x50        #movaps %xmm13, 0x50(%rax)
1646         .byte   0x44,0x0f,0x29,0x70,0x60        #movaps %xmm14, 0x60(%rax)
1647         .byte   0x44,0x0f,0x29,0x78,0x70        #movaps %xmm15, 0x70(%rax)
1648 ___
1649 $code.=<<___;
1650         movdqa  .LOne(%rip), $M0
1651         movd    $index, $INDEX
1652
1653         pxor    $Ra, $Ra
1654         pxor    $Rb, $Rb
1655         pxor    $Rc, $Rc
1656         pxor    $Rd, $Rd
1657
1658         movdqa  $M0, $ONE
1659         pshufd  \$0, $INDEX, $INDEX
1660         mov     \$64, %rax
1661
1662 .Lselect_loop_sse_w7:
1663         movdqa  $M0, $TMP0
1664         paddd   $ONE, $M0
1665         movdqa  16*0($in_t), $T0a
1666         movdqa  16*1($in_t), $T0b
1667         pcmpeqd $INDEX, $TMP0
1668         movdqa  16*2($in_t), $T0c
1669         movdqa  16*3($in_t), $T0d
1670         lea     16*4($in_t), $in_t
1671
1672         pand    $TMP0, $T0a
1673         pand    $TMP0, $T0b
1674         por     $T0a, $Ra
1675         pand    $TMP0, $T0c
1676         por     $T0b, $Rb
1677         pand    $TMP0, $T0d
1678         por     $T0c, $Rc
1679         prefetcht0      255($in_t)
1680         por     $T0d, $Rd
1681
1682         dec     %rax
1683         jnz     .Lselect_loop_sse_w7
1684
1685         movdqu  $Ra, 16*0($val)
1686         movdqu  $Rb, 16*1($val)
1687         movdqu  $Rc, 16*2($val)
1688         movdqu  $Rd, 16*3($val)
1689 ___
1690 $code.=<<___    if ($win64);
1691         movaps  (%rsp), %xmm6
1692         movaps  0x10(%rsp), %xmm7
1693         movaps  0x20(%rsp), %xmm8
1694         movaps  0x30(%rsp), %xmm9
1695         movaps  0x40(%rsp), %xmm10
1696         movaps  0x50(%rsp), %xmm11
1697         movaps  0x60(%rsp), %xmm12
1698         movaps  0x70(%rsp), %xmm13
1699         movaps  0x80(%rsp), %xmm14
1700         movaps  0x90(%rsp), %xmm15
1701         lea     0xa8(%rsp), %rsp
1702 ___
1703 $code.=<<___;
1704         ret
1705 .LSEH_end_ecp_nistz256_gather_w7:
1706 .size   ecp_nistz256_gather_w7,.-ecp_nistz256_gather_w7
1707 ___
1708 }
1709 if ($avx>1) {
1710 my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
1711 my ($TWO,$INDEX,$Ra,$Rb,$Rc)=map("%ymm$_",(0..4));
1712 my ($M0,$T0a,$T0b,$T0c,$TMP0)=map("%ymm$_",(5..9));
1713 my ($M1,$T1a,$T1b,$T1c,$TMP1)=map("%ymm$_",(10..14));
1714
1715 $code.=<<___;
1716 ################################################################################
1717 # void ecp_nistz256_avx2_gather_w5(uint64_t *val, uint64_t *in_t, int index);
1718 .type   ecp_nistz256_avx2_gather_w5,\@abi-omnipotent
1719 .align  32
1720 ecp_nistz256_avx2_gather_w5:
1721 .Lavx2_gather_w5:
1722         vzeroupper
1723 ___
1724 $code.=<<___    if ($win64);
1725         lea     -0x88(%rsp), %rax
1726         mov     %rsp,%r11
1727 .LSEH_begin_ecp_nistz256_avx2_gather_w5:
1728         .byte   0x48,0x8d,0x60,0xe0             # lea   -0x20(%rax), %rsp
1729         .byte   0xc5,0xf8,0x29,0x70,0xe0        # vmovaps %xmm6, -0x20(%rax)
1730         .byte   0xc5,0xf8,0x29,0x78,0xf0        # vmovaps %xmm7, -0x10(%rax)
1731         .byte   0xc5,0x78,0x29,0x40,0x00        # vmovaps %xmm8, 8(%rax)
1732         .byte   0xc5,0x78,0x29,0x48,0x10        # vmovaps %xmm9, 0x10(%rax)
1733         .byte   0xc5,0x78,0x29,0x50,0x20        # vmovaps %xmm10, 0x20(%rax)
1734         .byte   0xc5,0x78,0x29,0x58,0x30        # vmovaps %xmm11, 0x30(%rax)
1735         .byte   0xc5,0x78,0x29,0x60,0x40        # vmovaps %xmm12, 0x40(%rax)
1736         .byte   0xc5,0x78,0x29,0x68,0x50        # vmovaps %xmm13, 0x50(%rax)
1737         .byte   0xc5,0x78,0x29,0x70,0x60        # vmovaps %xmm14, 0x60(%rax)
1738         .byte   0xc5,0x78,0x29,0x78,0x70        # vmovaps %xmm15, 0x70(%rax)
1739 ___
1740 $code.=<<___;
1741         vmovdqa .LTwo(%rip), $TWO
1742
1743         vpxor   $Ra, $Ra, $Ra
1744         vpxor   $Rb, $Rb, $Rb
1745         vpxor   $Rc, $Rc, $Rc
1746
1747         vmovdqa .LOne(%rip), $M0
1748         vmovdqa .LTwo(%rip), $M1
1749
1750         vmovd   $index, %xmm1
1751         vpermd  $INDEX, $Ra, $INDEX
1752
1753         mov     \$8, %rax
1754 .Lselect_loop_avx2_w5:
1755
1756         vmovdqa 32*0($in_t), $T0a
1757         vmovdqa 32*1($in_t), $T0b
1758         vmovdqa 32*2($in_t), $T0c
1759
1760         vmovdqa 32*3($in_t), $T1a
1761         vmovdqa 32*4($in_t), $T1b
1762         vmovdqa 32*5($in_t), $T1c
1763
1764         vpcmpeqd        $INDEX, $M0, $TMP0
1765         vpcmpeqd        $INDEX, $M1, $TMP1
1766
1767         vpaddd  $TWO, $M0, $M0
1768         vpaddd  $TWO, $M1, $M1
1769         lea     32*6($in_t), $in_t
1770
1771         vpand   $TMP0, $T0a, $T0a
1772         vpand   $TMP0, $T0b, $T0b
1773         vpand   $TMP0, $T0c, $T0c
1774         vpand   $TMP1, $T1a, $T1a
1775         vpand   $TMP1, $T1b, $T1b
1776         vpand   $TMP1, $T1c, $T1c
1777
1778         vpxor   $T0a, $Ra, $Ra
1779         vpxor   $T0b, $Rb, $Rb
1780         vpxor   $T0c, $Rc, $Rc
1781         vpxor   $T1a, $Ra, $Ra
1782         vpxor   $T1b, $Rb, $Rb
1783         vpxor   $T1c, $Rc, $Rc
1784
1785         dec %rax
1786         jnz .Lselect_loop_avx2_w5
1787
1788         vmovdqu $Ra, 32*0($val)
1789         vmovdqu $Rb, 32*1($val)
1790         vmovdqu $Rc, 32*2($val)
1791         vzeroupper
1792 ___
1793 $code.=<<___    if ($win64);
1794         movaps  (%rsp), %xmm6
1795         movaps  0x10(%rsp), %xmm7
1796         movaps  0x20(%rsp), %xmm8
1797         movaps  0x30(%rsp), %xmm9
1798         movaps  0x40(%rsp), %xmm10
1799         movaps  0x50(%rsp), %xmm11
1800         movaps  0x60(%rsp), %xmm12
1801         movaps  0x70(%rsp), %xmm13
1802         movaps  0x80(%rsp), %xmm14
1803         movaps  0x90(%rsp), %xmm15
1804         lea     (%r11), %rsp
1805 ___
1806 $code.=<<___;
1807         ret
1808 .LSEH_end_ecp_nistz256_avx2_gather_w5:
1809 .size   ecp_nistz256_avx2_gather_w5,.-ecp_nistz256_avx2_gather_w5
1810 ___
1811 }
1812 if ($avx>1) {
1813 my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
1814 my ($THREE,$INDEX,$Ra,$Rb)=map("%ymm$_",(0..3));
1815 my ($M0,$T0a,$T0b,$TMP0)=map("%ymm$_",(4..7));
1816 my ($M1,$T1a,$T1b,$TMP1)=map("%ymm$_",(8..11));
1817 my ($M2,$T2a,$T2b,$TMP2)=map("%ymm$_",(12..15));
1818
1819 $code.=<<___;
1820
1821 ################################################################################
1822 # void ecp_nistz256_avx2_gather_w7(uint64_t *val, uint64_t *in_t, int index);
1823 .globl  ecp_nistz256_avx2_gather_w7
1824 .type   ecp_nistz256_avx2_gather_w7,\@abi-omnipotent
1825 .align  32
1826 ecp_nistz256_avx2_gather_w7:
1827 .Lavx2_gather_w7:
1828         vzeroupper
1829 ___
1830 $code.=<<___    if ($win64);
1831         mov     %rsp,%r11
1832         lea     -0x88(%rsp), %rax
1833 .LSEH_begin_ecp_nistz256_avx2_gather_w7:
1834         .byte   0x48,0x8d,0x60,0xe0             # lea   -0x20(%rax), %rsp
1835         .byte   0xc5,0xf8,0x29,0x70,0xe0        # vmovaps %xmm6, -0x20(%rax)
1836         .byte   0xc5,0xf8,0x29,0x78,0xf0        # vmovaps %xmm7, -0x10(%rax)
1837         .byte   0xc5,0x78,0x29,0x40,0x00        # vmovaps %xmm8, 8(%rax)
1838         .byte   0xc5,0x78,0x29,0x48,0x10        # vmovaps %xmm9, 0x10(%rax)
1839         .byte   0xc5,0x78,0x29,0x50,0x20        # vmovaps %xmm10, 0x20(%rax)
1840         .byte   0xc5,0x78,0x29,0x58,0x30        # vmovaps %xmm11, 0x30(%rax)
1841         .byte   0xc5,0x78,0x29,0x60,0x40        # vmovaps %xmm12, 0x40(%rax)
1842         .byte   0xc5,0x78,0x29,0x68,0x50        # vmovaps %xmm13, 0x50(%rax)
1843         .byte   0xc5,0x78,0x29,0x70,0x60        # vmovaps %xmm14, 0x60(%rax)
1844         .byte   0xc5,0x78,0x29,0x78,0x70        # vmovaps %xmm15, 0x70(%rax)
1845 ___
1846 $code.=<<___;
1847         vmovdqa .LThree(%rip), $THREE
1848
1849         vpxor   $Ra, $Ra, $Ra
1850         vpxor   $Rb, $Rb, $Rb
1851
1852         vmovdqa .LOne(%rip), $M0
1853         vmovdqa .LTwo(%rip), $M1
1854         vmovdqa .LThree(%rip), $M2
1855
1856         vmovd   $index, %xmm1
1857         vpermd  $INDEX, $Ra, $INDEX
1858         # Skip index = 0, because it is implicitly the point at infinity
1859
1860         mov     \$21, %rax
1861 .Lselect_loop_avx2_w7:
1862
1863         vmovdqa 32*0($in_t), $T0a
1864         vmovdqa 32*1($in_t), $T0b
1865
1866         vmovdqa 32*2($in_t), $T1a
1867         vmovdqa 32*3($in_t), $T1b
1868
1869         vmovdqa 32*4($in_t), $T2a
1870         vmovdqa 32*5($in_t), $T2b
1871
1872         vpcmpeqd        $INDEX, $M0, $TMP0
1873         vpcmpeqd        $INDEX, $M1, $TMP1
1874         vpcmpeqd        $INDEX, $M2, $TMP2
1875
1876         vpaddd  $THREE, $M0, $M0
1877         vpaddd  $THREE, $M1, $M1
1878         vpaddd  $THREE, $M2, $M2
1879         lea     32*6($in_t), $in_t
1880
1881         vpand   $TMP0, $T0a, $T0a
1882         vpand   $TMP0, $T0b, $T0b
1883         vpand   $TMP1, $T1a, $T1a
1884         vpand   $TMP1, $T1b, $T1b
1885         vpand   $TMP2, $T2a, $T2a
1886         vpand   $TMP2, $T2b, $T2b
1887
1888         vpxor   $T0a, $Ra, $Ra
1889         vpxor   $T0b, $Rb, $Rb
1890         vpxor   $T1a, $Ra, $Ra
1891         vpxor   $T1b, $Rb, $Rb
1892         vpxor   $T2a, $Ra, $Ra
1893         vpxor   $T2b, $Rb, $Rb
1894
1895         dec %rax
1896         jnz .Lselect_loop_avx2_w7
1897
1898
1899         vmovdqa 32*0($in_t), $T0a
1900         vmovdqa 32*1($in_t), $T0b
1901
1902         vpcmpeqd        $INDEX, $M0, $TMP0
1903
1904         vpand   $TMP0, $T0a, $T0a
1905         vpand   $TMP0, $T0b, $T0b
1906
1907         vpxor   $T0a, $Ra, $Ra
1908         vpxor   $T0b, $Rb, $Rb
1909
1910         vmovdqu $Ra, 32*0($val)
1911         vmovdqu $Rb, 32*1($val)
1912         vzeroupper
1913 ___
1914 $code.=<<___    if ($win64);
1915         movaps  (%rsp), %xmm6
1916         movaps  0x10(%rsp), %xmm7
1917         movaps  0x20(%rsp), %xmm8
1918         movaps  0x30(%rsp), %xmm9
1919         movaps  0x40(%rsp), %xmm10
1920         movaps  0x50(%rsp), %xmm11
1921         movaps  0x60(%rsp), %xmm12
1922         movaps  0x70(%rsp), %xmm13
1923         movaps  0x80(%rsp), %xmm14
1924         movaps  0x90(%rsp), %xmm15
1925         lea     (%r11), %rsp
1926 ___
1927 $code.=<<___;
1928         ret
1929 .LSEH_end_ecp_nistz256_avx2_gather_w7:
1930 .size   ecp_nistz256_avx2_gather_w7,.-ecp_nistz256_avx2_gather_w7
1931 ___
1932 } else {
1933 $code.=<<___;
1934 .globl  ecp_nistz256_avx2_gather_w7
1935 .type   ecp_nistz256_avx2_gather_w7,\@function,3
1936 .align  32
1937 ecp_nistz256_avx2_gather_w7:
1938         .byte   0x0f,0x0b       # ud2
1939         ret
1940 .size   ecp_nistz256_avx2_gather_w7,.-ecp_nistz256_avx2_gather_w7
1941 ___
1942 }
1943 {{{
1944 ########################################################################
1945 # This block implements higher level point_double, point_add and
1946 # point_add_affine. The key to performance in this case is to allow
1947 # out-of-order execution logic to overlap computations from next step
1948 # with tail processing from current step. By using tailored calling
1949 # sequence we minimize inter-step overhead to give processor better
1950 # shot at overlapping operations...
1951 #
1952 # You will notice that input data is copied to stack. Trouble is that
1953 # there are no registers to spare for holding original pointers and
1954 # reloading them, pointers, would create undesired dependencies on
1955 # effective addresses calculation paths. In other words it's too done
1956 # to favour out-of-order execution logic.
1957 #                                               <appro@openssl.org>
1958
1959 my ($r_ptr,$a_ptr,$b_org,$b_ptr)=("%rdi","%rsi","%rdx","%rbx");
1960 my ($acc0,$acc1,$acc2,$acc3,$acc4,$acc5,$acc6,$acc7)=map("%r$_",(8..15));
1961 my ($t0,$t1,$t2,$t3,$t4)=("%rax","%rbp","%rcx",$acc4,$acc4);
1962 my ($poly1,$poly3)=($acc6,$acc7);
1963
1964 sub load_for_mul () {
1965 my ($a,$b,$src0) = @_;
1966 my $bias = $src0 eq "%rax" ? 0 : -128;
1967
1968 "       mov     $b, $src0
1969         lea     $b, $b_ptr
1970         mov     8*0+$a, $acc1
1971         mov     8*1+$a, $acc2
1972         lea     $bias+$a, $a_ptr
1973         mov     8*2+$a, $acc3
1974         mov     8*3+$a, $acc4"
1975 }
1976
1977 sub load_for_sqr () {
1978 my ($a,$src0) = @_;
1979 my $bias = $src0 eq "%rax" ? 0 : -128;
1980
1981 "       mov     8*0+$a, $src0
1982         mov     8*1+$a, $acc6
1983         lea     $bias+$a, $a_ptr
1984         mov     8*2+$a, $acc7
1985         mov     8*3+$a, $acc0"
1986 }
1987
1988                                                                         {
1989 ########################################################################
1990 # operate in 4-5-0-1 "name space" that matches multiplication output
1991 #
1992 my ($a0,$a1,$a2,$a3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
1993
1994 $code.=<<___;
1995 .type   __ecp_nistz256_add_toq,\@abi-omnipotent
1996 .align  32
1997 __ecp_nistz256_add_toq:
1998         xor     $t4,$t4
1999         add     8*0($b_ptr), $a0
2000         adc     8*1($b_ptr), $a1
2001          mov    $a0, $t0
2002         adc     8*2($b_ptr), $a2
2003         adc     8*3($b_ptr), $a3
2004          mov    $a1, $t1
2005         adc     \$0, $t4
2006
2007         sub     \$-1, $a0
2008          mov    $a2, $t2
2009         sbb     $poly1, $a1
2010         sbb     \$0, $a2
2011          mov    $a3, $t3
2012         sbb     $poly3, $a3
2013         sbb     \$0, $t4
2014
2015         cmovc   $t0, $a0
2016         cmovc   $t1, $a1
2017         mov     $a0, 8*0($r_ptr)
2018         cmovc   $t2, $a2
2019         mov     $a1, 8*1($r_ptr)
2020         cmovc   $t3, $a3
2021         mov     $a2, 8*2($r_ptr)
2022         mov     $a3, 8*3($r_ptr)
2023
2024         ret
2025 .size   __ecp_nistz256_add_toq,.-__ecp_nistz256_add_toq
2026
2027 .type   __ecp_nistz256_sub_fromq,\@abi-omnipotent
2028 .align  32
2029 __ecp_nistz256_sub_fromq:
2030         sub     8*0($b_ptr), $a0
2031         sbb     8*1($b_ptr), $a1
2032          mov    $a0, $t0
2033         sbb     8*2($b_ptr), $a2
2034         sbb     8*3($b_ptr), $a3
2035          mov    $a1, $t1
2036         sbb     $t4, $t4
2037
2038         add     \$-1, $a0
2039          mov    $a2, $t2
2040         adc     $poly1, $a1
2041         adc     \$0, $a2
2042          mov    $a3, $t3
2043         adc     $poly3, $a3
2044         test    $t4, $t4
2045
2046         cmovz   $t0, $a0
2047         cmovz   $t1, $a1
2048         mov     $a0, 8*0($r_ptr)
2049         cmovz   $t2, $a2
2050         mov     $a1, 8*1($r_ptr)
2051         cmovz   $t3, $a3
2052         mov     $a2, 8*2($r_ptr)
2053         mov     $a3, 8*3($r_ptr)
2054
2055         ret
2056 .size   __ecp_nistz256_sub_fromq,.-__ecp_nistz256_sub_fromq
2057
2058 .type   __ecp_nistz256_subq,\@abi-omnipotent
2059 .align  32
2060 __ecp_nistz256_subq:
2061         sub     $a0, $t0
2062         sbb     $a1, $t1
2063          mov    $t0, $a0
2064         sbb     $a2, $t2
2065         sbb     $a3, $t3
2066          mov    $t1, $a1
2067         sbb     $t4, $t4
2068
2069         add     \$-1, $t0
2070          mov    $t2, $a2
2071         adc     $poly1, $t1
2072         adc     \$0, $t2
2073          mov    $t3, $a3
2074         adc     $poly3, $t3
2075         test    $t4, $t4
2076
2077         cmovnz  $t0, $a0
2078         cmovnz  $t1, $a1
2079         cmovnz  $t2, $a2
2080         cmovnz  $t3, $a3
2081
2082         ret
2083 .size   __ecp_nistz256_subq,.-__ecp_nistz256_subq
2084
2085 .type   __ecp_nistz256_mul_by_2q,\@abi-omnipotent
2086 .align  32
2087 __ecp_nistz256_mul_by_2q:
2088         xor     $t4, $t4
2089         add     $a0, $a0                # a0:a3+a0:a3
2090         adc     $a1, $a1
2091          mov    $a0, $t0
2092         adc     $a2, $a2
2093         adc     $a3, $a3
2094          mov    $a1, $t1
2095         adc     \$0, $t4
2096
2097         sub     \$-1, $a0
2098          mov    $a2, $t2
2099         sbb     $poly1, $a1
2100         sbb     \$0, $a2
2101          mov    $a3, $t3
2102         sbb     $poly3, $a3
2103         sbb     \$0, $t4
2104
2105         cmovc   $t0, $a0
2106         cmovc   $t1, $a1
2107         mov     $a0, 8*0($r_ptr)
2108         cmovc   $t2, $a2
2109         mov     $a1, 8*1($r_ptr)
2110         cmovc   $t3, $a3
2111         mov     $a2, 8*2($r_ptr)
2112         mov     $a3, 8*3($r_ptr)
2113
2114         ret
2115 .size   __ecp_nistz256_mul_by_2q,.-__ecp_nistz256_mul_by_2q
2116 ___
2117                                                                         }
2118 sub gen_double () {
2119     my $x = shift;
2120     my ($src0,$sfx,$bias);
2121     my ($S,$M,$Zsqr,$in_x,$tmp0)=map(32*$_,(0..4));
2122
2123     if ($x ne "x") {
2124         $src0 = "%rax";
2125         $sfx  = "";
2126         $bias = 0;
2127
2128 $code.=<<___;
2129 .globl  ecp_nistz256_point_double
2130 .type   ecp_nistz256_point_double,\@function,2
2131 .align  32
2132 ecp_nistz256_point_double:
2133 .cfi_startproc
2134 ___
2135 $code.=<<___    if ($addx);
2136         mov     \$0x80100, %ecx
2137         and     OPENSSL_ia32cap_P+8(%rip), %ecx
2138         cmp     \$0x80100, %ecx
2139         je      .Lpoint_doublex
2140 ___
2141     } else {
2142         $src0 = "%rdx";
2143         $sfx  = "x";
2144         $bias = 128;
2145
2146 $code.=<<___;
2147 .type   ecp_nistz256_point_doublex,\@function,2
2148 .align  32
2149 ecp_nistz256_point_doublex:
2150 .cfi_startproc
2151 .Lpoint_doublex:
2152 ___
2153     }
2154 $code.=<<___;
2155         push    %rbp
2156 .cfi_push       %rbp
2157         push    %rbx
2158 .cfi_push       %rbx
2159         push    %r12
2160 .cfi_push       %r12
2161         push    %r13
2162 .cfi_push       %r13
2163         push    %r14
2164 .cfi_push       %r14
2165         push    %r15
2166 .cfi_push       %r15
2167         sub     \$32*5+8, %rsp
2168 .cfi_adjust_cfa_offset  32*5+8
2169 .Lpoint_double${x}_body:
2170
2171 .Lpoint_double_shortcut$x:
2172         movdqu  0x00($a_ptr), %xmm0             # copy  *(P256_POINT *)$a_ptr.x
2173         mov     $a_ptr, $b_ptr                  # backup copy
2174         movdqu  0x10($a_ptr), %xmm1
2175          mov    0x20+8*0($a_ptr), $acc4         # load in_y in "5-4-0-1" order
2176          mov    0x20+8*1($a_ptr), $acc5
2177          mov    0x20+8*2($a_ptr), $acc0
2178          mov    0x20+8*3($a_ptr), $acc1
2179          mov    .Lpoly+8*1(%rip), $poly1
2180          mov    .Lpoly+8*3(%rip), $poly3
2181         movdqa  %xmm0, $in_x(%rsp)
2182         movdqa  %xmm1, $in_x+0x10(%rsp)
2183         lea     0x20($r_ptr), $acc2
2184         lea     0x40($r_ptr), $acc3
2185         movq    $r_ptr, %xmm0
2186         movq    $acc2, %xmm1
2187         movq    $acc3, %xmm2
2188
2189         lea     $S(%rsp), $r_ptr
2190         call    __ecp_nistz256_mul_by_2$x       # p256_mul_by_2(S, in_y);
2191
2192         mov     0x40+8*0($a_ptr), $src0
2193         mov     0x40+8*1($a_ptr), $acc6
2194         mov     0x40+8*2($a_ptr), $acc7
2195         mov     0x40+8*3($a_ptr), $acc0
2196         lea     0x40-$bias($a_ptr), $a_ptr
2197         lea     $Zsqr(%rsp), $r_ptr
2198         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Zsqr, in_z);
2199
2200         `&load_for_sqr("$S(%rsp)", "$src0")`
2201         lea     $S(%rsp), $r_ptr
2202         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(S, S);
2203
2204         mov     0x20($b_ptr), $src0             # $b_ptr is still valid
2205         mov     0x40+8*0($b_ptr), $acc1
2206         mov     0x40+8*1($b_ptr), $acc2
2207         mov     0x40+8*2($b_ptr), $acc3
2208         mov     0x40+8*3($b_ptr), $acc4
2209         lea     0x40-$bias($b_ptr), $a_ptr
2210         lea     0x20($b_ptr), $b_ptr
2211         movq    %xmm2, $r_ptr
2212         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_z, in_z, in_y);
2213         call    __ecp_nistz256_mul_by_2$x       # p256_mul_by_2(res_z, res_z);
2214
2215         mov     $in_x+8*0(%rsp), $acc4          # "5-4-0-1" order
2216         mov     $in_x+8*1(%rsp), $acc5
2217         lea     $Zsqr(%rsp), $b_ptr
2218         mov     $in_x+8*2(%rsp), $acc0
2219         mov     $in_x+8*3(%rsp), $acc1
2220         lea     $M(%rsp), $r_ptr
2221         call    __ecp_nistz256_add_to$x         # p256_add(M, in_x, Zsqr);
2222
2223         mov     $in_x+8*0(%rsp), $acc4          # "5-4-0-1" order
2224         mov     $in_x+8*1(%rsp), $acc5
2225         lea     $Zsqr(%rsp), $b_ptr
2226         mov     $in_x+8*2(%rsp), $acc0
2227         mov     $in_x+8*3(%rsp), $acc1
2228         lea     $Zsqr(%rsp), $r_ptr
2229         call    __ecp_nistz256_sub_from$x       # p256_sub(Zsqr, in_x, Zsqr);
2230
2231         `&load_for_sqr("$S(%rsp)", "$src0")`
2232         movq    %xmm1, $r_ptr
2233         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(res_y, S);
2234 ___
2235 {
2236 ######## ecp_nistz256_div_by_2(res_y, res_y); ##########################
2237 # operate in 4-5-6-7 "name space" that matches squaring output
2238 #
2239 my ($poly1,$poly3)=($a_ptr,$t1);
2240 my ($a0,$a1,$a2,$a3,$t3,$t4,$t1)=($acc4,$acc5,$acc6,$acc7,$acc0,$acc1,$acc2);
2241
2242 $code.=<<___;
2243         xor     $t4, $t4
2244         mov     $a0, $t0
2245         add     \$-1, $a0
2246         mov     $a1, $t1
2247         adc     $poly1, $a1
2248         mov     $a2, $t2
2249         adc     \$0, $a2
2250         mov     $a3, $t3
2251         adc     $poly3, $a3
2252         adc     \$0, $t4
2253         xor     $a_ptr, $a_ptr          # borrow $a_ptr
2254         test    \$1, $t0
2255
2256         cmovz   $t0, $a0
2257         cmovz   $t1, $a1
2258         cmovz   $t2, $a2
2259         cmovz   $t3, $a3
2260         cmovz   $a_ptr, $t4
2261
2262         mov     $a1, $t0                # a0:a3>>1
2263         shr     \$1, $a0
2264         shl     \$63, $t0
2265         mov     $a2, $t1
2266         shr     \$1, $a1
2267         or      $t0, $a0
2268         shl     \$63, $t1
2269         mov     $a3, $t2
2270         shr     \$1, $a2
2271         or      $t1, $a1
2272         shl     \$63, $t2
2273         mov     $a0, 8*0($r_ptr)
2274         shr     \$1, $a3
2275         mov     $a1, 8*1($r_ptr)
2276         shl     \$63, $t4
2277         or      $t2, $a2
2278         or      $t4, $a3
2279         mov     $a2, 8*2($r_ptr)
2280         mov     $a3, 8*3($r_ptr)
2281 ___
2282 }
2283 $code.=<<___;
2284         `&load_for_mul("$M(%rsp)", "$Zsqr(%rsp)", "$src0")`
2285         lea     $M(%rsp), $r_ptr
2286         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(M, M, Zsqr);
2287
2288         lea     $tmp0(%rsp), $r_ptr
2289         call    __ecp_nistz256_mul_by_2$x
2290
2291         lea     $M(%rsp), $b_ptr
2292         lea     $M(%rsp), $r_ptr
2293         call    __ecp_nistz256_add_to$x         # p256_mul_by_3(M, M);
2294
2295         `&load_for_mul("$S(%rsp)", "$in_x(%rsp)", "$src0")`
2296         lea     $S(%rsp), $r_ptr
2297         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S, S, in_x);
2298
2299         lea     $tmp0(%rsp), $r_ptr
2300         call    __ecp_nistz256_mul_by_2$x       # p256_mul_by_2(tmp0, S);
2301
2302         `&load_for_sqr("$M(%rsp)", "$src0")`
2303         movq    %xmm0, $r_ptr
2304         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(res_x, M);
2305
2306         lea     $tmp0(%rsp), $b_ptr
2307         mov     $acc6, $acc0                    # harmonize sqr output and sub input
2308         mov     $acc7, $acc1
2309         mov     $a_ptr, $poly1
2310         mov     $t1, $poly3
2311         call    __ecp_nistz256_sub_from$x       # p256_sub(res_x, res_x, tmp0);
2312
2313         mov     $S+8*0(%rsp), $t0
2314         mov     $S+8*1(%rsp), $t1
2315         mov     $S+8*2(%rsp), $t2
2316         mov     $S+8*3(%rsp), $acc2             # "4-5-0-1" order
2317         lea     $S(%rsp), $r_ptr
2318         call    __ecp_nistz256_sub$x            # p256_sub(S, S, res_x);
2319
2320         mov     $M(%rsp), $src0
2321         lea     $M(%rsp), $b_ptr
2322         mov     $acc4, $acc6                    # harmonize sub output and mul input
2323         xor     %ecx, %ecx
2324         mov     $acc4, $S+8*0(%rsp)             # have to save:-(
2325         mov     $acc5, $acc2
2326         mov     $acc5, $S+8*1(%rsp)
2327         cmovz   $acc0, $acc3
2328         mov     $acc0, $S+8*2(%rsp)
2329         lea     $S-$bias(%rsp), $a_ptr
2330         cmovz   $acc1, $acc4
2331         mov     $acc1, $S+8*3(%rsp)
2332         mov     $acc6, $acc1
2333         lea     $S(%rsp), $r_ptr
2334         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S, S, M);
2335
2336         movq    %xmm1, $b_ptr
2337         movq    %xmm1, $r_ptr
2338         call    __ecp_nistz256_sub_from$x       # p256_sub(res_y, S, res_y);
2339
2340         lea     32*5+56(%rsp), %rsi
2341 .cfi_def_cfa    %rsi,8
2342         mov     -48(%rsi),%r15
2343 .cfi_restore    %r15
2344         mov     -40(%rsi),%r14
2345 .cfi_restore    %r14
2346         mov     -32(%rsi),%r13
2347 .cfi_restore    %r13
2348         mov     -24(%rsi),%r12
2349 .cfi_restore    %r12
2350         mov     -16(%rsi),%rbx
2351 .cfi_restore    %rbx
2352         mov     -8(%rsi),%rbp
2353 .cfi_restore    %rbp
2354         lea     (%rsi),%rsp
2355 .cfi_def_cfa_register   %rsp
2356 .Lpoint_double${x}_epilogue:
2357         ret
2358 .cfi_endproc
2359 .size   ecp_nistz256_point_double$sfx,.-ecp_nistz256_point_double$sfx
2360 ___
2361 }
2362 &gen_double("q");
2363
2364 sub gen_add () {
2365     my $x = shift;
2366     my ($src0,$sfx,$bias);
2367     my ($H,$Hsqr,$R,$Rsqr,$Hcub,
2368         $U1,$U2,$S1,$S2,
2369         $res_x,$res_y,$res_z,
2370         $in1_x,$in1_y,$in1_z,
2371         $in2_x,$in2_y,$in2_z)=map(32*$_,(0..17));
2372     my ($Z1sqr, $Z2sqr) = ($Hsqr, $Rsqr);
2373
2374     if ($x ne "x") {
2375         $src0 = "%rax";
2376         $sfx  = "";
2377         $bias = 0;
2378
2379 $code.=<<___;
2380 .globl  ecp_nistz256_point_add
2381 .type   ecp_nistz256_point_add,\@function,3
2382 .align  32
2383 ecp_nistz256_point_add:
2384 .cfi_startproc
2385 ___
2386 $code.=<<___    if ($addx);
2387         mov     \$0x80100, %ecx
2388         and     OPENSSL_ia32cap_P+8(%rip), %ecx
2389         cmp     \$0x80100, %ecx
2390         je      .Lpoint_addx
2391 ___
2392     } else {
2393         $src0 = "%rdx";
2394         $sfx  = "x";
2395         $bias = 128;
2396
2397 $code.=<<___;
2398 .type   ecp_nistz256_point_addx,\@function,3
2399 .align  32
2400 ecp_nistz256_point_addx:
2401 .cfi_startproc
2402 .Lpoint_addx:
2403 ___
2404     }
2405 $code.=<<___;
2406         push    %rbp
2407 .cfi_push       %rbp
2408         push    %rbx
2409 .cfi_push       %rbx
2410         push    %r12
2411 .cfi_push       %r12
2412         push    %r13
2413 .cfi_push       %r13
2414         push    %r14
2415 .cfi_push       %r14
2416         push    %r15
2417 .cfi_push       %r15
2418         sub     \$32*18+8, %rsp
2419 .cfi_adjust_cfa_offset  32*18+8
2420 .Lpoint_add${x}_body:
2421
2422         movdqu  0x00($a_ptr), %xmm0             # copy  *(P256_POINT *)$a_ptr
2423         movdqu  0x10($a_ptr), %xmm1
2424         movdqu  0x20($a_ptr), %xmm2
2425         movdqu  0x30($a_ptr), %xmm3
2426         movdqu  0x40($a_ptr), %xmm4
2427         movdqu  0x50($a_ptr), %xmm5
2428         mov     $a_ptr, $b_ptr                  # reassign
2429         mov     $b_org, $a_ptr                  # reassign
2430         movdqa  %xmm0, $in1_x(%rsp)
2431         movdqa  %xmm1, $in1_x+0x10(%rsp)
2432         movdqa  %xmm2, $in1_y(%rsp)
2433         movdqa  %xmm3, $in1_y+0x10(%rsp)
2434         movdqa  %xmm4, $in1_z(%rsp)
2435         movdqa  %xmm5, $in1_z+0x10(%rsp)
2436         por     %xmm4, %xmm5
2437
2438         movdqu  0x00($a_ptr), %xmm0             # copy  *(P256_POINT *)$b_ptr
2439          pshufd \$0xb1, %xmm5, %xmm3
2440         movdqu  0x10($a_ptr), %xmm1
2441         movdqu  0x20($a_ptr), %xmm2
2442          por    %xmm3, %xmm5
2443         movdqu  0x30($a_ptr), %xmm3
2444          mov    0x40+8*0($a_ptr), $src0         # load original in2_z
2445          mov    0x40+8*1($a_ptr), $acc6
2446          mov    0x40+8*2($a_ptr), $acc7
2447          mov    0x40+8*3($a_ptr), $acc0
2448         movdqa  %xmm0, $in2_x(%rsp)
2449          pshufd \$0x1e, %xmm5, %xmm4
2450         movdqa  %xmm1, $in2_x+0x10(%rsp)
2451         movdqu  0x40($a_ptr),%xmm0              # in2_z again
2452         movdqu  0x50($a_ptr),%xmm1
2453         movdqa  %xmm2, $in2_y(%rsp)
2454         movdqa  %xmm3, $in2_y+0x10(%rsp)
2455          por    %xmm4, %xmm5
2456          pxor   %xmm4, %xmm4
2457         por     %xmm0, %xmm1
2458          movq   $r_ptr, %xmm0                   # save $r_ptr
2459
2460         lea     0x40-$bias($a_ptr), $a_ptr      # $a_ptr is still valid
2461          mov    $src0, $in2_z+8*0(%rsp)         # make in2_z copy
2462          mov    $acc6, $in2_z+8*1(%rsp)
2463          mov    $acc7, $in2_z+8*2(%rsp)
2464          mov    $acc0, $in2_z+8*3(%rsp)
2465         lea     $Z2sqr(%rsp), $r_ptr            # Z2^2
2466         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Z2sqr, in2_z);
2467
2468         pcmpeqd %xmm4, %xmm5
2469         pshufd  \$0xb1, %xmm1, %xmm4
2470         por     %xmm1, %xmm4
2471         pshufd  \$0, %xmm5, %xmm5               # in1infty
2472         pshufd  \$0x1e, %xmm4, %xmm3
2473         por     %xmm3, %xmm4
2474         pxor    %xmm3, %xmm3
2475         pcmpeqd %xmm3, %xmm4
2476         pshufd  \$0, %xmm4, %xmm4               # in2infty
2477          mov    0x40+8*0($b_ptr), $src0         # load original in1_z
2478          mov    0x40+8*1($b_ptr), $acc6
2479          mov    0x40+8*2($b_ptr), $acc7
2480          mov    0x40+8*3($b_ptr), $acc0
2481         movq    $b_ptr, %xmm1
2482
2483         lea     0x40-$bias($b_ptr), $a_ptr
2484         lea     $Z1sqr(%rsp), $r_ptr            # Z1^2
2485         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Z1sqr, in1_z);
2486
2487         `&load_for_mul("$Z2sqr(%rsp)", "$in2_z(%rsp)", "$src0")`
2488         lea     $S1(%rsp), $r_ptr               # S1 = Z2^3
2489         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S1, Z2sqr, in2_z);
2490
2491         `&load_for_mul("$Z1sqr(%rsp)", "$in1_z(%rsp)", "$src0")`
2492         lea     $S2(%rsp), $r_ptr               # S2 = Z1^3
2493         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, Z1sqr, in1_z);
2494
2495         `&load_for_mul("$S1(%rsp)", "$in1_y(%rsp)", "$src0")`
2496         lea     $S1(%rsp), $r_ptr               # S1 = Y1*Z2^3
2497         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S1, S1, in1_y);
2498
2499         `&load_for_mul("$S2(%rsp)", "$in2_y(%rsp)", "$src0")`
2500         lea     $S2(%rsp), $r_ptr               # S2 = Y2*Z1^3
2501         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, S2, in2_y);
2502
2503         lea     $S1(%rsp), $b_ptr
2504         lea     $R(%rsp), $r_ptr                # R = S2 - S1
2505         call    __ecp_nistz256_sub_from$x       # p256_sub(R, S2, S1);
2506
2507         or      $acc5, $acc4                    # see if result is zero
2508         movdqa  %xmm4, %xmm2
2509         or      $acc0, $acc4
2510         or      $acc1, $acc4
2511         por     %xmm5, %xmm2                    # in1infty || in2infty
2512         movq    $acc4, %xmm3
2513
2514         `&load_for_mul("$Z2sqr(%rsp)", "$in1_x(%rsp)", "$src0")`
2515         lea     $U1(%rsp), $r_ptr               # U1 = X1*Z2^2
2516         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U1, in1_x, Z2sqr);
2517
2518         `&load_for_mul("$Z1sqr(%rsp)", "$in2_x(%rsp)", "$src0")`
2519         lea     $U2(%rsp), $r_ptr               # U2 = X2*Z1^2
2520         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U2, in2_x, Z1sqr);
2521
2522         lea     $U1(%rsp), $b_ptr
2523         lea     $H(%rsp), $r_ptr                # H = U2 - U1
2524         call    __ecp_nistz256_sub_from$x       # p256_sub(H, U2, U1);
2525
2526         or      $acc5, $acc4                    # see if result is zero
2527         or      $acc0, $acc4
2528         or      $acc1, $acc4
2529
2530         .byte   0x3e                            # predict taken
2531         jnz     .Ladd_proceed$x                 # is_equal(U1,U2)?
2532         movq    %xmm2, $acc0
2533         movq    %xmm3, $acc1
2534         test    $acc0, $acc0
2535         jnz     .Ladd_proceed$x                 # (in1infty || in2infty)?
2536         test    $acc1, $acc1
2537         jz      .Ladd_double$x                  # is_equal(S1,S2)?
2538
2539         movq    %xmm0, $r_ptr                   # restore $r_ptr
2540         pxor    %xmm0, %xmm0
2541         movdqu  %xmm0, 0x00($r_ptr)
2542         movdqu  %xmm0, 0x10($r_ptr)
2543         movdqu  %xmm0, 0x20($r_ptr)
2544         movdqu  %xmm0, 0x30($r_ptr)
2545         movdqu  %xmm0, 0x40($r_ptr)
2546         movdqu  %xmm0, 0x50($r_ptr)
2547         jmp     .Ladd_done$x
2548
2549 .align  32
2550 .Ladd_double$x:
2551         movq    %xmm1, $a_ptr                   # restore $a_ptr
2552         movq    %xmm0, $r_ptr                   # restore $r_ptr
2553         add     \$`32*(18-5)`, %rsp             # difference in frame sizes
2554         jmp     .Lpoint_double_shortcut$x
2555
2556 .align  32
2557 .Ladd_proceed$x:
2558         `&load_for_sqr("$R(%rsp)", "$src0")`
2559         lea     $Rsqr(%rsp), $r_ptr             # R^2
2560         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Rsqr, R);
2561
2562         `&load_for_mul("$H(%rsp)", "$in1_z(%rsp)", "$src0")`
2563         lea     $res_z(%rsp), $r_ptr            # Z3 = H*Z1*Z2
2564         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_z, H, in1_z);
2565
2566         `&load_for_sqr("$H(%rsp)", "$src0")`
2567         lea     $Hsqr(%rsp), $r_ptr             # H^2
2568         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Hsqr, H);
2569
2570         `&load_for_mul("$res_z(%rsp)", "$in2_z(%rsp)", "$src0")`
2571         lea     $res_z(%rsp), $r_ptr            # Z3 = H*Z1*Z2
2572         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_z, res_z, in2_z);
2573
2574         `&load_for_mul("$Hsqr(%rsp)", "$H(%rsp)", "$src0")`
2575         lea     $Hcub(%rsp), $r_ptr             # H^3
2576         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(Hcub, Hsqr, H);
2577
2578         `&load_for_mul("$Hsqr(%rsp)", "$U1(%rsp)", "$src0")`
2579         lea     $U2(%rsp), $r_ptr               # U1*H^2
2580         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U2, U1, Hsqr);
2581 ___
2582 {
2583 #######################################################################
2584 # operate in 4-5-0-1 "name space" that matches multiplication output
2585 #
2586 my ($acc0,$acc1,$acc2,$acc3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
2587 my ($poly1, $poly3)=($acc6,$acc7);
2588
2589 $code.=<<___;
2590         #lea    $U2(%rsp), $a_ptr
2591         #lea    $Hsqr(%rsp), $r_ptr     # 2*U1*H^2
2592         #call   __ecp_nistz256_mul_by_2 # ecp_nistz256_mul_by_2(Hsqr, U2);
2593
2594         xor     $t4, $t4
2595         add     $acc0, $acc0            # a0:a3+a0:a3
2596         lea     $Rsqr(%rsp), $a_ptr
2597         adc     $acc1, $acc1
2598          mov    $acc0, $t0
2599         adc     $acc2, $acc2
2600         adc     $acc3, $acc3
2601          mov    $acc1, $t1
2602         adc     \$0, $t4
2603
2604         sub     \$-1, $acc0
2605          mov    $acc2, $t2
2606         sbb     $poly1, $acc1
2607         sbb     \$0, $acc2
2608          mov    $acc3, $t3
2609         sbb     $poly3, $acc3
2610         sbb     \$0, $t4
2611
2612         cmovc   $t0, $acc0
2613         mov     8*0($a_ptr), $t0
2614         cmovc   $t1, $acc1
2615         mov     8*1($a_ptr), $t1
2616         cmovc   $t2, $acc2
2617         mov     8*2($a_ptr), $t2
2618         cmovc   $t3, $acc3
2619         mov     8*3($a_ptr), $t3
2620
2621         call    __ecp_nistz256_sub$x            # p256_sub(res_x, Rsqr, Hsqr);
2622
2623         lea     $Hcub(%rsp), $b_ptr
2624         lea     $res_x(%rsp), $r_ptr
2625         call    __ecp_nistz256_sub_from$x       # p256_sub(res_x, res_x, Hcub);
2626
2627         mov     $U2+8*0(%rsp), $t0
2628         mov     $U2+8*1(%rsp), $t1
2629         mov     $U2+8*2(%rsp), $t2
2630         mov     $U2+8*3(%rsp), $t3
2631         lea     $res_y(%rsp), $r_ptr
2632
2633         call    __ecp_nistz256_sub$x            # p256_sub(res_y, U2, res_x);
2634
2635         mov     $acc0, 8*0($r_ptr)              # save the result, as
2636         mov     $acc1, 8*1($r_ptr)              # __ecp_nistz256_sub doesn't
2637         mov     $acc2, 8*2($r_ptr)
2638         mov     $acc3, 8*3($r_ptr)
2639 ___
2640 }
2641 $code.=<<___;
2642         `&load_for_mul("$S1(%rsp)", "$Hcub(%rsp)", "$src0")`
2643         lea     $S2(%rsp), $r_ptr
2644         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, S1, Hcub);
2645
2646         `&load_for_mul("$R(%rsp)", "$res_y(%rsp)", "$src0")`
2647         lea     $res_y(%rsp), $r_ptr
2648         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_y, R, res_y);
2649
2650         lea     $S2(%rsp), $b_ptr
2651         lea     $res_y(%rsp), $r_ptr
2652         call    __ecp_nistz256_sub_from$x       # p256_sub(res_y, res_y, S2);
2653
2654         movq    %xmm0, $r_ptr           # restore $r_ptr
2655
2656         movdqa  %xmm5, %xmm0            # copy_conditional(res_z, in2_z, in1infty);
2657         movdqa  %xmm5, %xmm1
2658         pandn   $res_z(%rsp), %xmm0
2659         movdqa  %xmm5, %xmm2
2660         pandn   $res_z+0x10(%rsp), %xmm1
2661         movdqa  %xmm5, %xmm3
2662         pand    $in2_z(%rsp), %xmm2
2663         pand    $in2_z+0x10(%rsp), %xmm3
2664         por     %xmm0, %xmm2
2665         por     %xmm1, %xmm3
2666
2667         movdqa  %xmm4, %xmm0            # copy_conditional(res_z, in1_z, in2infty);
2668         movdqa  %xmm4, %xmm1
2669         pandn   %xmm2, %xmm0
2670         movdqa  %xmm4, %xmm2
2671         pandn   %xmm3, %xmm1
2672         movdqa  %xmm4, %xmm3
2673         pand    $in1_z(%rsp), %xmm2
2674         pand    $in1_z+0x10(%rsp), %xmm3
2675         por     %xmm0, %xmm2
2676         por     %xmm1, %xmm3
2677         movdqu  %xmm2, 0x40($r_ptr)
2678         movdqu  %xmm3, 0x50($r_ptr)
2679
2680         movdqa  %xmm5, %xmm0            # copy_conditional(res_x, in2_x, in1infty);
2681         movdqa  %xmm5, %xmm1
2682         pandn   $res_x(%rsp), %xmm0
2683         movdqa  %xmm5, %xmm2
2684         pandn   $res_x+0x10(%rsp), %xmm1
2685         movdqa  %xmm5, %xmm3
2686         pand    $in2_x(%rsp), %xmm2
2687         pand    $in2_x+0x10(%rsp), %xmm3
2688         por     %xmm0, %xmm2
2689         por     %xmm1, %xmm3
2690
2691         movdqa  %xmm4, %xmm0            # copy_conditional(res_x, in1_x, in2infty);
2692         movdqa  %xmm4, %xmm1
2693         pandn   %xmm2, %xmm0
2694         movdqa  %xmm4, %xmm2
2695         pandn   %xmm3, %xmm1
2696         movdqa  %xmm4, %xmm3
2697         pand    $in1_x(%rsp), %xmm2
2698         pand    $in1_x+0x10(%rsp), %xmm3
2699         por     %xmm0, %xmm2
2700         por     %xmm1, %xmm3
2701         movdqu  %xmm2, 0x00($r_ptr)
2702         movdqu  %xmm3, 0x10($r_ptr)
2703
2704         movdqa  %xmm5, %xmm0            # copy_conditional(res_y, in2_y, in1infty);
2705         movdqa  %xmm5, %xmm1
2706         pandn   $res_y(%rsp), %xmm0
2707         movdqa  %xmm5, %xmm2
2708         pandn   $res_y+0x10(%rsp), %xmm1
2709         movdqa  %xmm5, %xmm3
2710         pand    $in2_y(%rsp), %xmm2
2711         pand    $in2_y+0x10(%rsp), %xmm3
2712         por     %xmm0, %xmm2
2713         por     %xmm1, %xmm3
2714
2715         movdqa  %xmm4, %xmm0            # copy_conditional(res_y, in1_y, in2infty);
2716         movdqa  %xmm4, %xmm1
2717         pandn   %xmm2, %xmm0
2718         movdqa  %xmm4, %xmm2
2719         pandn   %xmm3, %xmm1
2720         movdqa  %xmm4, %xmm3
2721         pand    $in1_y(%rsp), %xmm2
2722         pand    $in1_y+0x10(%rsp), %xmm3
2723         por     %xmm0, %xmm2
2724         por     %xmm1, %xmm3
2725         movdqu  %xmm2, 0x20($r_ptr)
2726         movdqu  %xmm3, 0x30($r_ptr)
2727
2728 .Ladd_done$x:
2729         lea     32*18+56(%rsp), %rsi
2730 .cfi_def_cfa    %rsi,8
2731         mov     -48(%rsi),%r15
2732 .cfi_restore    %r15
2733         mov     -40(%rsi),%r14
2734 .cfi_restore    %r14
2735         mov     -32(%rsi),%r13
2736 .cfi_restore    %r13
2737         mov     -24(%rsi),%r12
2738 .cfi_restore    %r12
2739         mov     -16(%rsi),%rbx
2740 .cfi_restore    %rbx
2741         mov     -8(%rsi),%rbp
2742 .cfi_restore    %rbp
2743         lea     (%rsi),%rsp
2744 .cfi_def_cfa_register   %rsp
2745 .Lpoint_add${x}_epilogue:
2746         ret
2747 .cfi_endproc
2748 .size   ecp_nistz256_point_add$sfx,.-ecp_nistz256_point_add$sfx
2749 ___
2750 }
2751 &gen_add("q");
2752
2753 sub gen_add_affine () {
2754     my $x = shift;
2755     my ($src0,$sfx,$bias);
2756     my ($U2,$S2,$H,$R,$Hsqr,$Hcub,$Rsqr,
2757         $res_x,$res_y,$res_z,
2758         $in1_x,$in1_y,$in1_z,
2759         $in2_x,$in2_y)=map(32*$_,(0..14));
2760     my $Z1sqr = $S2;
2761
2762     if ($x ne "x") {
2763         $src0 = "%rax";
2764         $sfx  = "";
2765         $bias = 0;
2766
2767 $code.=<<___;
2768 .globl  ecp_nistz256_point_add_affine
2769 .type   ecp_nistz256_point_add_affine,\@function,3
2770 .align  32
2771 ecp_nistz256_point_add_affine:
2772 .cfi_startproc
2773 ___
2774 $code.=<<___    if ($addx);
2775         mov     \$0x80100, %ecx
2776         and     OPENSSL_ia32cap_P+8(%rip), %ecx
2777         cmp     \$0x80100, %ecx
2778         je      .Lpoint_add_affinex
2779 ___
2780     } else {
2781         $src0 = "%rdx";
2782         $sfx  = "x";
2783         $bias = 128;
2784
2785 $code.=<<___;
2786 .type   ecp_nistz256_point_add_affinex,\@function,3
2787 .align  32
2788 ecp_nistz256_point_add_affinex:
2789 .cfi_startproc
2790 .Lpoint_add_affinex:
2791 ___
2792     }
2793 $code.=<<___;
2794         push    %rbp
2795 .cfi_push       %rbp
2796         push    %rbx
2797 .cfi_push       %rbx
2798         push    %r12
2799 .cfi_push       %r12
2800         push    %r13
2801 .cfi_push       %r13
2802         push    %r14
2803 .cfi_push       %r14
2804         push    %r15
2805 .cfi_push       %r15
2806         sub     \$32*15+8, %rsp
2807 .cfi_adjust_cfa_offset  32*15+8
2808 .Ladd_affine${x}_body:
2809
2810         movdqu  0x00($a_ptr), %xmm0     # copy  *(P256_POINT *)$a_ptr
2811         mov     $b_org, $b_ptr          # reassign
2812         movdqu  0x10($a_ptr), %xmm1
2813         movdqu  0x20($a_ptr), %xmm2
2814         movdqu  0x30($a_ptr), %xmm3
2815         movdqu  0x40($a_ptr), %xmm4
2816         movdqu  0x50($a_ptr), %xmm5
2817          mov    0x40+8*0($a_ptr), $src0 # load original in1_z
2818          mov    0x40+8*1($a_ptr), $acc6
2819          mov    0x40+8*2($a_ptr), $acc7
2820          mov    0x40+8*3($a_ptr), $acc0
2821         movdqa  %xmm0, $in1_x(%rsp)
2822         movdqa  %xmm1, $in1_x+0x10(%rsp)
2823         movdqa  %xmm2, $in1_y(%rsp)
2824         movdqa  %xmm3, $in1_y+0x10(%rsp)
2825         movdqa  %xmm4, $in1_z(%rsp)
2826         movdqa  %xmm5, $in1_z+0x10(%rsp)
2827         por     %xmm4, %xmm5
2828
2829         movdqu  0x00($b_ptr), %xmm0     # copy  *(P256_POINT_AFFINE *)$b_ptr
2830          pshufd \$0xb1, %xmm5, %xmm3
2831         movdqu  0x10($b_ptr), %xmm1
2832         movdqu  0x20($b_ptr), %xmm2
2833          por    %xmm3, %xmm5
2834         movdqu  0x30($b_ptr), %xmm3
2835         movdqa  %xmm0, $in2_x(%rsp)
2836          pshufd \$0x1e, %xmm5, %xmm4
2837         movdqa  %xmm1, $in2_x+0x10(%rsp)
2838         por     %xmm0, %xmm1
2839          movq   $r_ptr, %xmm0           # save $r_ptr
2840         movdqa  %xmm2, $in2_y(%rsp)
2841         movdqa  %xmm3, $in2_y+0x10(%rsp)
2842         por     %xmm2, %xmm3
2843          por    %xmm4, %xmm5
2844          pxor   %xmm4, %xmm4
2845         por     %xmm1, %xmm3
2846
2847         lea     0x40-$bias($a_ptr), $a_ptr      # $a_ptr is still valid
2848         lea     $Z1sqr(%rsp), $r_ptr            # Z1^2
2849         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Z1sqr, in1_z);
2850
2851         pcmpeqd %xmm4, %xmm5
2852         pshufd  \$0xb1, %xmm3, %xmm4
2853          mov    0x00($b_ptr), $src0             # $b_ptr is still valid
2854          #lea   0x00($b_ptr), $b_ptr
2855          mov    $acc4, $acc1                    # harmonize sqr output and mul input
2856         por     %xmm3, %xmm4
2857         pshufd  \$0, %xmm5, %xmm5               # in1infty
2858         pshufd  \$0x1e, %xmm4, %xmm3
2859          mov    $acc5, $acc2
2860         por     %xmm3, %xmm4
2861         pxor    %xmm3, %xmm3
2862          mov    $acc6, $acc3
2863         pcmpeqd %xmm3, %xmm4
2864         pshufd  \$0, %xmm4, %xmm4               # in2infty
2865
2866         lea     $Z1sqr-$bias(%rsp), $a_ptr
2867         mov     $acc7, $acc4
2868         lea     $U2(%rsp), $r_ptr               # U2 = X2*Z1^2
2869         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U2, Z1sqr, in2_x);
2870
2871         lea     $in1_x(%rsp), $b_ptr
2872         lea     $H(%rsp), $r_ptr                # H = U2 - U1
2873         call    __ecp_nistz256_sub_from$x       # p256_sub(H, U2, in1_x);
2874
2875         `&load_for_mul("$Z1sqr(%rsp)", "$in1_z(%rsp)", "$src0")`
2876         lea     $S2(%rsp), $r_ptr               # S2 = Z1^3
2877         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, Z1sqr, in1_z);
2878
2879         `&load_for_mul("$H(%rsp)", "$in1_z(%rsp)", "$src0")`
2880         lea     $res_z(%rsp), $r_ptr            # Z3 = H*Z1*Z2
2881         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(res_z, H, in1_z);
2882
2883         `&load_for_mul("$S2(%rsp)", "$in2_y(%rsp)", "$src0")`
2884         lea     $S2(%rsp), $r_ptr               # S2 = Y2*Z1^3
2885         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, S2, in2_y);
2886
2887         lea     $in1_y(%rsp), $b_ptr
2888         lea     $R(%rsp), $r_ptr                # R = S2 - S1
2889         call    __ecp_nistz256_sub_from$x       # p256_sub(R, S2, in1_y);
2890
2891         `&load_for_sqr("$H(%rsp)", "$src0")`
2892         lea     $Hsqr(%rsp), $r_ptr             # H^2
2893         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Hsqr, H);
2894
2895         `&load_for_sqr("$R(%rsp)", "$src0")`
2896         lea     $Rsqr(%rsp), $r_ptr             # R^2
2897         call    __ecp_nistz256_sqr_mont$x       # p256_sqr_mont(Rsqr, R);
2898
2899         `&load_for_mul("$H(%rsp)", "$Hsqr(%rsp)", "$src0")`
2900         lea     $Hcub(%rsp), $r_ptr             # H^3
2901         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(Hcub, Hsqr, H);
2902
2903         `&load_for_mul("$Hsqr(%rsp)", "$in1_x(%rsp)", "$src0")`
2904         lea     $U2(%rsp), $r_ptr               # U1*H^2
2905         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(U2, in1_x, Hsqr);
2906 ___
2907 {
2908 #######################################################################
2909 # operate in 4-5-0-1 "name space" that matches multiplication output
2910 #
2911 my ($acc0,$acc1,$acc2,$acc3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
2912 my ($poly1, $poly3)=($acc6,$acc7);
2913
2914 $code.=<<___;
2915         #lea    $U2(%rsp), $a_ptr
2916         #lea    $Hsqr(%rsp), $r_ptr     # 2*U1*H^2
2917         #call   __ecp_nistz256_mul_by_2 # ecp_nistz256_mul_by_2(Hsqr, U2);
2918
2919         xor     $t4, $t4
2920         add     $acc0, $acc0            # a0:a3+a0:a3
2921         lea     $Rsqr(%rsp), $a_ptr
2922         adc     $acc1, $acc1
2923          mov    $acc0, $t0
2924         adc     $acc2, $acc2
2925         adc     $acc3, $acc3
2926          mov    $acc1, $t1
2927         adc     \$0, $t4
2928
2929         sub     \$-1, $acc0
2930          mov    $acc2, $t2
2931         sbb     $poly1, $acc1
2932         sbb     \$0, $acc2
2933          mov    $acc3, $t3
2934         sbb     $poly3, $acc3
2935         sbb     \$0, $t4
2936
2937         cmovc   $t0, $acc0
2938         mov     8*0($a_ptr), $t0
2939         cmovc   $t1, $acc1
2940         mov     8*1($a_ptr), $t1
2941         cmovc   $t2, $acc2
2942         mov     8*2($a_ptr), $t2
2943         cmovc   $t3, $acc3
2944         mov     8*3($a_ptr), $t3
2945
2946         call    __ecp_nistz256_sub$x            # p256_sub(res_x, Rsqr, Hsqr);
2947
2948         lea     $Hcub(%rsp), $b_ptr
2949         lea     $res_x(%rsp), $r_ptr
2950         call    __ecp_nistz256_sub_from$x       # p256_sub(res_x, res_x, Hcub);
2951
2952         mov     $U2+8*0(%rsp), $t0
2953         mov     $U2+8*1(%rsp), $t1
2954         mov     $U2+8*2(%rsp), $t2
2955         mov     $U2+8*3(%rsp), $t3
2956         lea     $H(%rsp), $r_ptr
2957
2958         call    __ecp_nistz256_sub$x            # p256_sub(H, U2, res_x);
2959
2960         mov     $acc0, 8*0($r_ptr)              # save the result, as
2961         mov     $acc1, 8*1($r_ptr)              # __ecp_nistz256_sub doesn't
2962         mov     $acc2, 8*2($r_ptr)
2963         mov     $acc3, 8*3($r_ptr)
2964 ___
2965 }
2966 $code.=<<___;
2967         `&load_for_mul("$Hcub(%rsp)", "$in1_y(%rsp)", "$src0")`
2968         lea     $S2(%rsp), $r_ptr
2969         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(S2, Hcub, in1_y);
2970
2971         `&load_for_mul("$H(%rsp)", "$R(%rsp)", "$src0")`
2972         lea     $H(%rsp), $r_ptr
2973         call    __ecp_nistz256_mul_mont$x       # p256_mul_mont(H, H, R);
2974
2975         lea     $S2(%rsp), $b_ptr
2976         lea     $res_y(%rsp), $r_ptr
2977         call    __ecp_nistz256_sub_from$x       # p256_sub(res_y, H, S2);
2978
2979         movq    %xmm0, $r_ptr           # restore $r_ptr
2980
2981         movdqa  %xmm5, %xmm0            # copy_conditional(res_z, ONE, in1infty);
2982         movdqa  %xmm5, %xmm1
2983         pandn   $res_z(%rsp), %xmm0
2984         movdqa  %xmm5, %xmm2
2985         pandn   $res_z+0x10(%rsp), %xmm1
2986         movdqa  %xmm5, %xmm3
2987         pand    .LONE_mont(%rip), %xmm2
2988         pand    .LONE_mont+0x10(%rip), %xmm3
2989         por     %xmm0, %xmm2
2990         por     %xmm1, %xmm3
2991
2992         movdqa  %xmm4, %xmm0            # copy_conditional(res_z, in1_z, in2infty);
2993         movdqa  %xmm4, %xmm1
2994         pandn   %xmm2, %xmm0
2995         movdqa  %xmm4, %xmm2
2996         pandn   %xmm3, %xmm1
2997         movdqa  %xmm4, %xmm3
2998         pand    $in1_z(%rsp), %xmm2
2999         pand    $in1_z+0x10(%rsp), %xmm3
3000         por     %xmm0, %xmm2
3001         por     %xmm1, %xmm3
3002         movdqu  %xmm2, 0x40($r_ptr)
3003         movdqu  %xmm3, 0x50($r_ptr)
3004
3005         movdqa  %xmm5, %xmm0            # copy_conditional(res_x, in2_x, in1infty);
3006         movdqa  %xmm5, %xmm1
3007         pandn   $res_x(%rsp), %xmm0
3008         movdqa  %xmm5, %xmm2
3009         pandn   $res_x+0x10(%rsp), %xmm1
3010         movdqa  %xmm5, %xmm3
3011         pand    $in2_x(%rsp), %xmm2
3012         pand    $in2_x+0x10(%rsp), %xmm3
3013         por     %xmm0, %xmm2
3014         por     %xmm1, %xmm3
3015
3016         movdqa  %xmm4, %xmm0            # copy_conditional(res_x, in1_x, in2infty);
3017         movdqa  %xmm4, %xmm1
3018         pandn   %xmm2, %xmm0
3019         movdqa  %xmm4, %xmm2
3020         pandn   %xmm3, %xmm1
3021         movdqa  %xmm4, %xmm3
3022         pand    $in1_x(%rsp), %xmm2
3023         pand    $in1_x+0x10(%rsp), %xmm3
3024         por     %xmm0, %xmm2
3025         por     %xmm1, %xmm3
3026         movdqu  %xmm2, 0x00($r_ptr)
3027         movdqu  %xmm3, 0x10($r_ptr)
3028
3029         movdqa  %xmm5, %xmm0            # copy_conditional(res_y, in2_y, in1infty);
3030         movdqa  %xmm5, %xmm1
3031         pandn   $res_y(%rsp), %xmm0
3032         movdqa  %xmm5, %xmm2
3033         pandn   $res_y+0x10(%rsp), %xmm1
3034         movdqa  %xmm5, %xmm3
3035         pand    $in2_y(%rsp), %xmm2
3036         pand    $in2_y+0x10(%rsp), %xmm3
3037         por     %xmm0, %xmm2
3038         por     %xmm1, %xmm3
3039
3040         movdqa  %xmm4, %xmm0            # copy_conditional(res_y, in1_y, in2infty);
3041         movdqa  %xmm4, %xmm1
3042         pandn   %xmm2, %xmm0
3043         movdqa  %xmm4, %xmm2
3044         pandn   %xmm3, %xmm1
3045         movdqa  %xmm4, %xmm3
3046         pand    $in1_y(%rsp), %xmm2
3047         pand    $in1_y+0x10(%rsp), %xmm3
3048         por     %xmm0, %xmm2
3049         por     %xmm1, %xmm3
3050         movdqu  %xmm2, 0x20($r_ptr)
3051         movdqu  %xmm3, 0x30($r_ptr)
3052
3053         lea     32*15+56(%rsp), %rsi
3054 .cfi_def_cfa    %rsi,8
3055         mov     -48(%rsi),%r15
3056 .cfi_restore    %r15
3057         mov     -40(%rsi),%r14
3058 .cfi_restore    %r14
3059         mov     -32(%rsi),%r13
3060 .cfi_restore    %r13
3061         mov     -24(%rsi),%r12
3062 .cfi_restore    %r12
3063         mov     -16(%rsi),%rbx
3064 .cfi_restore    %rbx
3065         mov     -8(%rsi),%rbp
3066 .cfi_restore    %rbp
3067         lea     (%rsi),%rsp
3068 .cfi_def_cfa_register   %rsp
3069 .Ladd_affine${x}_epilogue:
3070         ret
3071 .cfi_endproc
3072 .size   ecp_nistz256_point_add_affine$sfx,.-ecp_nistz256_point_add_affine$sfx
3073 ___
3074 }
3075 &gen_add_affine("q");
3076
3077 ########################################################################
3078 # AD*X magic
3079 #
3080 if ($addx) {                                                            {
3081 ########################################################################
3082 # operate in 4-5-0-1 "name space" that matches multiplication output
3083 #
3084 my ($a0,$a1,$a2,$a3,$t3,$t4)=($acc4,$acc5,$acc0,$acc1,$acc2,$acc3);
3085
3086 $code.=<<___;
3087 .type   __ecp_nistz256_add_tox,\@abi-omnipotent
3088 .align  32
3089 __ecp_nistz256_add_tox:
3090         xor     $t4, $t4
3091         adc     8*0($b_ptr), $a0
3092         adc     8*1($b_ptr), $a1
3093          mov    $a0, $t0
3094         adc     8*2($b_ptr), $a2
3095         adc     8*3($b_ptr), $a3
3096          mov    $a1, $t1
3097         adc     \$0, $t4
3098
3099         xor     $t3, $t3
3100         sbb     \$-1, $a0
3101          mov    $a2, $t2
3102         sbb     $poly1, $a1
3103         sbb     \$0, $a2
3104          mov    $a3, $t3
3105         sbb     $poly3, $a3
3106         sbb     \$0, $t4
3107
3108         cmovc   $t0, $a0
3109         cmovc   $t1, $a1
3110         mov     $a0, 8*0($r_ptr)
3111         cmovc   $t2, $a2
3112         mov     $a1, 8*1($r_ptr)
3113         cmovc   $t3, $a3
3114         mov     $a2, 8*2($r_ptr)
3115         mov     $a3, 8*3($r_ptr)
3116
3117         ret
3118 .size   __ecp_nistz256_add_tox,.-__ecp_nistz256_add_tox
3119
3120 .type   __ecp_nistz256_sub_fromx,\@abi-omnipotent
3121 .align  32
3122 __ecp_nistz256_sub_fromx:
3123         xor     $t4, $t4
3124         sbb     8*0($b_ptr), $a0
3125         sbb     8*1($b_ptr), $a1
3126          mov    $a0, $t0
3127         sbb     8*2($b_ptr), $a2
3128         sbb     8*3($b_ptr), $a3
3129          mov    $a1, $t1
3130         sbb     \$0, $t4
3131
3132         xor     $t3, $t3
3133         adc     \$-1, $a0
3134          mov    $a2, $t2
3135         adc     $poly1, $a1
3136         adc     \$0, $a2
3137          mov    $a3, $t3
3138         adc     $poly3, $a3
3139
3140         bt      \$0, $t4
3141         cmovnc  $t0, $a0
3142         cmovnc  $t1, $a1
3143         mov     $a0, 8*0($r_ptr)
3144         cmovnc  $t2, $a2
3145         mov     $a1, 8*1($r_ptr)
3146         cmovnc  $t3, $a3
3147         mov     $a2, 8*2($r_ptr)
3148         mov     $a3, 8*3($r_ptr)
3149
3150         ret
3151 .size   __ecp_nistz256_sub_fromx,.-__ecp_nistz256_sub_fromx
3152
3153 .type   __ecp_nistz256_subx,\@abi-omnipotent
3154 .align  32
3155 __ecp_nistz256_subx:
3156         xor     $t4, $t4
3157         sbb     $a0, $t0
3158         sbb     $a1, $t1
3159          mov    $t0, $a0
3160         sbb     $a2, $t2
3161         sbb     $a3, $t3
3162          mov    $t1, $a1
3163         sbb     \$0, $t4
3164
3165         xor     $a3 ,$a3
3166         adc     \$-1, $t0
3167          mov    $t2, $a2
3168         adc     $poly1, $t1
3169         adc     \$0, $t2
3170          mov    $t3, $a3
3171         adc     $poly3, $t3
3172
3173         bt      \$0, $t4
3174         cmovc   $t0, $a0
3175         cmovc   $t1, $a1
3176         cmovc   $t2, $a2
3177         cmovc   $t3, $a3
3178
3179         ret
3180 .size   __ecp_nistz256_subx,.-__ecp_nistz256_subx
3181
3182 .type   __ecp_nistz256_mul_by_2x,\@abi-omnipotent
3183 .align  32
3184 __ecp_nistz256_mul_by_2x:
3185         xor     $t4, $t4
3186         adc     $a0, $a0                # a0:a3+a0:a3
3187         adc     $a1, $a1
3188          mov    $a0, $t0
3189         adc     $a2, $a2
3190         adc     $a3, $a3
3191          mov    $a1, $t1
3192         adc     \$0, $t4
3193
3194         xor     $t3, $t3
3195         sbb     \$-1, $a0
3196          mov    $a2, $t2
3197         sbb     $poly1, $a1
3198         sbb     \$0, $a2
3199          mov    $a3, $t3
3200         sbb     $poly3, $a3
3201         sbb     \$0, $t4
3202
3203         cmovc   $t0, $a0
3204         cmovc   $t1, $a1
3205         mov     $a0, 8*0($r_ptr)
3206         cmovc   $t2, $a2
3207         mov     $a1, 8*1($r_ptr)
3208         cmovc   $t3, $a3
3209         mov     $a2, 8*2($r_ptr)
3210         mov     $a3, 8*3($r_ptr)
3211
3212         ret
3213 .size   __ecp_nistz256_mul_by_2x,.-__ecp_nistz256_mul_by_2x
3214 ___
3215                                                                         }
3216 &gen_double("x");
3217 &gen_add("x");
3218 &gen_add_affine("x");
3219 }
3220 }}}
3221
3222 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
3223 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
3224 if ($win64) {
3225 $rec="%rcx";
3226 $frame="%rdx";
3227 $context="%r8";
3228 $disp="%r9";
3229
3230 $code.=<<___;
3231 .extern __imp_RtlVirtualUnwind
3232
3233 .type   short_handler,\@abi-omnipotent
3234 .align  16
3235 short_handler:
3236         push    %rsi
3237         push    %rdi
3238         push    %rbx
3239         push    %rbp
3240         push    %r12
3241         push    %r13
3242         push    %r14
3243         push    %r15
3244         pushfq
3245         sub     \$64,%rsp
3246
3247         mov     120($context),%rax      # pull context->Rax
3248         mov     248($context),%rbx      # pull context->Rip
3249
3250         mov     8($disp),%rsi           # disp->ImageBase
3251         mov     56($disp),%r11          # disp->HandlerData
3252
3253         mov     0(%r11),%r10d           # HandlerData[0]
3254         lea     (%rsi,%r10),%r10        # end of prologue label
3255         cmp     %r10,%rbx               # context->Rip<end of prologue label
3256         jb      .Lcommon_seh_tail
3257
3258         mov     152($context),%rax      # pull context->Rsp
3259
3260         mov     4(%r11),%r10d           # HandlerData[1]
3261         lea     (%rsi,%r10),%r10        # epilogue label
3262         cmp     %r10,%rbx               # context->Rip>=epilogue label
3263         jae     .Lcommon_seh_tail
3264
3265         lea     16(%rax),%rax
3266
3267         mov     -8(%rax),%r12
3268         mov     -16(%rax),%r13
3269         mov     %r12,216($context)      # restore context->R12
3270         mov     %r13,224($context)      # restore context->R13
3271
3272         jmp     .Lcommon_seh_tail
3273 .size   short_handler,.-short_handler
3274
3275 .type   full_handler,\@abi-omnipotent
3276 .align  16
3277 full_handler:
3278         push    %rsi
3279         push    %rdi
3280         push    %rbx
3281         push    %rbp
3282         push    %r12
3283         push    %r13
3284         push    %r14
3285         push    %r15
3286         pushfq
3287         sub     \$64,%rsp
3288
3289         mov     120($context),%rax      # pull context->Rax
3290         mov     248($context),%rbx      # pull context->Rip
3291
3292         mov     8($disp),%rsi           # disp->ImageBase
3293         mov     56($disp),%r11          # disp->HandlerData
3294
3295         mov     0(%r11),%r10d           # HandlerData[0]
3296         lea     (%rsi,%r10),%r10        # end of prologue label
3297         cmp     %r10,%rbx               # context->Rip<end of prologue label
3298         jb      .Lcommon_seh_tail
3299
3300         mov     152($context),%rax      # pull context->Rsp
3301
3302         mov     4(%r11),%r10d           # HandlerData[1]
3303         lea     (%rsi,%r10),%r10        # epilogue label
3304         cmp     %r10,%rbx               # context->Rip>=epilogue label
3305         jae     .Lcommon_seh_tail
3306
3307         mov     8(%r11),%r10d           # HandlerData[2]
3308         lea     (%rax,%r10),%rax
3309
3310         mov     -8(%rax),%rbp
3311         mov     -16(%rax),%rbx
3312         mov     -24(%rax),%r12
3313         mov     -32(%rax),%r13
3314         mov     -40(%rax),%r14
3315         mov     -48(%rax),%r15
3316         mov     %rbx,144($context)      # restore context->Rbx
3317         mov     %rbp,160($context)      # restore context->Rbp
3318         mov     %r12,216($context)      # restore context->R12
3319         mov     %r13,224($context)      # restore context->R13
3320         mov     %r14,232($context)      # restore context->R14
3321         mov     %r15,240($context)      # restore context->R15
3322
3323 .Lcommon_seh_tail:
3324         mov     8(%rax),%rdi
3325         mov     16(%rax),%rsi
3326         mov     %rax,152($context)      # restore context->Rsp
3327         mov     %rsi,168($context)      # restore context->Rsi
3328         mov     %rdi,176($context)      # restore context->Rdi
3329
3330         mov     40($disp),%rdi          # disp->ContextRecord
3331         mov     $context,%rsi           # context
3332         mov     \$154,%ecx              # sizeof(CONTEXT)
3333         .long   0xa548f3fc              # cld; rep movsq
3334
3335         mov     $disp,%rsi
3336         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
3337         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
3338         mov     0(%rsi),%r8             # arg3, disp->ControlPc
3339         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
3340         mov     40(%rsi),%r10           # disp->ContextRecord
3341         lea     56(%rsi),%r11           # &disp->HandlerData
3342         lea     24(%rsi),%r12           # &disp->EstablisherFrame
3343         mov     %r10,32(%rsp)           # arg5
3344         mov     %r11,40(%rsp)           # arg6
3345         mov     %r12,48(%rsp)           # arg7
3346         mov     %rcx,56(%rsp)           # arg8, (NULL)
3347         call    *__imp_RtlVirtualUnwind(%rip)
3348
3349         mov     \$1,%eax                # ExceptionContinueSearch
3350         add     \$64,%rsp
3351         popfq
3352         pop     %r15
3353         pop     %r14
3354         pop     %r13
3355         pop     %r12
3356         pop     %rbp
3357         pop     %rbx
3358         pop     %rdi
3359         pop     %rsi
3360         ret
3361 .size   full_handler,.-full_handler
3362
3363 .section        .pdata
3364 .align  4
3365         .rva    .LSEH_begin_ecp_nistz256_mul_by_2
3366         .rva    .LSEH_end_ecp_nistz256_mul_by_2
3367         .rva    .LSEH_info_ecp_nistz256_mul_by_2
3368
3369         .rva    .LSEH_begin_ecp_nistz256_div_by_2
3370         .rva    .LSEH_end_ecp_nistz256_div_by_2
3371         .rva    .LSEH_info_ecp_nistz256_div_by_2
3372
3373         .rva    .LSEH_begin_ecp_nistz256_mul_by_3
3374         .rva    .LSEH_end_ecp_nistz256_mul_by_3
3375         .rva    .LSEH_info_ecp_nistz256_mul_by_3
3376
3377         .rva    .LSEH_begin_ecp_nistz256_add
3378         .rva    .LSEH_end_ecp_nistz256_add
3379         .rva    .LSEH_info_ecp_nistz256_add
3380
3381         .rva    .LSEH_begin_ecp_nistz256_sub
3382         .rva    .LSEH_end_ecp_nistz256_sub
3383         .rva    .LSEH_info_ecp_nistz256_sub
3384
3385         .rva    .LSEH_begin_ecp_nistz256_neg
3386         .rva    .LSEH_end_ecp_nistz256_neg
3387         .rva    .LSEH_info_ecp_nistz256_neg
3388
3389         .rva    .LSEH_begin_ecp_nistz256_to_mont
3390         .rva    .LSEH_end_ecp_nistz256_to_mont
3391         .rva    .LSEH_info_ecp_nistz256_to_mont
3392
3393         .rva    .LSEH_begin_ecp_nistz256_mul_mont
3394         .rva    .LSEH_end_ecp_nistz256_mul_mont
3395         .rva    .LSEH_info_ecp_nistz256_mul_mont
3396
3397         .rva    .LSEH_begin_ecp_nistz256_sqr_mont
3398         .rva    .LSEH_end_ecp_nistz256_sqr_mont
3399         .rva    .LSEH_info_ecp_nistz256_sqr_mont
3400
3401         .rva    .LSEH_begin_ecp_nistz256_from_mont
3402         .rva    .LSEH_end_ecp_nistz256_from_mont
3403         .rva    .LSEH_info_ecp_nistz256_from_mont
3404
3405         .rva    .LSEH_begin_ecp_nistz256_gather_w5
3406         .rva    .LSEH_end_ecp_nistz256_gather_w5
3407         .rva    .LSEH_info_ecp_nistz256_gather_wX
3408
3409         .rva    .LSEH_begin_ecp_nistz256_gather_w7
3410         .rva    .LSEH_end_ecp_nistz256_gather_w7
3411         .rva    .LSEH_info_ecp_nistz256_gather_wX
3412 ___
3413 $code.=<<___    if ($avx>1);
3414         .rva    .LSEH_begin_ecp_nistz256_avx2_gather_w5
3415         .rva    .LSEH_end_ecp_nistz256_avx2_gather_w5
3416         .rva    .LSEH_info_ecp_nistz256_avx2_gather_wX
3417
3418         .rva    .LSEH_begin_ecp_nistz256_avx2_gather_w7
3419         .rva    .LSEH_end_ecp_nistz256_avx2_gather_w7
3420         .rva    .LSEH_info_ecp_nistz256_avx2_gather_wX
3421 ___
3422 $code.=<<___;
3423         .rva    .LSEH_begin_ecp_nistz256_point_double
3424         .rva    .LSEH_end_ecp_nistz256_point_double
3425         .rva    .LSEH_info_ecp_nistz256_point_double
3426
3427         .rva    .LSEH_begin_ecp_nistz256_point_add
3428         .rva    .LSEH_end_ecp_nistz256_point_add
3429         .rva    .LSEH_info_ecp_nistz256_point_add
3430
3431         .rva    .LSEH_begin_ecp_nistz256_point_add_affine
3432         .rva    .LSEH_end_ecp_nistz256_point_add_affine
3433         .rva    .LSEH_info_ecp_nistz256_point_add_affine
3434 ___
3435 $code.=<<___ if ($addx);
3436         .rva    .LSEH_begin_ecp_nistz256_point_doublex
3437         .rva    .LSEH_end_ecp_nistz256_point_doublex
3438         .rva    .LSEH_info_ecp_nistz256_point_doublex
3439
3440         .rva    .LSEH_begin_ecp_nistz256_point_addx
3441         .rva    .LSEH_end_ecp_nistz256_point_addx
3442         .rva    .LSEH_info_ecp_nistz256_point_addx
3443
3444         .rva    .LSEH_begin_ecp_nistz256_point_add_affinex
3445         .rva    .LSEH_end_ecp_nistz256_point_add_affinex
3446         .rva    .LSEH_info_ecp_nistz256_point_add_affinex
3447 ___
3448 $code.=<<___;
3449
3450 .section        .xdata
3451 .align  8
3452 .LSEH_info_ecp_nistz256_mul_by_2:
3453         .byte   9,0,0,0
3454         .rva    short_handler
3455         .rva    .Lmul_by_2_body,.Lmul_by_2_epilogue     # HandlerData[]
3456 .LSEH_info_ecp_nistz256_div_by_2:
3457         .byte   9,0,0,0
3458         .rva    short_handler
3459         .rva    .Ldiv_by_2_body,.Ldiv_by_2_epilogue     # HandlerData[]
3460 .LSEH_info_ecp_nistz256_mul_by_3:
3461         .byte   9,0,0,0
3462         .rva    short_handler
3463         .rva    .Lmul_by_3_body,.Lmul_by_3_epilogue     # HandlerData[]
3464 .LSEH_info_ecp_nistz256_add:
3465         .byte   9,0,0,0
3466         .rva    short_handler
3467         .rva    .Ladd_body,.Ladd_epilogue               # HandlerData[]
3468 .LSEH_info_ecp_nistz256_sub:
3469         .byte   9,0,0,0
3470         .rva    short_handler
3471         .rva    .Lsub_body,.Lsub_epilogue               # HandlerData[]
3472 .LSEH_info_ecp_nistz256_neg:
3473         .byte   9,0,0,0
3474         .rva    short_handler
3475         .rva    .Lneg_body,.Lneg_epilogue               # HandlerData[]
3476 .LSEH_info_ecp_nistz256_to_mont:
3477         .byte   9,0,0,0
3478         .rva    full_handler
3479         .rva    .Lmul_body,.Lmul_epilogue               # HandlerData[]
3480         .long   48,0
3481 .LSEH_info_ecp_nistz256_mul_mont:
3482         .byte   9,0,0,0
3483         .rva    full_handler
3484         .rva    .Lmul_body,.Lmul_epilogue               # HandlerData[]
3485         .long   48,0
3486 .LSEH_info_ecp_nistz256_sqr_mont:
3487         .byte   9,0,0,0
3488         .rva    full_handler
3489         .rva    .Lsqr_body,.Lsqr_epilogue               # HandlerData[]
3490         .long   48,0
3491 .LSEH_info_ecp_nistz256_from_mont:
3492         .byte   9,0,0,0
3493         .rva    short_handler
3494         .rva    .Lfrom_body,.Lfrom_epilogue             # HandlerData[]
3495 .LSEH_info_ecp_nistz256_gather_wX:
3496         .byte   0x01,0x33,0x16,0x00
3497         .byte   0x33,0xf8,0x09,0x00     #movaps 0x90(rsp),xmm15
3498         .byte   0x2e,0xe8,0x08,0x00     #movaps 0x80(rsp),xmm14
3499         .byte   0x29,0xd8,0x07,0x00     #movaps 0x70(rsp),xmm13
3500         .byte   0x24,0xc8,0x06,0x00     #movaps 0x60(rsp),xmm12
3501         .byte   0x1f,0xb8,0x05,0x00     #movaps 0x50(rsp),xmm11
3502         .byte   0x1a,0xa8,0x04,0x00     #movaps 0x40(rsp),xmm10
3503         .byte   0x15,0x98,0x03,0x00     #movaps 0x30(rsp),xmm9
3504         .byte   0x10,0x88,0x02,0x00     #movaps 0x20(rsp),xmm8
3505         .byte   0x0c,0x78,0x01,0x00     #movaps 0x10(rsp),xmm7
3506         .byte   0x08,0x68,0x00,0x00     #movaps 0x00(rsp),xmm6
3507         .byte   0x04,0x01,0x15,0x00     #sub    rsp,0xa8
3508         .align  8
3509 ___
3510 $code.=<<___    if ($avx>1);
3511 .LSEH_info_ecp_nistz256_avx2_gather_wX:
3512         .byte   0x01,0x36,0x17,0x0b
3513         .byte   0x36,0xf8,0x09,0x00     # vmovaps 0x90(rsp),xmm15
3514         .byte   0x31,0xe8,0x08,0x00     # vmovaps 0x80(rsp),xmm14
3515         .byte   0x2c,0xd8,0x07,0x00     # vmovaps 0x70(rsp),xmm13
3516         .byte   0x27,0xc8,0x06,0x00     # vmovaps 0x60(rsp),xmm12
3517         .byte   0x22,0xb8,0x05,0x00     # vmovaps 0x50(rsp),xmm11
3518         .byte   0x1d,0xa8,0x04,0x00     # vmovaps 0x40(rsp),xmm10
3519         .byte   0x18,0x98,0x03,0x00     # vmovaps 0x30(rsp),xmm9
3520         .byte   0x13,0x88,0x02,0x00     # vmovaps 0x20(rsp),xmm8
3521         .byte   0x0e,0x78,0x01,0x00     # vmovaps 0x10(rsp),xmm7
3522         .byte   0x09,0x68,0x00,0x00     # vmovaps 0x00(rsp),xmm6
3523         .byte   0x04,0x01,0x15,0x00     # sub     rsp,0xa8
3524         .byte   0x00,0xb3,0x00,0x00     # set_frame r11
3525         .align  8
3526 ___
3527 $code.=<<___;
3528 .LSEH_info_ecp_nistz256_point_double:
3529         .byte   9,0,0,0
3530         .rva    full_handler
3531         .rva    .Lpoint_doubleq_body,.Lpoint_doubleq_epilogue   # HandlerData[]
3532         .long   32*5+56,0
3533 .LSEH_info_ecp_nistz256_point_add:
3534         .byte   9,0,0,0
3535         .rva    full_handler
3536         .rva    .Lpoint_addq_body,.Lpoint_addq_epilogue         # HandlerData[]
3537         .long   32*18+56,0
3538 .LSEH_info_ecp_nistz256_point_add_affine:
3539         .byte   9,0,0,0
3540         .rva    full_handler
3541         .rva    .Ladd_affineq_body,.Ladd_affineq_epilogue       # HandlerData[]
3542         .long   32*15+56,0
3543 ___
3544 $code.=<<___ if ($addx);
3545 .align  8
3546 .LSEH_info_ecp_nistz256_point_doublex:
3547         .byte   9,0,0,0
3548         .rva    full_handler
3549         .rva    .Lpoint_doublex_body,.Lpoint_doublex_epilogue   # HandlerData[]
3550         .long   32*5+56,0
3551 .LSEH_info_ecp_nistz256_point_addx:
3552         .byte   9,0,0,0
3553         .rva    full_handler
3554         .rva    .Lpoint_addx_body,.Lpoint_addx_epilogue         # HandlerData[]
3555         .long   32*18+56,0
3556 .LSEH_info_ecp_nistz256_point_add_affinex:
3557         .byte   9,0,0,0
3558         .rva    full_handler
3559         .rva    .Ladd_affinex_body,.Ladd_affinex_epilogue       # HandlerData[]
3560         .long   32*15+56,0
3561 ___
3562 }
3563
3564 ########################################################################
3565 # Convert ecp_nistz256_table.c to layout expected by ecp_nistz_gather_w7
3566 #
3567 open TABLE,"<ecp_nistz256_table.c"              or
3568 open TABLE,"<${dir}../ecp_nistz256_table.c"     or
3569 die "failed to open ecp_nistz256_table.c:",$!;
3570
3571 use integer;
3572
3573 foreach(<TABLE>) {
3574         s/TOBN\(\s*(0x[0-9a-f]+),\s*(0x[0-9a-f]+)\s*\)/push @arr,hex($2),hex($1)/geo;
3575 }
3576 close TABLE;
3577
3578 die "insane number of elements" if ($#arr != 64*16*37-1);
3579
3580 print <<___;
3581 .text
3582 .globl  ecp_nistz256_precomputed
3583 .type   ecp_nistz256_precomputed,\@object
3584 .align  4096
3585 ecp_nistz256_precomputed:
3586 ___
3587 while (@line=splice(@arr,0,16)) {
3588         print ".long\t",join(',',map { sprintf "0x%08x",$_} @line),"\n";
3589 }
3590 print <<___;
3591 .size   ecp_nistz256_precomputed,.-ecp_nistz256_precomputed
3592 ___
3593
3594 $code =~ s/\`([^\`]*)\`/eval $1/gem;
3595 print $code;
3596 close STDOUT;