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