sha1-x86_64.pl: harmonize Win64 SE handlers for SIMD code pathes.
[openssl.git] / crypto / sha / asm / sha1-x86_64.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9 #
10 # sha1_block procedure for x86_64.
11 #
12 # It was brought to my attention that on EM64T compiler-generated code
13 # was far behind 32-bit assembler implementation. This is unlike on
14 # Opteron where compiler-generated code was only 15% behind 32-bit
15 # assembler, which originally made it hard to motivate the effort.
16 # There was suggestion to mechanically translate 32-bit code, but I
17 # dismissed it, reasoning that x86_64 offers enough register bank
18 # capacity to fully utilize SHA-1 parallelism. Therefore this fresh
19 # implementation:-) However! While 64-bit code does perform better
20 # on Opteron, I failed to beat 32-bit assembler on EM64T core. Well,
21 # x86_64 does offer larger *addressable* bank, but out-of-order core
22 # reaches for even more registers through dynamic aliasing, and EM64T
23 # core must have managed to run-time optimize even 32-bit code just as
24 # good as 64-bit one. Performance improvement is summarized in the
25 # following table:
26 #
27 #               gcc 3.4         32-bit asm      cycles/byte
28 # Opteron       +45%            +20%            6.8
29 # Xeon P4       +65%            +0%             9.9
30 # Core2         +60%            +10%            7.0
31
32 # August 2009.
33 #
34 # The code was revised to minimize code size and to maximize
35 # "distance" between instructions producing input to 'lea'
36 # instruction and the 'lea' instruction itself, which is essential
37 # for Intel Atom core.
38
39 # October 2010.
40 #
41 # Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it
42 # is to offload message schedule denoted by Wt in NIST specification,
43 # or Xupdate in OpenSSL source, to SIMD unit. See sha1-586.pl module
44 # for background and implementation details. The only difference from
45 # 32-bit code is that 64-bit code doesn't have to spill @X[] elements
46 # to free temporary registers.
47
48 # April 2011.
49 #
50 # Add AVX code path. See sha1-586.pl for further information.
51
52 # May 2013.
53 #
54 # Add AVX2+BMI code path. Initial attempt (utilizing BMI instructions
55 # and loading pair of consecutive blocks to 256-bit %ymm registers)
56 # did not provide impressive performance improvement till a crucial
57 # hint regarding the number of Xupdate iterations to pre-compute in
58 # advance was provided by Ilya Albrekht of Intel Corp.
59
60 ######################################################################
61 # Current performance is summarized in following table. Numbers are
62 # CPU clock cycles spent to process single byte (less is better).
63 #
64 #               x86_64          SSSE3           AVX[2]
65 # P4            9.8             -
66 # Opteron       6.65            -
67 # Core2         6.70            6.05/+11%       -
68 # Westmere      7.08            5.44/+30%       -
69 # Sandy Bridge  7.93            6.16/+28%       4.99/+59%
70 # Ivy Bridge    6.30            4.63/+36%       4.60/+37%
71 # Haswell       5.98            4.36/+37%       3.57/+67%
72 # Bulldozer     10.9            5.95/+82%
73 # VIA Nano      10.2            7.46/+37%
74 # Atom          11.0            9.61/+14%
75
76 $flavour = shift;
77 $output  = shift;
78 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
79
80 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
81
82 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
83 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
84 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
85 die "can't locate x86_64-xlate.pl";
86
87 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
88                 =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
89         $avx = ($1>=2.19) + ($1>=2.22);
90 }
91
92 if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
93            `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
94         $avx = ($1>=2.09) + ($1>=2.10);
95 }
96
97 if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
98            `ml64 2>&1` =~ /Version ([0-9]+)\./) {
99         $avx = ($1>=10) + ($1>=11);
100 }
101
102 open OUT,"| \"$^X\" $xlate $flavour $output";
103 *STDOUT=*OUT;
104
105 $ctx="%rdi";    # 1st arg
106 $inp="%rsi";    # 2nd arg
107 $num="%rdx";    # 3rd arg
108
109 # reassign arguments in order to produce more compact code
110 $ctx="%r8";
111 $inp="%r9";
112 $num="%r10";
113
114 $t0="%eax";
115 $t1="%ebx";
116 $t2="%ecx";
117 @xi=("%edx","%ebp");
118 $A="%esi";
119 $B="%edi";
120 $C="%r11d";
121 $D="%r12d";
122 $E="%r13d";
123
124 @V=($A,$B,$C,$D,$E);
125
126 sub BODY_00_19 {
127 my ($i,$a,$b,$c,$d,$e)=@_;
128 my $j=$i+1;
129 $code.=<<___ if ($i==0);
130         mov     `4*$i`($inp),$xi[0]
131         bswap   $xi[0]
132         mov     $xi[0],`4*$i`(%rsp)
133 ___
134 $code.=<<___ if ($i<15);
135         mov     $c,$t0
136         mov     `4*$j`($inp),$xi[1]
137         mov     $a,$t2
138         xor     $d,$t0
139         bswap   $xi[1]
140         rol     \$5,$t2
141         lea     0x5a827999($xi[0],$e),$e
142         and     $b,$t0
143         mov     $xi[1],`4*$j`(%rsp)
144         add     $t2,$e
145         xor     $d,$t0
146         rol     \$30,$b
147         add     $t0,$e
148 ___
149 $code.=<<___ if ($i>=15);
150         mov     `4*($j%16)`(%rsp),$xi[1]
151         mov     $c,$t0
152         mov     $a,$t2
153         xor     `4*(($j+2)%16)`(%rsp),$xi[1]
154         xor     $d,$t0
155         rol     \$5,$t2
156         xor     `4*(($j+8)%16)`(%rsp),$xi[1]
157         and     $b,$t0
158         lea     0x5a827999($xi[0],$e),$e
159         xor     `4*(($j+13)%16)`(%rsp),$xi[1]
160         xor     $d,$t0
161         rol     \$1,$xi[1]
162         add     $t2,$e
163         rol     \$30,$b
164         mov     $xi[1],`4*($j%16)`(%rsp)
165         add     $t0,$e
166 ___
167 unshift(@xi,pop(@xi));
168 }
169
170 sub BODY_20_39 {
171 my ($i,$a,$b,$c,$d,$e)=@_;
172 my $j=$i+1;
173 my $K=($i<40)?0x6ed9eba1:0xca62c1d6;
174 $code.=<<___ if ($i<79);
175         mov     `4*($j%16)`(%rsp),$xi[1]
176         mov     $c,$t0
177         mov     $a,$t2
178         xor     `4*(($j+2)%16)`(%rsp),$xi[1]
179         xor     $b,$t0
180         rol     \$5,$t2
181         lea     $K($xi[0],$e),$e
182         xor     `4*(($j+8)%16)`(%rsp),$xi[1]
183         xor     $d,$t0
184         add     $t2,$e
185         xor     `4*(($j+13)%16)`(%rsp),$xi[1]
186         rol     \$30,$b
187         add     $t0,$e
188         rol     \$1,$xi[1]
189 ___
190 $code.=<<___ if ($i<76);
191         mov     $xi[1],`4*($j%16)`(%rsp)
192 ___
193 $code.=<<___ if ($i==79);
194         mov     $c,$t0
195         mov     $a,$t2
196         xor     $b,$t0
197         lea     $K($xi[0],$e),$e
198         rol     \$5,$t2
199         xor     $d,$t0
200         add     $t2,$e
201         rol     \$30,$b
202         add     $t0,$e
203 ___
204 unshift(@xi,pop(@xi));
205 }
206
207 sub BODY_40_59 {
208 my ($i,$a,$b,$c,$d,$e)=@_;
209 my $j=$i+1;
210 $code.=<<___;
211         mov     `4*($j%16)`(%rsp),$xi[1]
212         mov     $c,$t0
213         mov     $c,$t1
214         xor     `4*(($j+2)%16)`(%rsp),$xi[1]
215         and     $d,$t0
216         mov     $a,$t2
217         xor     `4*(($j+8)%16)`(%rsp),$xi[1]
218         xor     $d,$t1
219         lea     0x8f1bbcdc($xi[0],$e),$e
220         rol     \$5,$t2
221         xor     `4*(($j+13)%16)`(%rsp),$xi[1]
222         add     $t0,$e
223         and     $b,$t1
224         rol     \$1,$xi[1]
225         add     $t1,$e
226         rol     \$30,$b
227         mov     $xi[1],`4*($j%16)`(%rsp)
228         add     $t2,$e
229 ___
230 unshift(@xi,pop(@xi));
231 }
232
233 $code.=<<___;
234 .text
235 .extern OPENSSL_ia32cap_P
236
237 .globl  sha1_block_data_order
238 .type   sha1_block_data_order,\@function,3
239 .align  16
240 sha1_block_data_order:
241         mov     OPENSSL_ia32cap_P+0(%rip),%r9d
242         mov     OPENSSL_ia32cap_P+4(%rip),%r8d
243         mov     OPENSSL_ia32cap_P+8(%rip),%r10d
244         test    \$`1<<9`,%r8d           # check SSSE3 bit
245         jz      .Lialu
246 ___
247 $code.=<<___ if ($avx>1);
248         and     \$`1<<3|1<<5|1<<8`,%r10d        # check AVX2+BMI1+BMI2
249         cmp     \$`1<<3|1<<5|1<<8`,%r10d
250         je      _avx2_shortcut
251 ___
252 $code.=<<___ if ($avx);
253         and     \$`1<<28`,%r8d          # mask AVX bit
254         and     \$`1<<30`,%r9d          # mask "Intel CPU" bit
255         or      %r9d,%r8d
256         cmp     \$`1<<28|1<<30`,%r8d
257         je      _avx_shortcut
258 ___
259 $code.=<<___;
260         jmp     _ssse3_shortcut
261
262 .align  16
263 .Lialu:
264         push    %rbx
265         push    %rbp
266         push    %r12
267         push    %r13
268         mov     %rsp,%r11
269         mov     %rdi,$ctx       # reassigned argument
270         sub     \$`8+16*4`,%rsp
271         mov     %rsi,$inp       # reassigned argument
272         and     \$-64,%rsp
273         mov     %rdx,$num       # reassigned argument
274         mov     %r11,`16*4`(%rsp)
275 .Lprologue:
276
277         mov     0($ctx),$A
278         mov     4($ctx),$B
279         mov     8($ctx),$C
280         mov     12($ctx),$D
281         mov     16($ctx),$E
282         jmp     .Lloop
283
284 .align  16
285 .Lloop:
286 ___
287 for($i=0;$i<20;$i++)    { &BODY_00_19($i,@V); unshift(@V,pop(@V)); }
288 for(;$i<40;$i++)        { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
289 for(;$i<60;$i++)        { &BODY_40_59($i,@V); unshift(@V,pop(@V)); }
290 for(;$i<80;$i++)        { &BODY_20_39($i,@V); unshift(@V,pop(@V)); }
291 $code.=<<___;
292         add     0($ctx),$A
293         add     4($ctx),$B
294         add     8($ctx),$C
295         add     12($ctx),$D
296         add     16($ctx),$E
297         mov     $A,0($ctx)
298         mov     $B,4($ctx)
299         mov     $C,8($ctx)
300         mov     $D,12($ctx)
301         mov     $E,16($ctx)
302
303         sub     \$1,$num
304         lea     `16*4`($inp),$inp
305         jnz     .Lloop
306
307         mov     `16*4`(%rsp),%rsi
308         mov     (%rsi),%r13
309         mov     8(%rsi),%r12
310         mov     16(%rsi),%rbp
311         mov     24(%rsi),%rbx
312         lea     32(%rsi),%rsp
313 .Lepilogue:
314         ret
315 .size   sha1_block_data_order,.-sha1_block_data_order
316 ___
317 {{{
318 my $Xi=4;
319 my @X=map("%xmm$_",(4..7,0..3));
320 my @Tx=map("%xmm$_",(8..10));
321 my $Kx="%xmm11";
322 my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp");    # size optimization
323 my @T=("%esi","%edi");
324 my $j=0;
325 my $rx=0;
326 my $K_XX_XX="%r11";
327
328 my $_rol=sub { &rol(@_) };
329 my $_ror=sub { &ror(@_) };
330
331 { my $sn;
332 sub align32() {
333   ++$sn;
334 $code.=<<___;
335         jmp     .Lalign32_$sn   # see "Decoded ICache" in manual
336 .align  32
337 .Lalign32_$sn:
338 ___
339 }
340 }
341
342 $code.=<<___;
343 .type   sha1_block_data_order_ssse3,\@function,3
344 .align  16
345 sha1_block_data_order_ssse3:
346 _ssse3_shortcut:
347         mov     %rsp,%rax
348         push    %rbx
349         push    %rbp
350         push    %r12
351         push    %r13            # redundant, done to share Win64 SE handler
352         push    %r14
353         lea     `-64-($win64?6*16:0)`(%rsp),%rsp
354 ___
355 $code.=<<___ if ($win64);
356         movaps  %xmm6,-40-6*16(%rax)
357         movaps  %xmm7,-40-5*16(%rax)
358         movaps  %xmm8,-40-4*16(%rax)
359         movaps  %xmm9,-40-3*16(%rax)
360         movaps  %xmm10,-40-2*16(%rax)
361         movaps  %xmm11,-40-1*16(%rax)
362 .Lprologue_ssse3:
363 ___
364 $code.=<<___;
365         mov     %rax,%r14       # original %rsp
366         and     \$-64,%rsp
367         mov     %rdi,$ctx       # reassigned argument
368         mov     %rsi,$inp       # reassigned argument
369         mov     %rdx,$num       # reassigned argument
370
371         shl     \$6,$num
372         add     $inp,$num
373         lea     K_XX_XX+64(%rip),$K_XX_XX
374
375         mov     0($ctx),$A              # load context
376         mov     4($ctx),$B
377         mov     8($ctx),$C
378         mov     12($ctx),$D
379         mov     $B,@T[0]                # magic seed
380         mov     16($ctx),$E
381         mov     $C,@T[1]
382         xor     $D,@T[1]
383         and     @T[1],@T[0]
384
385         movdqa  64($K_XX_XX),@X[2]      # pbswap mask
386         movdqa  -64($K_XX_XX),@Tx[1]    # K_00_19
387         movdqu  0($inp),@X[-4&7]        # load input to %xmm[0-3]
388         movdqu  16($inp),@X[-3&7]
389         movdqu  32($inp),@X[-2&7]
390         movdqu  48($inp),@X[-1&7]
391         pshufb  @X[2],@X[-4&7]          # byte swap
392         add     \$64,$inp
393         pshufb  @X[2],@X[-3&7]
394         pshufb  @X[2],@X[-2&7]
395         pshufb  @X[2],@X[-1&7]
396         paddd   @Tx[1],@X[-4&7]         # add K_00_19
397         paddd   @Tx[1],@X[-3&7]
398         paddd   @Tx[1],@X[-2&7]
399         movdqa  @X[-4&7],0(%rsp)        # X[]+K xfer to IALU
400         psubd   @Tx[1],@X[-4&7]         # restore X[]
401         movdqa  @X[-3&7],16(%rsp)
402         psubd   @Tx[1],@X[-3&7]
403         movdqa  @X[-2&7],32(%rsp)
404         psubd   @Tx[1],@X[-2&7]
405         jmp     .Loop_ssse3
406 ___
407
408 sub AUTOLOAD()          # thunk [simplified] 32-bit style perlasm
409 { my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
410   my $arg = pop;
411     $arg = "\$$arg" if ($arg*1 eq $arg);
412     $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
413 }
414
415 sub Xupdate_ssse3_16_31()               # recall that $Xi starts wtih 4
416 { use integer;
417   my $body = shift;
418   my @insns = (&$body,&$body,&$body,&$body);    # 40 instructions
419   my ($a,$b,$c,$d,$e);
420
421         &movdqa (@X[0],@X[-3&7]);
422          eval(shift(@insns));
423          eval(shift(@insns));
424         &movdqa (@Tx[0],@X[-1&7]);
425         &palignr(@X[0],@X[-4&7],8);     # compose "X[-14]" in "X[0]"
426          eval(shift(@insns));
427          eval(shift(@insns));
428
429           &paddd        (@Tx[1],@X[-1&7]);
430          eval(shift(@insns));
431          eval(shift(@insns));
432         &psrldq (@Tx[0],4);             # "X[-3]", 3 dwords
433          eval(shift(@insns));
434          eval(shift(@insns));
435         &pxor   (@X[0],@X[-4&7]);       # "X[0]"^="X[-16]"
436          eval(shift(@insns));
437          eval(shift(@insns));
438
439         &pxor   (@Tx[0],@X[-2&7]);      # "X[-3]"^"X[-8]"
440          eval(shift(@insns));
441          eval(shift(@insns));
442          eval(shift(@insns));
443          eval(shift(@insns));
444
445         &pxor   (@X[0],@Tx[0]);         # "X[0]"^="X[-3]"^"X[-8]"
446          eval(shift(@insns));
447          eval(shift(@insns));
448           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
449          eval(shift(@insns));
450          eval(shift(@insns));
451
452         &movdqa (@Tx[2],@X[0]);
453         &movdqa (@Tx[0],@X[0]);
454          eval(shift(@insns));
455          eval(shift(@insns));
456          eval(shift(@insns));
457          eval(shift(@insns));
458
459         &pslldq (@Tx[2],12);            # "X[0]"<<96, extract one dword
460         &paddd  (@X[0],@X[0]);
461          eval(shift(@insns));
462          eval(shift(@insns));
463          eval(shift(@insns));
464          eval(shift(@insns));
465
466         &psrld  (@Tx[0],31);
467          eval(shift(@insns));
468          eval(shift(@insns));
469         &movdqa (@Tx[1],@Tx[2]);
470          eval(shift(@insns));
471          eval(shift(@insns));
472
473         &psrld  (@Tx[2],30);
474         &por    (@X[0],@Tx[0]);         # "X[0]"<<<=1
475          eval(shift(@insns));
476          eval(shift(@insns));
477          eval(shift(@insns));
478          eval(shift(@insns));
479
480         &pslld  (@Tx[1],2);
481         &pxor   (@X[0],@Tx[2]);
482          eval(shift(@insns));
483          eval(shift(@insns));
484           &movdqa       (@Tx[2],eval(2*16*(($Xi)/5)-64)."($K_XX_XX)");  # K_XX_XX
485          eval(shift(@insns));
486          eval(shift(@insns));
487
488         &pxor   (@X[0],@Tx[1]);         # "X[0]"^=("X[0]">>96)<<<2
489
490          foreach (@insns) { eval; }     # remaining instructions [if any]
491
492   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
493                 push(@Tx,shift(@Tx));
494 }
495
496 sub Xupdate_ssse3_32_79()
497 { use integer;
498   my $body = shift;
499   my @insns = (&$body,&$body,&$body,&$body);    # 32 to 44 instructions
500   my ($a,$b,$c,$d,$e);
501
502         &movdqa (@Tx[0],@X[-1&7])       if ($Xi==8);
503          eval(shift(@insns));           # body_20_39
504         &pxor   (@X[0],@X[-4&7]);       # "X[0]"="X[-32]"^"X[-16]"
505         &palignr(@Tx[0],@X[-2&7],8);    # compose "X[-6]"
506          eval(shift(@insns));
507          eval(shift(@insns));
508          eval(shift(@insns));           # rol
509
510         &pxor   (@X[0],@X[-7&7]);       # "X[0]"^="X[-28]"
511          eval(shift(@insns));
512          eval(shift(@insns))    if (@insns[0] !~ /&ro[rl]/);
513         if ($Xi%5) {
514           &movdqa       (@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX...
515         } else {                        # ... or load next one
516           &movdqa       (@Tx[2],eval(2*16*($Xi/5)-64)."($K_XX_XX)");
517         }
518           &paddd        (@Tx[1],@X[-1&7]);
519          eval(shift(@insns));           # ror
520          eval(shift(@insns));
521
522         &pxor   (@X[0],@Tx[0]);         # "X[0]"^="X[-6]"
523          eval(shift(@insns));           # body_20_39
524          eval(shift(@insns));
525          eval(shift(@insns));
526          eval(shift(@insns));           # rol
527
528         &movdqa (@Tx[0],@X[0]);
529           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
530          eval(shift(@insns));
531          eval(shift(@insns));
532          eval(shift(@insns));           # ror
533          eval(shift(@insns));
534
535         &pslld  (@X[0],2);
536          eval(shift(@insns));           # body_20_39
537          eval(shift(@insns));
538         &psrld  (@Tx[0],30);
539          eval(shift(@insns));
540          eval(shift(@insns));           # rol
541          eval(shift(@insns));
542          eval(shift(@insns));
543          eval(shift(@insns));           # ror
544          eval(shift(@insns));
545
546         &por    (@X[0],@Tx[0]);         # "X[0]"<<<=2
547          eval(shift(@insns));           # body_20_39
548          eval(shift(@insns));
549           &movdqa       (@Tx[1],@X[0])  if ($Xi<19);
550          eval(shift(@insns));
551          eval(shift(@insns));           # rol
552          eval(shift(@insns));
553          eval(shift(@insns));
554          eval(shift(@insns));           # rol
555          eval(shift(@insns));
556
557          foreach (@insns) { eval; }     # remaining instructions
558
559   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
560                 push(@Tx,shift(@Tx));
561 }
562
563 sub Xuplast_ssse3_80()
564 { use integer;
565   my $body = shift;
566   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
567   my ($a,$b,$c,$d,$e);
568
569          eval(shift(@insns));
570           &paddd        (@Tx[1],@X[-1&7]);
571          eval(shift(@insns));
572          eval(shift(@insns));
573          eval(shift(@insns));
574          eval(shift(@insns));
575
576           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
577
578          foreach (@insns) { eval; }             # remaining instructions
579
580         &cmp    ($inp,$num);
581         &je     (".Ldone_ssse3");
582
583         unshift(@Tx,pop(@Tx));
584
585         &movdqa (@X[2],"64($K_XX_XX)");         # pbswap mask
586         &movdqa (@Tx[1],"-64($K_XX_XX)");       # K_00_19
587         &movdqu (@X[-4&7],"0($inp)");           # load input
588         &movdqu (@X[-3&7],"16($inp)");
589         &movdqu (@X[-2&7],"32($inp)");
590         &movdqu (@X[-1&7],"48($inp)");
591         &pshufb (@X[-4&7],@X[2]);               # byte swap
592         &add    ($inp,64);
593
594   $Xi=0;
595 }
596
597 sub Xloop_ssse3()
598 { use integer;
599   my $body = shift;
600   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
601   my ($a,$b,$c,$d,$e);
602
603          eval(shift(@insns));
604          eval(shift(@insns));
605         &pshufb (@X[($Xi-3)&7],@X[2]);
606          eval(shift(@insns));
607          eval(shift(@insns));
608          eval(shift(@insns));
609         &paddd  (@X[($Xi-4)&7],@Tx[1]);
610          eval(shift(@insns));
611          eval(shift(@insns));
612          eval(shift(@insns));
613          eval(shift(@insns));
614         &movdqa (eval(16*$Xi)."(%rsp)",@X[($Xi-4)&7]);  # X[]+K xfer to IALU
615          eval(shift(@insns));
616          eval(shift(@insns));
617         &psubd  (@X[($Xi-4)&7],@Tx[1]);
618
619         foreach (@insns) { eval; }
620   $Xi++;
621 }
622
623 sub Xtail_ssse3()
624 { use integer;
625   my $body = shift;
626   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
627   my ($a,$b,$c,$d,$e);
628
629         foreach (@insns) { eval; }
630 }
631
632 sub body_00_19 () {     # ((c^d)&b)^d
633         # on start @T[0]=(c^d)&b
634         return &body_20_39() if ($rx==19); $rx++;
635         (
636         '($a,$b,$c,$d,$e)=@V;'.
637         '&$_ror ($b,$j?7:2)',   # $b>>>2
638         '&xor   (@T[0],$d)',
639         '&mov   (@T[1],$a)',    # $b for next round
640
641         '&add   ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer
642         '&xor   ($b,$c)',       # $c^$d for next round
643
644         '&$_rol ($a,5)',
645         '&add   ($e,@T[0])',
646         '&and   (@T[1],$b)',    # ($b&($c^$d)) for next round
647
648         '&xor   ($b,$c)',       # restore $b
649         '&add   ($e,$a);'       .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
650         );
651 }
652
653 sub body_20_39 () {     # b^d^c
654         # on entry @T[0]=b^d
655         return &body_40_59() if ($rx==39); $rx++;
656         (
657         '($a,$b,$c,$d,$e)=@V;'.
658         '&add   ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer
659         '&xor   (@T[0],$d)      if($j==19);'.
660         '&xor   (@T[0],$c)      if($j> 19)',    # ($b^$d^$c)
661         '&mov   (@T[1],$a)',    # $b for next round
662
663         '&$_rol ($a,5)',
664         '&add   ($e,@T[0])',
665         '&xor   (@T[1],$c)      if ($j< 79)',   # $b^$d for next round
666
667         '&$_ror ($b,7)',        # $b>>>2
668         '&add   ($e,$a);'       .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
669         );
670 }
671
672 sub body_40_59 () {     # ((b^c)&(c^d))^c
673         # on entry @T[0]=(b^c), (c^=d)
674         $rx++;
675         (
676         '($a,$b,$c,$d,$e)=@V;'.
677         '&add   ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer
678         '&and   (@T[0],$c)      if ($j>=40)',   # (b^c)&(c^d)
679         '&xor   ($c,$d)         if ($j>=40)',   # restore $c
680
681         '&$_ror ($b,7)',        # $b>>>2
682         '&mov   (@T[1],$a)',    # $b for next round
683         '&xor   (@T[0],$c)',
684
685         '&$_rol ($a,5)',
686         '&add   ($e,@T[0])',
687         '&xor   (@T[1],$c)      if ($j==59);'.
688         '&xor   (@T[1],$b)      if ($j< 59)',   # b^c for next round
689
690         '&xor   ($b,$c)         if ($j< 59)',   # c^d for next round
691         '&add   ($e,$a);'       .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
692         );
693 }
694 $code.=<<___;
695 .align  16
696 .Loop_ssse3:
697 ___
698         &Xupdate_ssse3_16_31(\&body_00_19);
699         &Xupdate_ssse3_16_31(\&body_00_19);
700         &Xupdate_ssse3_16_31(\&body_00_19);
701         &Xupdate_ssse3_16_31(\&body_00_19);
702         &Xupdate_ssse3_32_79(\&body_00_19);
703         &Xupdate_ssse3_32_79(\&body_20_39);
704         &Xupdate_ssse3_32_79(\&body_20_39);
705         &Xupdate_ssse3_32_79(\&body_20_39);
706         &Xupdate_ssse3_32_79(\&body_20_39);
707         &Xupdate_ssse3_32_79(\&body_20_39);
708         &Xupdate_ssse3_32_79(\&body_40_59);
709         &Xupdate_ssse3_32_79(\&body_40_59);
710         &Xupdate_ssse3_32_79(\&body_40_59);
711         &Xupdate_ssse3_32_79(\&body_40_59);
712         &Xupdate_ssse3_32_79(\&body_40_59);
713         &Xupdate_ssse3_32_79(\&body_20_39);
714         &Xuplast_ssse3_80(\&body_20_39);        # can jump to "done"
715
716                                 $saved_j=$j; @saved_V=@V;
717
718         &Xloop_ssse3(\&body_20_39);
719         &Xloop_ssse3(\&body_20_39);
720         &Xloop_ssse3(\&body_20_39);
721
722 $code.=<<___;
723         add     0($ctx),$A                      # update context
724         add     4($ctx),@T[0]
725         add     8($ctx),$C
726         add     12($ctx),$D
727         mov     $A,0($ctx)
728         add     16($ctx),$E
729         mov     @T[0],4($ctx)
730         mov     @T[0],$B                        # magic seed
731         mov     $C,8($ctx)
732         mov     $C,@T[1]
733         mov     $D,12($ctx)
734         xor     $D,@T[1]
735         mov     $E,16($ctx)
736         and     @T[1],@T[0]
737         jmp     .Loop_ssse3
738
739 .align  16
740 .Ldone_ssse3:
741 ___
742                                 $j=$saved_j; @V=@saved_V;
743
744         &Xtail_ssse3(\&body_20_39);
745         &Xtail_ssse3(\&body_20_39);
746         &Xtail_ssse3(\&body_20_39);
747
748 $code.=<<___;
749         add     0($ctx),$A                      # update context
750         add     4($ctx),@T[0]
751         add     8($ctx),$C
752         mov     $A,0($ctx)
753         add     12($ctx),$D
754         mov     @T[0],4($ctx)
755         add     16($ctx),$E
756         mov     $C,8($ctx)
757         mov     $D,12($ctx)
758         mov     $E,16($ctx)
759 ___
760 $code.=<<___ if ($win64);
761         movaps  -40-6*16(%r14),%xmm6
762         movaps  -40-5*16(%r14),%xmm7
763         movaps  -40-4*16(%r14),%xmm8
764         movaps  -40-3*16(%r14),%xmm9
765         movaps  -40-2*16(%r14),%xmm10
766         movaps  -40-1*16(%r14),%xmm11
767 ___
768 $code.=<<___;
769         lea     (%r14),%rsi
770         mov     -40(%rsi),%r14
771         mov     -32(%rsi),%r13
772         mov     -24(%rsi),%r12
773         mov     -16(%rsi),%rbp
774         mov     -8(%rsi),%rbx
775         lea     (%rsi),%rsp
776 .Lepilogue_ssse3:
777         ret
778 .size   sha1_block_data_order_ssse3,.-sha1_block_data_order_ssse3
779 ___
780
781 if ($avx) {
782 $Xi=4;                          # reset variables
783 @X=map("%xmm$_",(4..7,0..3));
784 @Tx=map("%xmm$_",(8..10));
785 $j=0;
786 $rx=0;
787
788 my $done_avx_label=".Ldone_avx";
789
790 my $_rol=sub { &shld(@_[0],@_) };
791 my $_ror=sub { &shrd(@_[0],@_) };
792
793 $code.=<<___;
794 .type   sha1_block_data_order_avx,\@function,3
795 .align  16
796 sha1_block_data_order_avx:
797 _avx_shortcut:
798         mov     %rsp,%rax
799         push    %rbx
800         push    %rbp
801         push    %r12
802         push    %r13            # redundant, done to share Win64 SE handler
803         push    %r14
804         lea     `-64-($win64?6*16:0)`(%rsp),%rsp
805         vzeroupper
806 ___
807 $code.=<<___ if ($win64);
808         vmovaps %xmm6,-40-6*16(%rax)
809         vmovaps %xmm7,-40-5*16(%rax)
810         vmovaps %xmm8,-40-4*16(%rax)
811         vmovaps %xmm9,-40-3*16(%rax)
812         vmovaps %xmm10,-40-2*16(%rax)
813         vmovaps %xmm11,-40-1*16(%rax)
814 .Lprologue_avx:
815 ___
816 $code.=<<___;
817         mov     %rax,%r14       # original %rsp
818         and     \$-64,%rsp
819         mov     %rdi,$ctx       # reassigned argument
820         mov     %rsi,$inp       # reassigned argument
821         mov     %rdx,$num       # reassigned argument
822
823         shl     \$6,$num
824         add     $inp,$num
825         lea     K_XX_XX+64(%rip),$K_XX_XX
826
827         mov     0($ctx),$A              # load context
828         mov     4($ctx),$B
829         mov     8($ctx),$C
830         mov     12($ctx),$D
831         mov     $B,@T[0]                # magic seed
832         mov     16($ctx),$E
833         mov     $C,@T[1]
834         xor     $D,@T[1]
835         and     @T[1],@T[0]
836
837         vmovdqa 64($K_XX_XX),@X[2]      # pbswap mask
838         vmovdqa -64($K_XX_XX),$Kx       # K_00_19
839         vmovdqu 0($inp),@X[-4&7]        # load input to %xmm[0-3]
840         vmovdqu 16($inp),@X[-3&7]
841         vmovdqu 32($inp),@X[-2&7]
842         vmovdqu 48($inp),@X[-1&7]
843         vpshufb @X[2],@X[-4&7],@X[-4&7] # byte swap
844         add     \$64,$inp
845         vpshufb @X[2],@X[-3&7],@X[-3&7]
846         vpshufb @X[2],@X[-2&7],@X[-2&7]
847         vpshufb @X[2],@X[-1&7],@X[-1&7]
848         vpaddd  $Kx,@X[-4&7],@X[0]      # add K_00_19
849         vpaddd  $Kx,@X[-3&7],@X[1]
850         vpaddd  $Kx,@X[-2&7],@X[2]
851         vmovdqa @X[0],0(%rsp)           # X[]+K xfer to IALU
852         vmovdqa @X[1],16(%rsp)
853         vmovdqa @X[2],32(%rsp)
854         jmp     .Loop_avx
855 ___
856
857 sub Xupdate_avx_16_31()         # recall that $Xi starts wtih 4
858 { use integer;
859   my $body = shift;
860   my @insns = (&$body,&$body,&$body,&$body);    # 40 instructions
861   my ($a,$b,$c,$d,$e);
862
863          eval(shift(@insns));
864          eval(shift(@insns));
865         &vpalignr(@X[0],@X[-3&7],@X[-4&7],8);   # compose "X[-14]" in "X[0]"
866          eval(shift(@insns));
867          eval(shift(@insns));
868
869           &vpaddd       (@Tx[1],$Kx,@X[-1&7]);
870          eval(shift(@insns));
871          eval(shift(@insns));
872         &vpsrldq(@Tx[0],@X[-1&7],4);            # "X[-3]", 3 dwords
873          eval(shift(@insns));
874          eval(shift(@insns));
875         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"^="X[-16]"
876          eval(shift(@insns));
877          eval(shift(@insns));
878
879         &vpxor  (@Tx[0],@Tx[0],@X[-2&7]);       # "X[-3]"^"X[-8]"
880          eval(shift(@insns));
881          eval(shift(@insns));
882          eval(shift(@insns));
883          eval(shift(@insns));
884
885         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-3]"^"X[-8]"
886          eval(shift(@insns));
887          eval(shift(@insns));
888           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
889          eval(shift(@insns));
890          eval(shift(@insns));
891
892         &vpsrld (@Tx[0],@X[0],31);
893          eval(shift(@insns));
894          eval(shift(@insns));
895          eval(shift(@insns));
896          eval(shift(@insns));
897
898         &vpslldq(@Tx[2],@X[0],12);              # "X[0]"<<96, extract one dword
899         &vpaddd (@X[0],@X[0],@X[0]);
900          eval(shift(@insns));
901          eval(shift(@insns));
902          eval(shift(@insns));
903          eval(shift(@insns));
904
905         &vpsrld (@Tx[1],@Tx[2],30);
906         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=1
907          eval(shift(@insns));
908          eval(shift(@insns));
909          eval(shift(@insns));
910          eval(shift(@insns));
911
912         &vpslld (@Tx[2],@Tx[2],2);
913         &vpxor  (@X[0],@X[0],@Tx[1]);
914          eval(shift(@insns));
915          eval(shift(@insns));
916          eval(shift(@insns));
917          eval(shift(@insns));
918
919         &vpxor  (@X[0],@X[0],@Tx[2]);           # "X[0]"^=("X[0]">>96)<<<2
920          eval(shift(@insns));
921          eval(shift(@insns));
922           &vmovdqa      ($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)")      if ($Xi%5==0);  # K_XX_XX
923          eval(shift(@insns));
924          eval(shift(@insns));
925
926
927          foreach (@insns) { eval; }     # remaining instructions [if any]
928
929   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
930 }
931
932 sub Xupdate_avx_32_79()
933 { use integer;
934   my $body = shift;
935   my @insns = (&$body,&$body,&$body,&$body);    # 32 to 44 instructions
936   my ($a,$b,$c,$d,$e);
937
938         &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8);  # compose "X[-6]"
939         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"="X[-32]"^"X[-16]"
940          eval(shift(@insns));           # body_20_39
941          eval(shift(@insns));
942          eval(shift(@insns));
943          eval(shift(@insns));           # rol
944
945         &vpxor  (@X[0],@X[0],@X[-7&7]);         # "X[0]"^="X[-28]"
946          eval(shift(@insns));
947          eval(shift(@insns))    if (@insns[0] !~ /&ro[rl]/);
948           &vpaddd       (@Tx[1],$Kx,@X[-1&7]);
949           &vmovdqa      ($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)")        if ($Xi%5==0);
950          eval(shift(@insns));           # ror
951          eval(shift(@insns));
952
953         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-6]"
954          eval(shift(@insns));           # body_20_39
955          eval(shift(@insns));
956          eval(shift(@insns));
957          eval(shift(@insns));           # rol
958
959         &vpsrld (@Tx[0],@X[0],30);
960           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
961          eval(shift(@insns));
962          eval(shift(@insns));
963          eval(shift(@insns));           # ror
964          eval(shift(@insns));
965
966         &vpslld (@X[0],@X[0],2);
967          eval(shift(@insns));           # body_20_39
968          eval(shift(@insns));
969          eval(shift(@insns));
970          eval(shift(@insns));           # rol
971          eval(shift(@insns));
972          eval(shift(@insns));
973          eval(shift(@insns));           # ror
974          eval(shift(@insns));
975
976         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=2
977          eval(shift(@insns));           # body_20_39
978          eval(shift(@insns));
979          eval(shift(@insns));
980          eval(shift(@insns));           # rol
981          eval(shift(@insns));
982          eval(shift(@insns));
983          eval(shift(@insns));           # rol
984          eval(shift(@insns));
985
986          foreach (@insns) { eval; }     # remaining instructions
987
988   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
989 }
990
991 sub Xuplast_avx_80()
992 { use integer;
993   my $body = shift;
994   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
995   my ($a,$b,$c,$d,$e);
996
997          eval(shift(@insns));
998           &vpaddd       (@Tx[1],$Kx,@X[-1&7]);
999          eval(shift(@insns));
1000          eval(shift(@insns));
1001          eval(shift(@insns));
1002          eval(shift(@insns));
1003
1004           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
1005
1006          foreach (@insns) { eval; }             # remaining instructions
1007
1008         &cmp    ($inp,$num);
1009         &je     ($done_avx_label);
1010
1011         &vmovdqa(@X[2],"64($K_XX_XX)");         # pbswap mask
1012         &vmovdqa($Kx,"-64($K_XX_XX)");          # K_00_19
1013         &vmovdqu(@X[-4&7],"0($inp)");           # load input
1014         &vmovdqu(@X[-3&7],"16($inp)");
1015         &vmovdqu(@X[-2&7],"32($inp)");
1016         &vmovdqu(@X[-1&7],"48($inp)");
1017         &vpshufb(@X[-4&7],@X[-4&7],@X[2]);      # byte swap
1018         &add    ($inp,64);
1019
1020   $Xi=0;
1021 }
1022
1023 sub Xloop_avx()
1024 { use integer;
1025   my $body = shift;
1026   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
1027   my ($a,$b,$c,$d,$e);
1028
1029          eval(shift(@insns));
1030          eval(shift(@insns));
1031         &vpshufb(@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]);
1032          eval(shift(@insns));
1033          eval(shift(@insns));
1034         &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],$Kx);
1035          eval(shift(@insns));
1036          eval(shift(@insns));
1037          eval(shift(@insns));
1038          eval(shift(@insns));
1039         &vmovdqa(eval(16*$Xi)."(%rsp)",@X[$Xi&7]);      # X[]+K xfer to IALU
1040          eval(shift(@insns));
1041          eval(shift(@insns));
1042
1043         foreach (@insns) { eval; }
1044   $Xi++;
1045 }
1046
1047 sub Xtail_avx()
1048 { use integer;
1049   my $body = shift;
1050   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
1051   my ($a,$b,$c,$d,$e);
1052
1053         foreach (@insns) { eval; }
1054 }
1055
1056 $code.=<<___;
1057 .align  16
1058 .Loop_avx:
1059 ___
1060         &Xupdate_avx_16_31(\&body_00_19);
1061         &Xupdate_avx_16_31(\&body_00_19);
1062         &Xupdate_avx_16_31(\&body_00_19);
1063         &Xupdate_avx_16_31(\&body_00_19);
1064         &Xupdate_avx_32_79(\&body_00_19);
1065         &Xupdate_avx_32_79(\&body_20_39);
1066         &Xupdate_avx_32_79(\&body_20_39);
1067         &Xupdate_avx_32_79(\&body_20_39);
1068         &Xupdate_avx_32_79(\&body_20_39);
1069         &Xupdate_avx_32_79(\&body_20_39);
1070         &Xupdate_avx_32_79(\&body_40_59);
1071         &Xupdate_avx_32_79(\&body_40_59);
1072         &Xupdate_avx_32_79(\&body_40_59);
1073         &Xupdate_avx_32_79(\&body_40_59);
1074         &Xupdate_avx_32_79(\&body_40_59);
1075         &Xupdate_avx_32_79(\&body_20_39);
1076         &Xuplast_avx_80(\&body_20_39);  # can jump to "done"
1077
1078                                 $saved_j=$j; @saved_V=@V;
1079
1080         &Xloop_avx(\&body_20_39);
1081         &Xloop_avx(\&body_20_39);
1082         &Xloop_avx(\&body_20_39);
1083
1084 $code.=<<___;
1085         add     0($ctx),$A                      # update context
1086         add     4($ctx),@T[0]
1087         add     8($ctx),$C
1088         add     12($ctx),$D
1089         mov     $A,0($ctx)
1090         add     16($ctx),$E
1091         mov     @T[0],4($ctx)
1092         mov     @T[0],$B                        # magic seed
1093         mov     $C,8($ctx)
1094         mov     $C,@T[1]
1095         mov     $D,12($ctx)
1096         xor     $D,@T[1]
1097         mov     $E,16($ctx)
1098         and     @T[1],@T[0]
1099         jmp     .Loop_avx
1100
1101 .align  16
1102 $done_avx_label:
1103 ___
1104                                 $j=$saved_j; @V=@saved_V;
1105
1106         &Xtail_avx(\&body_20_39);
1107         &Xtail_avx(\&body_20_39);
1108         &Xtail_avx(\&body_20_39);
1109
1110 $code.=<<___;
1111         vzeroupper
1112
1113         add     0($ctx),$A                      # update context
1114         add     4($ctx),@T[0]
1115         add     8($ctx),$C
1116         mov     $A,0($ctx)
1117         add     12($ctx),$D
1118         mov     @T[0],4($ctx)
1119         add     16($ctx),$E
1120         mov     $C,8($ctx)
1121         mov     $D,12($ctx)
1122         mov     $E,16($ctx)
1123 ___
1124 $code.=<<___ if ($win64);
1125         movaps  -40-6*16(%r14),%xmm6
1126         movaps  -40-5*16(%r14),%xmm7
1127         movaps  -40-4*16(%r14),%xmm8
1128         movaps  -40-3*16(%r14),%xmm9
1129         movaps  -40-2*16(%r14),%xmm10
1130         movaps  -40-1*16(%r14),%xmm11
1131 ___
1132 $code.=<<___;
1133         lea     (%r14),%rsi
1134         mov     -40(%rsi),%r14
1135         mov     -32(%rsi),%r13
1136         mov     -24(%rsi),%r12
1137         mov     -16(%rsi),%rbp
1138         mov     -8(%rsi),%rbx
1139         lea     (%rsi),%rsp
1140 .Lepilogue_avx:
1141         ret
1142 .size   sha1_block_data_order_avx,.-sha1_block_data_order_avx
1143 ___
1144
1145 if ($avx>1) {
1146 use integer;
1147 $Xi=4;                                  # reset variables
1148 @X=map("%ymm$_",(4..7,0..3));
1149 @Tx=map("%ymm$_",(8..10));
1150 $Kx="%ymm11";
1151 $j=0;
1152
1153 my @ROTX=("%eax","%ebp","%ebx","%ecx","%edx","%esi");
1154 my ($a5,$t0)=("%r12d","%edi");
1155
1156 my ($A,$F,$B,$C,$D,$E)=@ROTX;
1157 my $rx=0;
1158 my $frame="%r13";
1159
1160 $code.=<<___;
1161 .type   sha1_block_data_order_avx2,\@function,3
1162 .align  16
1163 sha1_block_data_order_avx2:
1164 _avx2_shortcut:
1165         mov     %rsp,%rax
1166         push    %rbx
1167         push    %rbp
1168         push    %r12
1169         push    %r13
1170         push    %r14
1171         vzeroupper
1172 ___
1173 $code.=<<___ if ($win64);
1174         lea     -6*16(%rsp),%rsp
1175         vmovaps %xmm6,-40-6*16(%rax)
1176         vmovaps %xmm7,-40-5*16(%rax)
1177         vmovaps %xmm8,-40-4*16(%rax)
1178         vmovaps %xmm9,-40-3*16(%rax)
1179         vmovaps %xmm10,-40-2*16(%rax)
1180         vmovaps %xmm11,-40-1*16(%rax)
1181 .Lprologue_avx2:
1182 ___
1183 $code.=<<___;
1184         mov     %rax,%r14               # original %rsp
1185         mov     %rdi,$ctx               # reassigned argument
1186         mov     %rsi,$inp               # reassigned argument
1187         mov     %rdx,$num               # reassigned argument
1188
1189         lea     -640(%rsp),%rsp
1190         shl     \$6,$num
1191          lea    64($inp),$frame
1192         and     \$-128,%rsp
1193         add     $inp,$num
1194         lea     K_XX_XX+64(%rip),$K_XX_XX
1195
1196         mov     0($ctx),$A              # load context
1197          cmp    $num,$frame
1198          cmovae $inp,$frame             # next or same block
1199         mov     4($ctx),$F
1200         mov     8($ctx),$C
1201         mov     12($ctx),$D
1202         mov     16($ctx),$E
1203         vmovdqu 64($K_XX_XX),@X[2]      # pbswap mask
1204
1205         vmovdqu         ($inp),%xmm0
1206         vmovdqu         16($inp),%xmm1
1207         vmovdqu         32($inp),%xmm2
1208         vmovdqu         48($inp),%xmm3
1209         lea             64($inp),$inp
1210         vinserti128     \$1,($frame),@X[-4&7],@X[-4&7]
1211         vinserti128     \$1,16($frame),@X[-3&7],@X[-3&7]
1212         vpshufb         @X[2],@X[-4&7],@X[-4&7]
1213         vinserti128     \$1,32($frame),@X[-2&7],@X[-2&7]
1214         vpshufb         @X[2],@X[-3&7],@X[-3&7]
1215         vinserti128     \$1,48($frame),@X[-1&7],@X[-1&7]
1216         vpshufb         @X[2],@X[-2&7],@X[-2&7]
1217         vmovdqu         -64($K_XX_XX),$Kx       # K_00_19
1218         vpshufb         @X[2],@X[-1&7],@X[-1&7]
1219
1220         vpaddd  $Kx,@X[-4&7],@X[0]      # add K_00_19
1221         vpaddd  $Kx,@X[-3&7],@X[1]
1222         vmovdqu @X[0],0(%rsp)           # X[]+K xfer to IALU
1223         vpaddd  $Kx,@X[-2&7],@X[2]
1224         vmovdqu @X[1],32(%rsp)
1225         vpaddd  $Kx,@X[-1&7],@X[3]
1226         vmovdqu @X[2],64(%rsp)
1227         vmovdqu @X[3],96(%rsp)
1228 ___
1229 for (;$Xi<8;$Xi++) {    # Xupdate_avx2_16_31
1230     use integer;
1231
1232         &vpalignr(@X[0],@X[-3&7],@X[-4&7],8);   # compose "X[-14]" in "X[0]"
1233         &vpsrldq(@Tx[0],@X[-1&7],4);            # "X[-3]", 3 dwords
1234         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"^="X[-16]"
1235         &vpxor  (@Tx[0],@Tx[0],@X[-2&7]);       # "X[-3]"^"X[-8]"
1236         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-3]"^"X[-8]"
1237         &vpsrld (@Tx[0],@X[0],31);
1238         &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)")      if ($Xi%5==0);  # K_XX_XX
1239         &vpslldq(@Tx[2],@X[0],12);              # "X[0]"<<96, extract one dword
1240         &vpaddd (@X[0],@X[0],@X[0]);
1241         &vpsrld (@Tx[1],@Tx[2],30);
1242         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=1
1243         &vpslld (@Tx[2],@Tx[2],2);
1244         &vpxor  (@X[0],@X[0],@Tx[1]);
1245         &vpxor  (@X[0],@X[0],@Tx[2]);           # "X[0]"^=("X[0]">>96)<<<2
1246         &vpaddd (@Tx[1],@X[0],$Kx);
1247         &vmovdqu("32*$Xi(%rsp)",@Tx[1]);        # X[]+K xfer to IALU
1248
1249         push(@X,shift(@X));     # "rotate" X[]
1250 }
1251 $code.=<<___;
1252         lea     128(%rsp),$frame
1253         jmp     .Loop_avx2
1254 .align  32
1255 .Loop_avx2:
1256         rorx    \$2,$F,$B
1257         andn    $D,$F,$t0
1258         and     $C,$F
1259         xor     $t0,$F
1260 ___
1261 sub bodyx_00_19 () {    # 8 instructions, 3 cycles critical path
1262         # at start $f=(b&c)^(~b&d), $b>>>=2
1263         return &bodyx_20_39() if ($rx==19); $rx++;
1264         (
1265         '($a,$f,$b,$c,$d,$e)=@ROTX;'.
1266
1267         '&add   ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'.       # e+=X[i]+K
1268          '&lea  ($frame,"256($frame)")  if ($j%32==31);',
1269         '&andn  ($t0,$a,$c)',                   # ~b&d for next round
1270
1271         '&add   ($e,$f)',                       # e+=(b&c)^(~b&d)
1272         '&rorx  ($a5,$a,27)',                   # a<<<5
1273         '&rorx  ($f,$a,2)',                     # b>>>2 for next round
1274         '&and   ($a,$b)',                       # b&c for next round
1275
1276         '&add   ($e,$a5)',                      # e+=a<<<5
1277         '&xor   ($a,$t0);'.                     # f=(b&c)^(~b&d) for next round
1278
1279         'unshift(@ROTX,pop(@ROTX)); $j++;'
1280         )
1281 }
1282
1283 sub bodyx_20_39 () {    # 7 instructions, 2 cycles critical path
1284         # on entry $f=b^c^d, $b>>>=2
1285         return &bodyx_40_59() if ($rx==39); $rx++;
1286         (
1287         '($a,$f,$b,$c,$d,$e)=@ROTX;'.
1288
1289         '&add   ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'.       # e+=X[i]+K
1290          '&lea  ($frame,"256($frame)")  if ($j%32==31);',
1291
1292         '&lea   ($e,"($e,$f)")',                # e+=b^c^d
1293         '&rorx  ($a5,$a,27)',                   # a<<<5
1294         '&rorx  ($f,$a,2)       if ($j<79)',    # b>>>2 in next round
1295         '&xor   ($a,$b)         if ($j<79)',    # b^c for next round
1296
1297         '&add   ($e,$a5)',                      # e+=a<<<5
1298         '&xor   ($a,$c)         if ($j<79);'.   # f=b^c^d for next round
1299
1300         'unshift(@ROTX,pop(@ROTX)); $j++;'
1301         )
1302 }
1303
1304 sub bodyx_40_59 () {    # 10 instructions, 3 cycles critical path
1305         # on entry $f=((b^c)&(c^d)), $b>>>=2
1306         $rx++;
1307         (
1308         '($a,$f,$b,$c,$d,$e)=@ROTX;'.
1309
1310         '&add   ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'.       # e+=X[i]+K
1311          '&lea  ($frame,"256($frame)")  if ($j%32==31);',
1312         '&xor   ($f,$c)         if ($j>39)',    # (b^c)&(c^d)^c
1313         '&mov   ($t0,$b)        if ($j<59)',    # count on zero latency
1314         '&xor   ($t0,$c)        if ($j<59)',    # c^d for next round
1315
1316         '&lea   ($e,"($e,$f)")',                # e+=(b^c)&(c^d)^c
1317         '&rorx  ($a5,$a,27)',                   # a<<<5
1318         '&rorx  ($f,$a,2)',                     # b>>>2 in next round
1319         '&xor   ($a,$b)',                       # b^c for next round
1320
1321         '&add   ($e,$a5)',                      # e+=a<<<5
1322         '&and   ($a,$t0)        if ($j< 59);'.  # f=(b^c)&(c^d) for next round
1323         '&xor   ($a,$c)         if ($j==59);'.  # f=b^c^d for next round
1324
1325         'unshift(@ROTX,pop(@ROTX)); $j++;'
1326         )
1327 }
1328
1329 sub Xupdate_avx2_16_31()                # recall that $Xi starts wtih 4
1330 { use integer;
1331   my $body = shift;
1332   my @insns = (&$body,&$body,&$body,&$body,&$body);     # 35 instructions
1333   my ($a,$b,$c,$d,$e);
1334
1335         &vpalignr(@X[0],@X[-3&7],@X[-4&7],8);   # compose "X[-14]" in "X[0]"
1336          eval(shift(@insns));
1337          eval(shift(@insns));
1338          eval(shift(@insns));
1339          eval(shift(@insns));
1340
1341         &vpsrldq(@Tx[0],@X[-1&7],4);            # "X[-3]", 3 dwords
1342          eval(shift(@insns));
1343          eval(shift(@insns));
1344          eval(shift(@insns));
1345
1346         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"^="X[-16]"
1347         &vpxor  (@Tx[0],@Tx[0],@X[-2&7]);       # "X[-3]"^"X[-8]"
1348          eval(shift(@insns));
1349          eval(shift(@insns));
1350
1351         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-3]"^"X[-8]"
1352          eval(shift(@insns));
1353          eval(shift(@insns));
1354          eval(shift(@insns));
1355          eval(shift(@insns));
1356
1357         &vpsrld (@Tx[0],@X[0],31);
1358         &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)")      if ($Xi%5==0);  # K_XX_XX
1359          eval(shift(@insns));
1360          eval(shift(@insns));
1361          eval(shift(@insns));
1362
1363         &vpslldq(@Tx[2],@X[0],12);              # "X[0]"<<96, extract one dword
1364         &vpaddd (@X[0],@X[0],@X[0]);
1365          eval(shift(@insns));
1366          eval(shift(@insns));
1367
1368         &vpsrld (@Tx[1],@Tx[2],30);
1369         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=1
1370          eval(shift(@insns));
1371          eval(shift(@insns));
1372
1373         &vpslld (@Tx[2],@Tx[2],2);
1374         &vpxor  (@X[0],@X[0],@Tx[1]);
1375          eval(shift(@insns));
1376          eval(shift(@insns));
1377
1378         &vpxor  (@X[0],@X[0],@Tx[2]);           # "X[0]"^=("X[0]">>96)<<<2
1379          eval(shift(@insns));
1380          eval(shift(@insns));
1381          eval(shift(@insns));
1382
1383         &vpaddd (@Tx[1],@X[0],$Kx);
1384          eval(shift(@insns));
1385          eval(shift(@insns));
1386          eval(shift(@insns));
1387         &vmovdqu(eval(32*($Xi))."(%rsp)",@Tx[1]);       # X[]+K xfer to IALU
1388
1389          foreach (@insns) { eval; }     # remaining instructions [if any]
1390
1391         $Xi++;
1392         push(@X,shift(@X));     # "rotate" X[]
1393 }
1394
1395 sub Xupdate_avx2_32_79()
1396 { use integer;
1397   my $body = shift;
1398   my @insns = (&$body,&$body,&$body,&$body,&$body);     # 35 to 50 instructions
1399   my ($a,$b,$c,$d,$e);
1400
1401         &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8);  # compose "X[-6]"
1402         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"="X[-32]"^"X[-16]"
1403          eval(shift(@insns));
1404          eval(shift(@insns));
1405
1406         &vpxor  (@X[0],@X[0],@X[-7&7]);         # "X[0]"^="X[-28]"
1407         &vmovdqu($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)")        if ($Xi%5==0);
1408          eval(shift(@insns));
1409          eval(shift(@insns));
1410          eval(shift(@insns));
1411
1412         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-6]"
1413          eval(shift(@insns));
1414          eval(shift(@insns));
1415          eval(shift(@insns));
1416
1417         &vpsrld (@Tx[0],@X[0],30);
1418         &vpslld (@X[0],@X[0],2);
1419          eval(shift(@insns));
1420          eval(shift(@insns));
1421          eval(shift(@insns));
1422
1423         #&vpslld        (@X[0],@X[0],2);
1424          eval(shift(@insns));
1425          eval(shift(@insns));
1426          eval(shift(@insns));
1427
1428         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=2
1429          eval(shift(@insns));
1430          eval(shift(@insns));
1431          eval(shift(@insns));
1432          eval(shift(@insns));
1433
1434         &vpaddd (@Tx[1],@X[0],$Kx);
1435          eval(shift(@insns));
1436          eval(shift(@insns));
1437          eval(shift(@insns));
1438          eval(shift(@insns));
1439
1440         &vmovdqu("32*$Xi(%rsp)",@Tx[1]);        # X[]+K xfer to IALU
1441
1442          foreach (@insns) { eval; }     # remaining instructions
1443
1444         $Xi++;
1445         push(@X,shift(@X));     # "rotate" X[]
1446 }
1447
1448 sub Xloop_avx2()
1449 { use integer;
1450   my $body = shift;
1451   my @insns = (&$body,&$body,&$body,&$body,&$body);     # 32 instructions
1452   my ($a,$b,$c,$d,$e);
1453
1454          foreach (@insns) { eval; }
1455 }
1456
1457         &align32();
1458         &Xupdate_avx2_32_79(\&bodyx_00_19);
1459         &Xupdate_avx2_32_79(\&bodyx_00_19);
1460         &Xupdate_avx2_32_79(\&bodyx_00_19);
1461         &Xupdate_avx2_32_79(\&bodyx_00_19);
1462
1463         &Xupdate_avx2_32_79(\&bodyx_20_39);
1464         &Xupdate_avx2_32_79(\&bodyx_20_39);
1465         &Xupdate_avx2_32_79(\&bodyx_20_39);
1466         &Xupdate_avx2_32_79(\&bodyx_20_39);
1467
1468         &align32();
1469         &Xupdate_avx2_32_79(\&bodyx_40_59);
1470         &Xupdate_avx2_32_79(\&bodyx_40_59);
1471         &Xupdate_avx2_32_79(\&bodyx_40_59);
1472         &Xupdate_avx2_32_79(\&bodyx_40_59);
1473
1474         &Xloop_avx2(\&bodyx_20_39);
1475         &Xloop_avx2(\&bodyx_20_39);
1476         &Xloop_avx2(\&bodyx_20_39);
1477         &Xloop_avx2(\&bodyx_20_39);
1478
1479 $code.=<<___;
1480         lea     128($inp),$frame
1481         lea     128($inp),%rdi                  # borrow $t0
1482         cmp     $num,$frame
1483         cmovae  $inp,$frame                     # next or previous block
1484
1485         # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c
1486         add     0($ctx),@ROTX[0]                # update context
1487         add     4($ctx),@ROTX[1]
1488         add     8($ctx),@ROTX[3]
1489         mov     @ROTX[0],0($ctx)
1490         add     12($ctx),@ROTX[4]
1491         mov     @ROTX[1],4($ctx)
1492          mov    @ROTX[0],$A                     # A=d
1493         add     16($ctx),@ROTX[5]
1494          mov    @ROTX[3],$a5
1495         mov     @ROTX[3],8($ctx)
1496          mov    @ROTX[4],$D                     # D=b
1497          #xchg  @ROTX[5],$F                     # F=c, C=f
1498         mov     @ROTX[4],12($ctx)
1499          mov    @ROTX[1],$F                     # F=e
1500         mov     @ROTX[5],16($ctx)
1501         #mov    $F,16($ctx)
1502          mov    @ROTX[5],$E                     # E=c
1503          mov    $a5,$C                          # C=f
1504          #xchg  $F,$E                           # E=c, F=e
1505
1506         cmp     $num,$inp
1507         je      .Ldone_avx2
1508 ___
1509
1510 $Xi=4;                          # reset variables
1511 @X=map("%ymm$_",(4..7,0..3));
1512
1513 $code.=<<___;
1514         vmovdqu 64($K_XX_XX),@X[2]              # pbswap mask
1515         cmp     $num,%rdi                       # borrowed $t0
1516         ja      .Last_avx2
1517
1518         vmovdqu         -64(%rdi),%xmm0         # low part of @X[-4&7]
1519         vmovdqu         -48(%rdi),%xmm1
1520         vmovdqu         -32(%rdi),%xmm2
1521         vmovdqu         -16(%rdi),%xmm3
1522         vinserti128     \$1,0($frame),@X[-4&7],@X[-4&7]
1523         vinserti128     \$1,16($frame),@X[-3&7],@X[-3&7]
1524         vinserti128     \$1,32($frame),@X[-2&7],@X[-2&7]
1525         vinserti128     \$1,48($frame),@X[-1&7],@X[-1&7]
1526         jmp     .Last_avx2
1527
1528 .align  32
1529 .Last_avx2:
1530         lea     128+16(%rsp),$frame
1531         rorx    \$2,$F,$B
1532         andn    $D,$F,$t0
1533         and     $C,$F
1534         xor     $t0,$F
1535         sub     \$-128,$inp
1536 ___
1537         $rx=$j=0;       @ROTX=($A,$F,$B,$C,$D,$E);
1538
1539         &Xloop_avx2     (\&bodyx_00_19);
1540         &Xloop_avx2     (\&bodyx_00_19);
1541         &Xloop_avx2     (\&bodyx_00_19);
1542         &Xloop_avx2     (\&bodyx_00_19);
1543
1544         &Xloop_avx2     (\&bodyx_20_39);
1545           &vmovdqu      ($Kx,"-64($K_XX_XX)");          # K_00_19
1546           &vpshufb      (@X[-4&7],@X[-4&7],@X[2]);      # byte swap
1547         &Xloop_avx2     (\&bodyx_20_39);
1548           &vpshufb      (@X[-3&7],@X[-3&7],@X[2]);
1549           &vpaddd       (@Tx[0],@X[-4&7],$Kx);          # add K_00_19
1550         &Xloop_avx2     (\&bodyx_20_39);
1551           &vmovdqu      ("0(%rsp)",@Tx[0]);
1552           &vpshufb      (@X[-2&7],@X[-2&7],@X[2]);
1553           &vpaddd       (@Tx[1],@X[-3&7],$Kx);
1554         &Xloop_avx2     (\&bodyx_20_39);
1555           &vmovdqu      ("32(%rsp)",@Tx[1]);
1556           &vpshufb      (@X[-1&7],@X[-1&7],@X[2]);
1557           &vpaddd       (@X[2],@X[-2&7],$Kx);
1558
1559         &Xloop_avx2     (\&bodyx_40_59);
1560         &align32        ();
1561           &vmovdqu      ("64(%rsp)",@X[2]);
1562           &vpaddd       (@X[3],@X[-1&7],$Kx);
1563         &Xloop_avx2     (\&bodyx_40_59);
1564           &vmovdqu      ("96(%rsp)",@X[3]);
1565         &Xloop_avx2     (\&bodyx_40_59);
1566         &Xupdate_avx2_16_31(\&bodyx_40_59);
1567
1568         &Xupdate_avx2_16_31(\&bodyx_20_39);
1569         &Xupdate_avx2_16_31(\&bodyx_20_39);
1570         &Xupdate_avx2_16_31(\&bodyx_20_39);
1571         &Xloop_avx2     (\&bodyx_20_39);
1572
1573 $code.=<<___;
1574         lea     128(%rsp),$frame
1575
1576         # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c
1577         add     0($ctx),@ROTX[0]                # update context
1578         add     4($ctx),@ROTX[1]
1579         add     8($ctx),@ROTX[3]
1580         mov     @ROTX[0],0($ctx)
1581         add     12($ctx),@ROTX[4]
1582         mov     @ROTX[1],4($ctx)
1583          mov    @ROTX[0],$A                     # A=d
1584         add     16($ctx),@ROTX[5]
1585          mov    @ROTX[3],$a5
1586         mov     @ROTX[3],8($ctx)
1587          mov    @ROTX[4],$D                     # D=b
1588          #xchg  @ROTX[5],$F                     # F=c, C=f
1589         mov     @ROTX[4],12($ctx)
1590          mov    @ROTX[1],$F                     # F=e
1591         mov     @ROTX[5],16($ctx)
1592         #mov    $F,16($ctx)
1593          mov    @ROTX[5],$E                     # E=c
1594          mov    $a5,$C                          # C=f
1595          #xchg  $F,$E                           # E=c, F=e
1596
1597         cmp     $num,$inp
1598         jbe     .Loop_avx2
1599
1600 .Ldone_avx2:
1601         vzeroupper
1602 ___
1603 $code.=<<___ if ($win64);
1604         movaps  -40-6*16(%r14),%xmm6
1605         movaps  -40-5*16(%r14),%xmm7
1606         movaps  -40-4*16(%r14),%xmm8
1607         movaps  -40-3*16(%r14),%xmm9
1608         movaps  -40-2*16(%r14),%xmm10
1609         movaps  -40-1*16(%r14),%xmm11
1610 ___
1611 $code.=<<___;
1612         lea     (%r14),%rsi
1613         mov     -40(%rsi),%r14
1614         mov     -32(%rsi),%r13
1615         mov     -24(%rsi),%r12
1616         mov     -16(%rsi),%rbp
1617         mov     -8(%rsi),%rbx
1618         lea     (%rsi),%rsp
1619 .Lepilogue_avx2:
1620         ret
1621 .size   sha1_block_data_order_avx2,.-sha1_block_data_order_avx2
1622 ___
1623 }
1624 }
1625 $code.=<<___;
1626 .align  64
1627 K_XX_XX:
1628 .long   0x5a827999,0x5a827999,0x5a827999,0x5a827999     # K_00_19
1629 .long   0x5a827999,0x5a827999,0x5a827999,0x5a827999     # K_00_19
1630 .long   0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1     # K_20_39
1631 .long   0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1     # K_20_39
1632 .long   0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc     # K_40_59
1633 .long   0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc     # K_40_59
1634 .long   0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6     # K_60_79
1635 .long   0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6     # K_60_79
1636 .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap mask
1637 .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap mask
1638 ___
1639 }}}
1640 $code.=<<___;
1641 .asciz  "SHA1 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
1642 .align  64
1643 ___
1644
1645 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1646 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
1647 if ($win64) {
1648 $rec="%rcx";
1649 $frame="%rdx";
1650 $context="%r8";
1651 $disp="%r9";
1652
1653 $code.=<<___;
1654 .extern __imp_RtlVirtualUnwind
1655 .type   se_handler,\@abi-omnipotent
1656 .align  16
1657 se_handler:
1658         push    %rsi
1659         push    %rdi
1660         push    %rbx
1661         push    %rbp
1662         push    %r12
1663         push    %r13
1664         push    %r14
1665         push    %r15
1666         pushfq
1667         sub     \$64,%rsp
1668
1669         mov     120($context),%rax      # pull context->Rax
1670         mov     248($context),%rbx      # pull context->Rip
1671
1672         lea     .Lprologue(%rip),%r10
1673         cmp     %r10,%rbx               # context->Rip<.Lprologue
1674         jb      .Lcommon_seh_tail
1675
1676         mov     152($context),%rax      # pull context->Rsp
1677
1678         lea     .Lepilogue(%rip),%r10
1679         cmp     %r10,%rbx               # context->Rip>=.Lepilogue
1680         jae     .Lcommon_seh_tail
1681
1682         mov     `16*4`(%rax),%rax       # pull saved stack pointer
1683         lea     32(%rax),%rax
1684
1685         mov     -8(%rax),%rbx
1686         mov     -16(%rax),%rbp
1687         mov     -24(%rax),%r12
1688         mov     -32(%rax),%r13
1689         mov     %rbx,144($context)      # restore context->Rbx
1690         mov     %rbp,160($context)      # restore context->Rbp
1691         mov     %r12,216($context)      # restore context->R12
1692         mov     %r13,224($context)      # restore context->R13
1693
1694         jmp     .Lcommon_seh_tail
1695 .size   se_handler,.-se_handler
1696
1697 .type   ssse3_handler,\@abi-omnipotent
1698 .align  16
1699 ssse3_handler:
1700         push    %rsi
1701         push    %rdi
1702         push    %rbx
1703         push    %rbp
1704         push    %r12
1705         push    %r13
1706         push    %r14
1707         push    %r15
1708         pushfq
1709         sub     \$64,%rsp
1710
1711         mov     120($context),%rax      # pull context->Rax
1712         mov     248($context),%rbx      # pull context->Rip
1713
1714         mov     8($disp),%rsi           # disp->ImageBase
1715         mov     56($disp),%r11          # disp->HandlerData
1716
1717         mov     0(%r11),%r10d           # HandlerData[0]
1718         lea     (%rsi,%r10),%r10        # prologue label
1719         cmp     %r10,%rbx               # context->Rip<prologue label
1720         jb      .Lcommon_seh_tail
1721
1722         mov     152($context),%rax      # pull context->Rsp
1723
1724         mov     4(%r11),%r10d           # HandlerData[1]
1725         lea     (%rsi,%r10),%r10        # epilogue label
1726         cmp     %r10,%rbx               # context->Rip>=epilogue label
1727         jae     .Lcommon_seh_tail
1728
1729         mov     232($context),%rax      # pull context->R14
1730
1731         lea     -40-6*16(%rax),%rsi
1732         lea     512($context),%rdi      # &context.Xmm6
1733         mov     \$12,%ecx
1734         .long   0xa548f3fc              # cld; rep movsq
1735
1736         mov     -8(%rax),%rbx
1737         mov     -16(%rax),%rbp
1738         mov     -24(%rax),%r12
1739         mov     -32(%rax),%r13
1740         mov     -40(%rax),%r14
1741         mov     %rbx,144($context)      # restore context->Rbx
1742         mov     %rbp,160($context)      # restore context->Rbp
1743         mov     %r12,216($context)      # restore cotnext->R12
1744         mov     %r13,224($context)      # restore cotnext->R13
1745         mov     %r14,232($context)      # restore cotnext->R14
1746
1747 .Lcommon_seh_tail:
1748         mov     8(%rax),%rdi
1749         mov     16(%rax),%rsi
1750         mov     %rax,152($context)      # restore context->Rsp
1751         mov     %rsi,168($context)      # restore context->Rsi
1752         mov     %rdi,176($context)      # restore context->Rdi
1753
1754         mov     40($disp),%rdi          # disp->ContextRecord
1755         mov     $context,%rsi           # context
1756         mov     \$154,%ecx              # sizeof(CONTEXT)
1757         .long   0xa548f3fc              # cld; rep movsq
1758
1759         mov     $disp,%rsi
1760         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
1761         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
1762         mov     0(%rsi),%r8             # arg3, disp->ControlPc
1763         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
1764         mov     40(%rsi),%r10           # disp->ContextRecord
1765         lea     56(%rsi),%r11           # &disp->HandlerData
1766         lea     24(%rsi),%r12           # &disp->EstablisherFrame
1767         mov     %r10,32(%rsp)           # arg5
1768         mov     %r11,40(%rsp)           # arg6
1769         mov     %r12,48(%rsp)           # arg7
1770         mov     %rcx,56(%rsp)           # arg8, (NULL)
1771         call    *__imp_RtlVirtualUnwind(%rip)
1772
1773         mov     \$1,%eax                # ExceptionContinueSearch
1774         add     \$64,%rsp
1775         popfq
1776         pop     %r15
1777         pop     %r14
1778         pop     %r13
1779         pop     %r12
1780         pop     %rbp
1781         pop     %rbx
1782         pop     %rdi
1783         pop     %rsi
1784         ret
1785 .size   ssse3_handler,.-ssse3_handler
1786
1787 .section        .pdata
1788 .align  4
1789         .rva    .LSEH_begin_sha1_block_data_order
1790         .rva    .LSEH_end_sha1_block_data_order
1791         .rva    .LSEH_info_sha1_block_data_order
1792         .rva    .LSEH_begin_sha1_block_data_order_ssse3
1793         .rva    .LSEH_end_sha1_block_data_order_ssse3
1794         .rva    .LSEH_info_sha1_block_data_order_ssse3
1795 ___
1796 $code.=<<___ if ($avx);
1797         .rva    .LSEH_begin_sha1_block_data_order_avx
1798         .rva    .LSEH_end_sha1_block_data_order_avx
1799         .rva    .LSEH_info_sha1_block_data_order_avx
1800 ___
1801 $code.=<<___ if ($avx>1);
1802         .rva    .LSEH_begin_sha1_block_data_order_avx2
1803         .rva    .LSEH_end_sha1_block_data_order_avx2
1804         .rva    .LSEH_info_sha1_block_data_order_avx2
1805 ___
1806 $code.=<<___;
1807 .section        .xdata
1808 .align  8
1809 .LSEH_info_sha1_block_data_order:
1810         .byte   9,0,0,0
1811         .rva    se_handler
1812 .LSEH_info_sha1_block_data_order_ssse3:
1813         .byte   9,0,0,0
1814         .rva    ssse3_handler
1815         .rva    .Lprologue_ssse3,.Lepilogue_ssse3       # HandlerData[]
1816 ___
1817 $code.=<<___ if ($avx);
1818 .LSEH_info_sha1_block_data_order_avx:
1819         .byte   9,0,0,0
1820         .rva    ssse3_handler
1821         .rva    .Lprologue_avx,.Lepilogue_avx           # HandlerData[]
1822 ___
1823 $code.=<<___ if ($avx>1);
1824 .LSEH_info_sha1_block_data_order_avx2:
1825         .byte   9,0,0,0
1826         .rva    ssse3_handler
1827         .rva    .Lprologue_avx2,.Lepilogue_avx2         # HandlerData[]
1828 ___
1829 }
1830
1831 ####################################################################
1832
1833 $code =~ s/\`([^\`]*)\`/eval $1/gem;
1834 print $code;
1835 close STDOUT;