Added Appro's SSSE3 SHA implementations
[gnutls:gnutls.git] / devel / perlasm / sha1-ssse3-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         push    %rbx
348         push    %rbp
349         push    %r12
350         lea     `-64-($win64?6*16:0)`(%rsp),%rsp
351 ___
352 $code.=<<___ if ($win64);
353         movaps  %xmm6,64+0(%rsp)
354         movaps  %xmm7,64+16(%rsp)
355         movaps  %xmm8,64+32(%rsp)
356         movaps  %xmm9,64+48(%rsp)
357         movaps  %xmm10,64+64(%rsp)
358         movaps  %xmm11,64+80(%rsp)
359 .Lprologue_ssse3:
360 ___
361 $code.=<<___;
362         mov     %rdi,$ctx       # reassigned argument
363         mov     %rsi,$inp       # reassigned argument
364         mov     %rdx,$num       # reassigned argument
365
366         shl     \$6,$num
367         add     $inp,$num
368         lea     K_XX_XX+64(%rip),$K_XX_XX
369
370         mov     0($ctx),$A              # load context
371         mov     4($ctx),$B
372         mov     8($ctx),$C
373         mov     12($ctx),$D
374         mov     $B,@T[0]                # magic seed
375         mov     16($ctx),$E
376         mov     $C,@T[1]
377         xor     $D,@T[1]
378         and     @T[1],@T[0]
379
380         movdqa  64($K_XX_XX),@X[2]      # pbswap mask
381         movdqa  -64($K_XX_XX),@Tx[1]    # K_00_19
382         movdqu  0($inp),@X[-4&7]        # load input to %xmm[0-3]
383         movdqu  16($inp),@X[-3&7]
384         movdqu  32($inp),@X[-2&7]
385         movdqu  48($inp),@X[-1&7]
386         pshufb  @X[2],@X[-4&7]          # byte swap
387         add     \$64,$inp
388         pshufb  @X[2],@X[-3&7]
389         pshufb  @X[2],@X[-2&7]
390         pshufb  @X[2],@X[-1&7]
391         paddd   @Tx[1],@X[-4&7]         # add K_00_19
392         paddd   @Tx[1],@X[-3&7]
393         paddd   @Tx[1],@X[-2&7]
394         movdqa  @X[-4&7],0(%rsp)        # X[]+K xfer to IALU
395         psubd   @Tx[1],@X[-4&7]         # restore X[]
396         movdqa  @X[-3&7],16(%rsp)
397         psubd   @Tx[1],@X[-3&7]
398         movdqa  @X[-2&7],32(%rsp)
399         psubd   @Tx[1],@X[-2&7]
400         jmp     .Loop_ssse3
401 ___
402
403 sub AUTOLOAD()          # thunk [simplified] 32-bit style perlasm
404 { my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
405   my $arg = pop;
406     $arg = "\$$arg" if ($arg*1 eq $arg);
407     $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
408 }
409
410 sub Xupdate_ssse3_16_31()               # recall that $Xi starts wtih 4
411 { use integer;
412   my $body = shift;
413   my @insns = (&$body,&$body,&$body,&$body);    # 40 instructions
414   my ($a,$b,$c,$d,$e);
415
416         &movdqa (@X[0],@X[-3&7]);
417          eval(shift(@insns));
418          eval(shift(@insns));
419         &movdqa (@Tx[0],@X[-1&7]);
420         &palignr(@X[0],@X[-4&7],8);     # compose "X[-14]" in "X[0]"
421          eval(shift(@insns));
422          eval(shift(@insns));
423
424           &paddd        (@Tx[1],@X[-1&7]);
425          eval(shift(@insns));
426          eval(shift(@insns));
427         &psrldq (@Tx[0],4);             # "X[-3]", 3 dwords
428          eval(shift(@insns));
429          eval(shift(@insns));
430         &pxor   (@X[0],@X[-4&7]);       # "X[0]"^="X[-16]"
431          eval(shift(@insns));
432          eval(shift(@insns));
433
434         &pxor   (@Tx[0],@X[-2&7]);      # "X[-3]"^"X[-8]"
435          eval(shift(@insns));
436          eval(shift(@insns));
437          eval(shift(@insns));
438          eval(shift(@insns));
439
440         &pxor   (@X[0],@Tx[0]);         # "X[0]"^="X[-3]"^"X[-8]"
441          eval(shift(@insns));
442          eval(shift(@insns));
443           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
444          eval(shift(@insns));
445          eval(shift(@insns));
446
447         &movdqa (@Tx[2],@X[0]);
448         &movdqa (@Tx[0],@X[0]);
449          eval(shift(@insns));
450          eval(shift(@insns));
451          eval(shift(@insns));
452          eval(shift(@insns));
453
454         &pslldq (@Tx[2],12);            # "X[0]"<<96, extract one dword
455         &paddd  (@X[0],@X[0]);
456          eval(shift(@insns));
457          eval(shift(@insns));
458          eval(shift(@insns));
459          eval(shift(@insns));
460
461         &psrld  (@Tx[0],31);
462          eval(shift(@insns));
463          eval(shift(@insns));
464         &movdqa (@Tx[1],@Tx[2]);
465          eval(shift(@insns));
466          eval(shift(@insns));
467
468         &psrld  (@Tx[2],30);
469         &por    (@X[0],@Tx[0]);         # "X[0]"<<<=1
470          eval(shift(@insns));
471          eval(shift(@insns));
472          eval(shift(@insns));
473          eval(shift(@insns));
474
475         &pslld  (@Tx[1],2);
476         &pxor   (@X[0],@Tx[2]);
477          eval(shift(@insns));
478          eval(shift(@insns));
479           &movdqa       (@Tx[2],eval(2*16*(($Xi)/5)-64)."($K_XX_XX)");  # K_XX_XX
480          eval(shift(@insns));
481          eval(shift(@insns));
482
483         &pxor   (@X[0],@Tx[1]);         # "X[0]"^=("X[0]">>96)<<<2
484
485          foreach (@insns) { eval; }     # remaining instructions [if any]
486
487   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
488                 push(@Tx,shift(@Tx));
489 }
490
491 sub Xupdate_ssse3_32_79()
492 { use integer;
493   my $body = shift;
494   my @insns = (&$body,&$body,&$body,&$body);    # 32 to 44 instructions
495   my ($a,$b,$c,$d,$e);
496
497         &movdqa (@Tx[0],@X[-1&7])       if ($Xi==8);
498          eval(shift(@insns));           # body_20_39
499         &pxor   (@X[0],@X[-4&7]);       # "X[0]"="X[-32]"^"X[-16]"
500         &palignr(@Tx[0],@X[-2&7],8);    # compose "X[-6]"
501          eval(shift(@insns));
502          eval(shift(@insns));
503          eval(shift(@insns));           # rol
504
505         &pxor   (@X[0],@X[-7&7]);       # "X[0]"^="X[-28]"
506          eval(shift(@insns));
507          eval(shift(@insns))    if (@insns[0] !~ /&ro[rl]/);
508         if ($Xi%5) {
509           &movdqa       (@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX...
510         } else {                        # ... or load next one
511           &movdqa       (@Tx[2],eval(2*16*($Xi/5)-64)."($K_XX_XX)");
512         }
513           &paddd        (@Tx[1],@X[-1&7]);
514          eval(shift(@insns));           # ror
515          eval(shift(@insns));
516
517         &pxor   (@X[0],@Tx[0]);         # "X[0]"^="X[-6]"
518          eval(shift(@insns));           # body_20_39
519          eval(shift(@insns));
520          eval(shift(@insns));
521          eval(shift(@insns));           # rol
522
523         &movdqa (@Tx[0],@X[0]);
524           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
525          eval(shift(@insns));
526          eval(shift(@insns));
527          eval(shift(@insns));           # ror
528          eval(shift(@insns));
529
530         &pslld  (@X[0],2);
531          eval(shift(@insns));           # body_20_39
532          eval(shift(@insns));
533         &psrld  (@Tx[0],30);
534          eval(shift(@insns));
535          eval(shift(@insns));           # rol
536          eval(shift(@insns));
537          eval(shift(@insns));
538          eval(shift(@insns));           # ror
539          eval(shift(@insns));
540
541         &por    (@X[0],@Tx[0]);         # "X[0]"<<<=2
542          eval(shift(@insns));           # body_20_39
543          eval(shift(@insns));
544           &movdqa       (@Tx[1],@X[0])  if ($Xi<19);
545          eval(shift(@insns));
546          eval(shift(@insns));           # rol
547          eval(shift(@insns));
548          eval(shift(@insns));
549          eval(shift(@insns));           # rol
550          eval(shift(@insns));
551
552          foreach (@insns) { eval; }     # remaining instructions
553
554   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
555                 push(@Tx,shift(@Tx));
556 }
557
558 sub Xuplast_ssse3_80()
559 { use integer;
560   my $body = shift;
561   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
562   my ($a,$b,$c,$d,$e);
563
564          eval(shift(@insns));
565           &paddd        (@Tx[1],@X[-1&7]);
566          eval(shift(@insns));
567          eval(shift(@insns));
568          eval(shift(@insns));
569          eval(shift(@insns));
570
571           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
572
573          foreach (@insns) { eval; }             # remaining instructions
574
575         &cmp    ($inp,$num);
576         &je     (".Ldone_ssse3");
577
578         unshift(@Tx,pop(@Tx));
579
580         &movdqa (@X[2],"64($K_XX_XX)");         # pbswap mask
581         &movdqa (@Tx[1],"-64($K_XX_XX)");       # K_00_19
582         &movdqu (@X[-4&7],"0($inp)");           # load input
583         &movdqu (@X[-3&7],"16($inp)");
584         &movdqu (@X[-2&7],"32($inp)");
585         &movdqu (@X[-1&7],"48($inp)");
586         &pshufb (@X[-4&7],@X[2]);               # byte swap
587         &add    ($inp,64);
588
589   $Xi=0;
590 }
591
592 sub Xloop_ssse3()
593 { use integer;
594   my $body = shift;
595   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
596   my ($a,$b,$c,$d,$e);
597
598          eval(shift(@insns));
599          eval(shift(@insns));
600         &pshufb (@X[($Xi-3)&7],@X[2]);
601          eval(shift(@insns));
602          eval(shift(@insns));
603          eval(shift(@insns));
604         &paddd  (@X[($Xi-4)&7],@Tx[1]);
605          eval(shift(@insns));
606          eval(shift(@insns));
607          eval(shift(@insns));
608          eval(shift(@insns));
609         &movdqa (eval(16*$Xi)."(%rsp)",@X[($Xi-4)&7]);  # X[]+K xfer to IALU
610          eval(shift(@insns));
611          eval(shift(@insns));
612         &psubd  (@X[($Xi-4)&7],@Tx[1]);
613
614         foreach (@insns) { eval; }
615   $Xi++;
616 }
617
618 sub Xtail_ssse3()
619 { use integer;
620   my $body = shift;
621   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
622   my ($a,$b,$c,$d,$e);
623
624         foreach (@insns) { eval; }
625 }
626
627 sub body_00_19 () {     # ((c^d)&b)^d
628         # on start @T[0]=(c^d)&b
629         return &body_20_39() if ($rx==19); $rx++;
630         (
631         '($a,$b,$c,$d,$e)=@V;'.
632         '&$_ror ($b,$j?7:2)',   # $b>>>2
633         '&xor   (@T[0],$d)',
634         '&mov   (@T[1],$a)',    # $b for next round
635
636         '&add   ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer
637         '&xor   ($b,$c)',       # $c^$d for next round
638
639         '&$_rol ($a,5)',
640         '&add   ($e,@T[0])',
641         '&and   (@T[1],$b)',    # ($b&($c^$d)) for next round
642
643         '&xor   ($b,$c)',       # restore $b
644         '&add   ($e,$a);'       .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
645         );
646 }
647
648 sub body_20_39 () {     # b^d^c
649         # on entry @T[0]=b^d
650         return &body_40_59() if ($rx==39); $rx++;
651         (
652         '($a,$b,$c,$d,$e)=@V;'.
653         '&add   ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer
654         '&xor   (@T[0],$d)      if($j==19);'.
655         '&xor   (@T[0],$c)      if($j> 19)',    # ($b^$d^$c)
656         '&mov   (@T[1],$a)',    # $b for next round
657
658         '&$_rol ($a,5)',
659         '&add   ($e,@T[0])',
660         '&xor   (@T[1],$c)      if ($j< 79)',   # $b^$d for next round
661
662         '&$_ror ($b,7)',        # $b>>>2
663         '&add   ($e,$a);'       .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
664         );
665 }
666
667 sub body_40_59 () {     # ((b^c)&(c^d))^c
668         # on entry @T[0]=(b^c), (c^=d)
669         $rx++;
670         (
671         '($a,$b,$c,$d,$e)=@V;'.
672         '&add   ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer
673         '&and   (@T[0],$c)      if ($j>=40)',   # (b^c)&(c^d)
674         '&xor   ($c,$d)         if ($j>=40)',   # restore $c
675
676         '&$_ror ($b,7)',        # $b>>>2
677         '&mov   (@T[1],$a)',    # $b for next round
678         '&xor   (@T[0],$c)',
679
680         '&$_rol ($a,5)',
681         '&add   ($e,@T[0])',
682         '&xor   (@T[1],$c)      if ($j==59);'.
683         '&xor   (@T[1],$b)      if ($j< 59)',   # b^c for next round
684
685         '&xor   ($b,$c)         if ($j< 59)',   # c^d for next round
686         '&add   ($e,$a);'       .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
687         );
688 }
689 $code.=<<___;
690 .align  16
691 .Loop_ssse3:
692 ___
693         &Xupdate_ssse3_16_31(\&body_00_19);
694         &Xupdate_ssse3_16_31(\&body_00_19);
695         &Xupdate_ssse3_16_31(\&body_00_19);
696         &Xupdate_ssse3_16_31(\&body_00_19);
697         &Xupdate_ssse3_32_79(\&body_00_19);
698         &Xupdate_ssse3_32_79(\&body_20_39);
699         &Xupdate_ssse3_32_79(\&body_20_39);
700         &Xupdate_ssse3_32_79(\&body_20_39);
701         &Xupdate_ssse3_32_79(\&body_20_39);
702         &Xupdate_ssse3_32_79(\&body_20_39);
703         &Xupdate_ssse3_32_79(\&body_40_59);
704         &Xupdate_ssse3_32_79(\&body_40_59);
705         &Xupdate_ssse3_32_79(\&body_40_59);
706         &Xupdate_ssse3_32_79(\&body_40_59);
707         &Xupdate_ssse3_32_79(\&body_40_59);
708         &Xupdate_ssse3_32_79(\&body_20_39);
709         &Xuplast_ssse3_80(\&body_20_39);        # can jump to "done"
710
711                                 $saved_j=$j; @saved_V=@V;
712
713         &Xloop_ssse3(\&body_20_39);
714         &Xloop_ssse3(\&body_20_39);
715         &Xloop_ssse3(\&body_20_39);
716
717 $code.=<<___;
718         add     0($ctx),$A                      # update context
719         add     4($ctx),@T[0]
720         add     8($ctx),$C
721         add     12($ctx),$D
722         mov     $A,0($ctx)
723         add     16($ctx),$E
724         mov     @T[0],4($ctx)
725         mov     @T[0],$B                        # magic seed
726         mov     $C,8($ctx)
727         mov     $C,@T[1]
728         mov     $D,12($ctx)
729         xor     $D,@T[1]
730         mov     $E,16($ctx)
731         and     @T[1],@T[0]
732         jmp     .Loop_ssse3
733
734 .align  16
735 .Ldone_ssse3:
736 ___
737                                 $j=$saved_j; @V=@saved_V;
738
739         &Xtail_ssse3(\&body_20_39);
740         &Xtail_ssse3(\&body_20_39);
741         &Xtail_ssse3(\&body_20_39);
742
743 $code.=<<___;
744         add     0($ctx),$A                      # update context
745         add     4($ctx),@T[0]
746         add     8($ctx),$C
747         mov     $A,0($ctx)
748         add     12($ctx),$D
749         mov     @T[0],4($ctx)
750         add     16($ctx),$E
751         mov     $C,8($ctx)
752         mov     $D,12($ctx)
753         mov     $E,16($ctx)
754 ___
755 $code.=<<___ if ($win64);
756         movaps  64+0(%rsp),%xmm6
757         movaps  64+16(%rsp),%xmm7
758         movaps  64+32(%rsp),%xmm8
759         movaps  64+48(%rsp),%xmm9
760         movaps  64+64(%rsp),%xmm10
761         movaps  64+80(%rsp),%xmm11
762 ___
763 $code.=<<___;
764         lea     `64+($win64?6*16:0)`(%rsp),%rsi
765         mov     0(%rsi),%r12
766         mov     8(%rsi),%rbp
767         mov     16(%rsi),%rbx
768         lea     24(%rsi),%rsp
769 .Lepilogue_ssse3:
770         ret
771 .size   sha1_block_data_order_ssse3,.-sha1_block_data_order_ssse3
772 ___
773
774 if ($avx) {
775 $Xi=4;                          # reset variables
776 @X=map("%xmm$_",(4..7,0..3));
777 @Tx=map("%xmm$_",(8..10));
778 $j=0;
779 $rx=0;
780
781 my $done_avx_label=".Ldone_avx";
782
783 my $_rol=sub { &shld(@_[0],@_) };
784 my $_ror=sub { &shrd(@_[0],@_) };
785
786 $code.=<<___;
787 .type   sha1_block_data_order_avx,\@function,3
788 .align  16
789 sha1_block_data_order_avx:
790 _avx_shortcut:
791         push    %rbx
792         push    %rbp
793         push    %r12
794         lea     `-64-($win64?6*16:0)`(%rsp),%rsp
795 ___
796 $code.=<<___ if ($win64);
797         movaps  %xmm6,64+0(%rsp)
798         movaps  %xmm7,64+16(%rsp)
799         movaps  %xmm8,64+32(%rsp)
800         movaps  %xmm9,64+48(%rsp)
801         movaps  %xmm10,64+64(%rsp)
802         movaps  %xmm11,64+80(%rsp)
803 .Lprologue_avx:
804 ___
805 $code.=<<___;
806         mov     %rdi,$ctx       # reassigned argument
807         mov     %rsi,$inp       # reassigned argument
808         mov     %rdx,$num       # reassigned argument
809         vzeroupper
810
811         shl     \$6,$num
812         add     $inp,$num
813         lea     K_XX_XX+64(%rip),$K_XX_XX
814
815         mov     0($ctx),$A              # load context
816         mov     4($ctx),$B
817         mov     8($ctx),$C
818         mov     12($ctx),$D
819         mov     $B,@T[0]                # magic seed
820         mov     16($ctx),$E
821         mov     $C,@T[1]
822         xor     $D,@T[1]
823         and     @T[1],@T[0]
824
825         vmovdqa 64($K_XX_XX),@X[2]      # pbswap mask
826         vmovdqa -64($K_XX_XX),$Kx       # K_00_19
827         vmovdqu 0($inp),@X[-4&7]        # load input to %xmm[0-3]
828         vmovdqu 16($inp),@X[-3&7]
829         vmovdqu 32($inp),@X[-2&7]
830         vmovdqu 48($inp),@X[-1&7]
831         vpshufb @X[2],@X[-4&7],@X[-4&7] # byte swap
832         add     \$64,$inp
833         vpshufb @X[2],@X[-3&7],@X[-3&7]
834         vpshufb @X[2],@X[-2&7],@X[-2&7]
835         vpshufb @X[2],@X[-1&7],@X[-1&7]
836         vpaddd  $Kx,@X[-4&7],@X[0]      # add K_00_19
837         vpaddd  $Kx,@X[-3&7],@X[1]
838         vpaddd  $Kx,@X[-2&7],@X[2]
839         vmovdqa @X[0],0(%rsp)           # X[]+K xfer to IALU
840         vmovdqa @X[1],16(%rsp)
841         vmovdqa @X[2],32(%rsp)
842         jmp     .Loop_avx
843 ___
844
845 sub Xupdate_avx_16_31()         # recall that $Xi starts wtih 4
846 { use integer;
847   my $body = shift;
848   my @insns = (&$body,&$body,&$body,&$body);    # 40 instructions
849   my ($a,$b,$c,$d,$e);
850
851          eval(shift(@insns));
852          eval(shift(@insns));
853         &vpalignr(@X[0],@X[-3&7],@X[-4&7],8);   # compose "X[-14]" in "X[0]"
854          eval(shift(@insns));
855          eval(shift(@insns));
856
857           &vpaddd       (@Tx[1],$Kx,@X[-1&7]);
858          eval(shift(@insns));
859          eval(shift(@insns));
860         &vpsrldq(@Tx[0],@X[-1&7],4);            # "X[-3]", 3 dwords
861          eval(shift(@insns));
862          eval(shift(@insns));
863         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"^="X[-16]"
864          eval(shift(@insns));
865          eval(shift(@insns));
866
867         &vpxor  (@Tx[0],@Tx[0],@X[-2&7]);       # "X[-3]"^"X[-8]"
868          eval(shift(@insns));
869          eval(shift(@insns));
870          eval(shift(@insns));
871          eval(shift(@insns));
872
873         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-3]"^"X[-8]"
874          eval(shift(@insns));
875          eval(shift(@insns));
876           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
877          eval(shift(@insns));
878          eval(shift(@insns));
879
880         &vpsrld (@Tx[0],@X[0],31);
881          eval(shift(@insns));
882          eval(shift(@insns));
883          eval(shift(@insns));
884          eval(shift(@insns));
885
886         &vpslldq(@Tx[2],@X[0],12);              # "X[0]"<<96, extract one dword
887         &vpaddd (@X[0],@X[0],@X[0]);
888          eval(shift(@insns));
889          eval(shift(@insns));
890          eval(shift(@insns));
891          eval(shift(@insns));
892
893         &vpsrld (@Tx[1],@Tx[2],30);
894         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=1
895          eval(shift(@insns));
896          eval(shift(@insns));
897          eval(shift(@insns));
898          eval(shift(@insns));
899
900         &vpslld (@Tx[2],@Tx[2],2);
901         &vpxor  (@X[0],@X[0],@Tx[1]);
902          eval(shift(@insns));
903          eval(shift(@insns));
904          eval(shift(@insns));
905          eval(shift(@insns));
906
907         &vpxor  (@X[0],@X[0],@Tx[2]);           # "X[0]"^=("X[0]">>96)<<<2
908          eval(shift(@insns));
909          eval(shift(@insns));
910           &vmovdqa      ($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)")      if ($Xi%5==0);  # K_XX_XX
911          eval(shift(@insns));
912          eval(shift(@insns));
913
914
915          foreach (@insns) { eval; }     # remaining instructions [if any]
916
917   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
918 }
919
920 sub Xupdate_avx_32_79()
921 { use integer;
922   my $body = shift;
923   my @insns = (&$body,&$body,&$body,&$body);    # 32 to 44 instructions
924   my ($a,$b,$c,$d,$e);
925
926         &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8);  # compose "X[-6]"
927         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"="X[-32]"^"X[-16]"
928          eval(shift(@insns));           # body_20_39
929          eval(shift(@insns));
930          eval(shift(@insns));
931          eval(shift(@insns));           # rol
932
933         &vpxor  (@X[0],@X[0],@X[-7&7]);         # "X[0]"^="X[-28]"
934          eval(shift(@insns));
935          eval(shift(@insns))    if (@insns[0] !~ /&ro[rl]/);
936           &vpaddd       (@Tx[1],$Kx,@X[-1&7]);
937           &vmovdqa      ($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)")        if ($Xi%5==0);
938          eval(shift(@insns));           # ror
939          eval(shift(@insns));
940
941         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-6]"
942          eval(shift(@insns));           # body_20_39
943          eval(shift(@insns));
944          eval(shift(@insns));
945          eval(shift(@insns));           # rol
946
947         &vpsrld (@Tx[0],@X[0],30);
948           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
949          eval(shift(@insns));
950          eval(shift(@insns));
951          eval(shift(@insns));           # ror
952          eval(shift(@insns));
953
954         &vpslld (@X[0],@X[0],2);
955          eval(shift(@insns));           # body_20_39
956          eval(shift(@insns));
957          eval(shift(@insns));
958          eval(shift(@insns));           # rol
959          eval(shift(@insns));
960          eval(shift(@insns));
961          eval(shift(@insns));           # ror
962          eval(shift(@insns));
963
964         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=2
965          eval(shift(@insns));           # body_20_39
966          eval(shift(@insns));
967          eval(shift(@insns));
968          eval(shift(@insns));           # rol
969          eval(shift(@insns));
970          eval(shift(@insns));
971          eval(shift(@insns));           # rol
972          eval(shift(@insns));
973
974          foreach (@insns) { eval; }     # remaining instructions
975
976   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
977 }
978
979 sub Xuplast_avx_80()
980 { use integer;
981   my $body = shift;
982   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
983   my ($a,$b,$c,$d,$e);
984
985          eval(shift(@insns));
986           &vpaddd       (@Tx[1],$Kx,@X[-1&7]);
987          eval(shift(@insns));
988          eval(shift(@insns));
989          eval(shift(@insns));
990          eval(shift(@insns));
991
992           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
993
994          foreach (@insns) { eval; }             # remaining instructions
995
996         &cmp    ($inp,$num);
997         &je     ($done_avx_label);
998
999         &vmovdqa(@X[2],"64($K_XX_XX)");         # pbswap mask
1000         &vmovdqa($Kx,"-64($K_XX_XX)");          # K_00_19
1001         &vmovdqu(@X[-4&7],"0($inp)");           # load input
1002         &vmovdqu(@X[-3&7],"16($inp)");
1003         &vmovdqu(@X[-2&7],"32($inp)");
1004         &vmovdqu(@X[-1&7],"48($inp)");
1005         &vpshufb(@X[-4&7],@X[-4&7],@X[2]);      # byte swap
1006         &add    ($inp,64);
1007
1008   $Xi=0;
1009 }
1010
1011 sub Xloop_avx()
1012 { use integer;
1013   my $body = shift;
1014   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
1015   my ($a,$b,$c,$d,$e);
1016
1017          eval(shift(@insns));
1018          eval(shift(@insns));
1019         &vpshufb(@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]);
1020          eval(shift(@insns));
1021          eval(shift(@insns));
1022         &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],$Kx);
1023          eval(shift(@insns));
1024          eval(shift(@insns));
1025          eval(shift(@insns));
1026          eval(shift(@insns));
1027         &vmovdqa(eval(16*$Xi)."(%rsp)",@X[$Xi&7]);      # X[]+K xfer to IALU
1028          eval(shift(@insns));
1029          eval(shift(@insns));
1030
1031         foreach (@insns) { eval; }
1032   $Xi++;
1033 }
1034
1035 sub Xtail_avx()
1036 { use integer;
1037   my $body = shift;
1038   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
1039   my ($a,$b,$c,$d,$e);
1040
1041         foreach (@insns) { eval; }
1042 }
1043
1044 $code.=<<___;
1045 .align  16
1046 .Loop_avx:
1047 ___
1048         &Xupdate_avx_16_31(\&body_00_19);
1049         &Xupdate_avx_16_31(\&body_00_19);
1050         &Xupdate_avx_16_31(\&body_00_19);
1051         &Xupdate_avx_16_31(\&body_00_19);
1052         &Xupdate_avx_32_79(\&body_00_19);
1053         &Xupdate_avx_32_79(\&body_20_39);
1054         &Xupdate_avx_32_79(\&body_20_39);
1055         &Xupdate_avx_32_79(\&body_20_39);
1056         &Xupdate_avx_32_79(\&body_20_39);
1057         &Xupdate_avx_32_79(\&body_20_39);
1058         &Xupdate_avx_32_79(\&body_40_59);
1059         &Xupdate_avx_32_79(\&body_40_59);
1060         &Xupdate_avx_32_79(\&body_40_59);
1061         &Xupdate_avx_32_79(\&body_40_59);
1062         &Xupdate_avx_32_79(\&body_40_59);
1063         &Xupdate_avx_32_79(\&body_20_39);
1064         &Xuplast_avx_80(\&body_20_39);  # can jump to "done"
1065
1066                                 $saved_j=$j; @saved_V=@V;
1067
1068         &Xloop_avx(\&body_20_39);
1069         &Xloop_avx(\&body_20_39);
1070         &Xloop_avx(\&body_20_39);
1071
1072 $code.=<<___;
1073         add     0($ctx),$A                      # update context
1074         add     4($ctx),@T[0]
1075         add     8($ctx),$C
1076         add     12($ctx),$D
1077         mov     $A,0($ctx)
1078         add     16($ctx),$E
1079         mov     @T[0],4($ctx)
1080         mov     @T[0],$B                        # magic seed
1081         mov     $C,8($ctx)
1082         mov     $C,@T[1]
1083         mov     $D,12($ctx)
1084         xor     $D,@T[1]
1085         mov     $E,16($ctx)
1086         and     @T[1],@T[0]
1087         jmp     .Loop_avx
1088
1089 .align  16
1090 $done_avx_label:
1091 ___
1092                                 $j=$saved_j; @V=@saved_V;
1093
1094         &Xtail_avx(\&body_20_39);
1095         &Xtail_avx(\&body_20_39);
1096         &Xtail_avx(\&body_20_39);
1097
1098 $code.=<<___;
1099         vzeroupper
1100
1101         add     0($ctx),$A                      # update context
1102         add     4($ctx),@T[0]
1103         add     8($ctx),$C
1104         mov     $A,0($ctx)
1105         add     12($ctx),$D
1106         mov     @T[0],4($ctx)
1107         add     16($ctx),$E
1108         mov     $C,8($ctx)
1109         mov     $D,12($ctx)
1110         mov     $E,16($ctx)
1111 ___
1112 $code.=<<___ if ($win64);
1113         movaps  64+0(%rsp),%xmm6
1114         movaps  64+16(%rsp),%xmm7
1115         movaps  64+32(%rsp),%xmm8
1116         movaps  64+48(%rsp),%xmm9
1117         movaps  64+64(%rsp),%xmm10
1118         movaps  64+80(%rsp),%xmm11
1119 ___
1120 $code.=<<___;
1121         lea     `64+($win64?6*16:0)`(%rsp),%rsi
1122         mov     0(%rsi),%r12
1123         mov     8(%rsi),%rbp
1124         mov     16(%rsi),%rbx
1125         lea     24(%rsi),%rsp
1126 .Lepilogue_avx:
1127         ret
1128 .size   sha1_block_data_order_avx,.-sha1_block_data_order_avx
1129 ___
1130
1131 if ($avx>1) {
1132 use integer;
1133 $Xi=4;                                  # reset variables
1134 @X=map("%ymm$_",(4..7,0..3));
1135 @Tx=map("%ymm$_",(8..10));
1136 $Kx="%ymm11";
1137 $j=0;
1138
1139 my @ROTX=("%eax","%ebp","%ebx","%ecx","%edx","%esi");
1140 my ($a5,$t0)=("%r12d","%edi");
1141
1142 my ($A,$F,$B,$C,$D,$E)=@ROTX;
1143 my $rx=0;
1144 my $frame="%r13";
1145
1146 $code.=<<___;
1147 .type   sha1_block_data_order_avx2,\@function,3
1148 .align  16
1149 sha1_block_data_order_avx2:
1150 _avx2_shortcut:
1151         push    %rbx
1152         push    %rbp
1153         push    %r12
1154         push    %r13
1155         push    %r14
1156         lea     (%rsp),%r14
1157 ___
1158 $code.=<<___ if ($win64);
1159         lea     -6*16(%rsp),%rsp
1160         movaps  %xmm6,-6*16(%r14)
1161         movaps  %xmm7,-5*16(%r14)
1162         movaps  %xmm8,-4*16(%r14)
1163         movaps  %xmm9,-3*16(%r14)
1164         movaps  %xmm10,-2*16(%r14)
1165         movaps  %xmm11,-1*16(%r14)
1166 .Lprologue_avx2:
1167 ___
1168 $code.=<<___;
1169         mov     %rdi,$ctx               # reassigned argument
1170         mov     %rsi,$inp               # reassigned argument
1171         mov     %rdx,$num               # reassigned argument
1172         vzeroupper
1173
1174         lea     -640(%rsp),%rsp
1175         shl     \$6,$num
1176          lea    64($inp),$frame
1177         and     \$-128,%rsp
1178         add     $inp,$num
1179         lea     K_XX_XX+64(%rip),$K_XX_XX
1180
1181         mov     0($ctx),$A              # load context
1182          cmp    $num,$frame
1183          cmovae $inp,$frame             # next or same block
1184         mov     4($ctx),$F
1185         mov     8($ctx),$C
1186         mov     12($ctx),$D
1187         mov     16($ctx),$E
1188         vmovdqu 64($K_XX_XX),@X[2]      # pbswap mask
1189
1190         vmovdqu         ($inp),%xmm0
1191         vmovdqu         16($inp),%xmm1
1192         vmovdqu         32($inp),%xmm2
1193         vmovdqu         48($inp),%xmm3
1194         lea             64($inp),$inp
1195         vinserti128     \$1,($frame),@X[-4&7],@X[-4&7]
1196         vinserti128     \$1,16($frame),@X[-3&7],@X[-3&7]
1197         vpshufb         @X[2],@X[-4&7],@X[-4&7]
1198         vinserti128     \$1,32($frame),@X[-2&7],@X[-2&7]
1199         vpshufb         @X[2],@X[-3&7],@X[-3&7]
1200         vinserti128     \$1,48($frame),@X[-1&7],@X[-1&7]
1201         vpshufb         @X[2],@X[-2&7],@X[-2&7]
1202         vmovdqu         -64($K_XX_XX),$Kx       # K_00_19
1203         vpshufb         @X[2],@X[-1&7],@X[-1&7]
1204
1205         vpaddd  $Kx,@X[-4&7],@X[0]      # add K_00_19
1206         vpaddd  $Kx,@X[-3&7],@X[1]
1207         vmovdqu @X[0],0(%rsp)           # X[]+K xfer to IALU
1208         vpaddd  $Kx,@X[-2&7],@X[2]
1209         vmovdqu @X[1],32(%rsp)
1210         vpaddd  $Kx,@X[-1&7],@X[3]
1211         vmovdqu @X[2],64(%rsp)
1212         vmovdqu @X[3],96(%rsp)
1213 ___
1214 for (;$Xi<8;$Xi++) {    # Xupdate_avx2_16_31
1215     use integer;
1216
1217         &vpalignr(@X[0],@X[-3&7],@X[-4&7],8);   # compose "X[-14]" in "X[0]"
1218         &vpsrldq(@Tx[0],@X[-1&7],4);            # "X[-3]", 3 dwords
1219         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"^="X[-16]"
1220         &vpxor  (@Tx[0],@Tx[0],@X[-2&7]);       # "X[-3]"^"X[-8]"
1221         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-3]"^"X[-8]"
1222         &vpsrld (@Tx[0],@X[0],31);
1223         &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)")      if ($Xi%5==0);  # K_XX_XX
1224         &vpslldq(@Tx[2],@X[0],12);              # "X[0]"<<96, extract one dword
1225         &vpaddd (@X[0],@X[0],@X[0]);
1226         &vpsrld (@Tx[1],@Tx[2],30);
1227         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=1
1228         &vpslld (@Tx[2],@Tx[2],2);
1229         &vpxor  (@X[0],@X[0],@Tx[1]);
1230         &vpxor  (@X[0],@X[0],@Tx[2]);           # "X[0]"^=("X[0]">>96)<<<2
1231         &vpaddd (@Tx[1],@X[0],$Kx);
1232         &vmovdqu("32*$Xi(%rsp)",@Tx[1]);        # X[]+K xfer to IALU
1233
1234         push(@X,shift(@X));     # "rotate" X[]
1235 }
1236 $code.=<<___;
1237         lea     128(%rsp),$frame
1238         jmp     .Loop_avx2
1239 .align  32
1240 .Loop_avx2:
1241         rorx    \$2,$F,$B
1242         andn    $D,$F,$t0
1243         and     $C,$F
1244         xor     $t0,$F
1245 ___
1246 sub bodyx_00_19 () {    # 8 instructions, 3 cycles critical path
1247         # at start $f=(b&c)^(~b&d), $b>>>=2
1248         return &bodyx_20_39() if ($rx==19); $rx++;
1249         (
1250         '($a,$f,$b,$c,$d,$e)=@ROTX;'.
1251
1252         '&add   ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'.       # e+=X[i]+K
1253          '&lea  ($frame,"256($frame)")  if ($j%32==31);',
1254         '&andn  ($t0,$a,$c)',                   # ~b&d for next round
1255
1256         '&add   ($e,$f)',                       # e+=(b&c)^(~b&d)
1257         '&rorx  ($a5,$a,27)',                   # a<<<5
1258         '&rorx  ($f,$a,2)',                     # b>>>2 for next round
1259         '&and   ($a,$b)',                       # b&c for next round
1260
1261         '&add   ($e,$a5)',                      # e+=a<<<5
1262         '&xor   ($a,$t0);'.                     # f=(b&c)^(~b&d) for next round
1263
1264         'unshift(@ROTX,pop(@ROTX)); $j++;'
1265         )
1266 }
1267
1268 sub bodyx_20_39 () {    # 7 instructions, 2 cycles critical path
1269         # on entry $f=b^c^d, $b>>>=2
1270         return &bodyx_40_59() if ($rx==39); $rx++;
1271         (
1272         '($a,$f,$b,$c,$d,$e)=@ROTX;'.
1273
1274         '&add   ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'.       # e+=X[i]+K
1275          '&lea  ($frame,"256($frame)")  if ($j%32==31);',
1276
1277         '&lea   ($e,"($e,$f)")',                # e+=b^c^d
1278         '&rorx  ($a5,$a,27)',                   # a<<<5
1279         '&rorx  ($f,$a,2)       if ($j<79)',    # b>>>2 in next round
1280         '&xor   ($a,$b)         if ($j<79)',    # b^c for next round
1281
1282         '&add   ($e,$a5)',                      # e+=a<<<5
1283         '&xor   ($a,$c)         if ($j<79);'.   # f=b^c^d for next round
1284
1285         'unshift(@ROTX,pop(@ROTX)); $j++;'
1286         )
1287 }
1288
1289 sub bodyx_40_59 () {    # 10 instructions, 3 cycles critical path
1290         # on entry $f=((b^c)&(c^d)), $b>>>=2
1291         $rx++;
1292         (
1293         '($a,$f,$b,$c,$d,$e)=@ROTX;'.
1294
1295         '&add   ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'.       # e+=X[i]+K
1296          '&lea  ($frame,"256($frame)")  if ($j%32==31);',
1297         '&xor   ($f,$c)         if ($j>39)',    # (b^c)&(c^d)^c
1298         '&mov   ($t0,$b)        if ($j<59)',    # count on zero latency
1299         '&xor   ($t0,$c)        if ($j<59)',    # c^d for next round
1300
1301         '&lea   ($e,"($e,$f)")',                # e+=(b^c)&(c^d)^c
1302         '&rorx  ($a5,$a,27)',                   # a<<<5
1303         '&rorx  ($f,$a,2)',                     # b>>>2 in next round
1304         '&xor   ($a,$b)',                       # b^c for next round
1305
1306         '&add   ($e,$a5)',                      # e+=a<<<5
1307         '&and   ($a,$t0)        if ($j< 59);'.  # f=(b^c)&(c^d) for next round
1308         '&xor   ($a,$c)         if ($j==59);'.  # f=b^c^d for next round
1309
1310         'unshift(@ROTX,pop(@ROTX)); $j++;'
1311         )
1312 }
1313
1314 sub Xupdate_avx2_16_31()                # recall that $Xi starts wtih 4
1315 { use integer;
1316   my $body = shift;
1317   my @insns = (&$body,&$body,&$body,&$body,&$body);     # 35 instructions
1318   my ($a,$b,$c,$d,$e);
1319
1320         &vpalignr(@X[0],@X[-3&7],@X[-4&7],8);   # compose "X[-14]" in "X[0]"
1321          eval(shift(@insns));
1322          eval(shift(@insns));
1323          eval(shift(@insns));
1324          eval(shift(@insns));
1325
1326         &vpsrldq(@Tx[0],@X[-1&7],4);            # "X[-3]", 3 dwords
1327          eval(shift(@insns));
1328          eval(shift(@insns));
1329          eval(shift(@insns));
1330
1331         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"^="X[-16]"
1332         &vpxor  (@Tx[0],@Tx[0],@X[-2&7]);       # "X[-3]"^"X[-8]"
1333          eval(shift(@insns));
1334          eval(shift(@insns));
1335
1336         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-3]"^"X[-8]"
1337          eval(shift(@insns));
1338          eval(shift(@insns));
1339          eval(shift(@insns));
1340          eval(shift(@insns));
1341
1342         &vpsrld (@Tx[0],@X[0],31);
1343         &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)")      if ($Xi%5==0);  # K_XX_XX
1344          eval(shift(@insns));
1345          eval(shift(@insns));
1346          eval(shift(@insns));
1347
1348         &vpslldq(@Tx[2],@X[0],12);              # "X[0]"<<96, extract one dword
1349         &vpaddd (@X[0],@X[0],@X[0]);
1350          eval(shift(@insns));
1351          eval(shift(@insns));
1352
1353         &vpsrld (@Tx[1],@Tx[2],30);
1354         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=1
1355          eval(shift(@insns));
1356          eval(shift(@insns));
1357
1358         &vpslld (@Tx[2],@Tx[2],2);
1359         &vpxor  (@X[0],@X[0],@Tx[1]);
1360          eval(shift(@insns));
1361          eval(shift(@insns));
1362
1363         &vpxor  (@X[0],@X[0],@Tx[2]);           # "X[0]"^=("X[0]">>96)<<<2
1364          eval(shift(@insns));
1365          eval(shift(@insns));
1366          eval(shift(@insns));
1367
1368         &vpaddd (@Tx[1],@X[0],$Kx);
1369          eval(shift(@insns));
1370          eval(shift(@insns));
1371          eval(shift(@insns));
1372         &vmovdqu(eval(32*($Xi))."(%rsp)",@Tx[1]);       # X[]+K xfer to IALU
1373
1374          foreach (@insns) { eval; }     # remaining instructions [if any]
1375
1376         $Xi++;
1377         push(@X,shift(@X));     # "rotate" X[]
1378 }
1379
1380 sub Xupdate_avx2_32_79()
1381 { use integer;
1382   my $body = shift;
1383   my @insns = (&$body,&$body,&$body,&$body,&$body);     # 35 to 50 instructions
1384   my ($a,$b,$c,$d,$e);
1385
1386         &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8);  # compose "X[-6]"
1387         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"="X[-32]"^"X[-16]"
1388          eval(shift(@insns));
1389          eval(shift(@insns));
1390
1391         &vpxor  (@X[0],@X[0],@X[-7&7]);         # "X[0]"^="X[-28]"
1392         &vmovdqu($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)")        if ($Xi%5==0);
1393          eval(shift(@insns));
1394          eval(shift(@insns));
1395          eval(shift(@insns));
1396
1397         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-6]"
1398          eval(shift(@insns));
1399          eval(shift(@insns));
1400          eval(shift(@insns));
1401
1402         &vpsrld (@Tx[0],@X[0],30);
1403         &vpslld (@X[0],@X[0],2);
1404          eval(shift(@insns));
1405          eval(shift(@insns));
1406          eval(shift(@insns));
1407
1408         #&vpslld        (@X[0],@X[0],2);
1409          eval(shift(@insns));
1410          eval(shift(@insns));
1411          eval(shift(@insns));
1412
1413         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=2
1414          eval(shift(@insns));
1415          eval(shift(@insns));
1416          eval(shift(@insns));
1417          eval(shift(@insns));
1418
1419         &vpaddd (@Tx[1],@X[0],$Kx);
1420          eval(shift(@insns));
1421          eval(shift(@insns));
1422          eval(shift(@insns));
1423          eval(shift(@insns));
1424
1425         &vmovdqu("32*$Xi(%rsp)",@Tx[1]);        # X[]+K xfer to IALU
1426
1427          foreach (@insns) { eval; }     # remaining instructions
1428
1429         $Xi++;
1430         push(@X,shift(@X));     # "rotate" X[]
1431 }
1432
1433 sub Xloop_avx2()
1434 { use integer;
1435   my $body = shift;
1436   my @insns = (&$body,&$body,&$body,&$body,&$body);     # 32 instructions
1437   my ($a,$b,$c,$d,$e);
1438
1439          foreach (@insns) { eval; }
1440 }
1441
1442         &align32();
1443         &Xupdate_avx2_32_79(\&bodyx_00_19);
1444         &Xupdate_avx2_32_79(\&bodyx_00_19);
1445         &Xupdate_avx2_32_79(\&bodyx_00_19);
1446         &Xupdate_avx2_32_79(\&bodyx_00_19);
1447
1448         &Xupdate_avx2_32_79(\&bodyx_20_39);
1449         &Xupdate_avx2_32_79(\&bodyx_20_39);
1450         &Xupdate_avx2_32_79(\&bodyx_20_39);
1451         &Xupdate_avx2_32_79(\&bodyx_20_39);
1452
1453         &align32();
1454         &Xupdate_avx2_32_79(\&bodyx_40_59);
1455         &Xupdate_avx2_32_79(\&bodyx_40_59);
1456         &Xupdate_avx2_32_79(\&bodyx_40_59);
1457         &Xupdate_avx2_32_79(\&bodyx_40_59);
1458
1459         &Xloop_avx2(\&bodyx_20_39);
1460         &Xloop_avx2(\&bodyx_20_39);
1461         &Xloop_avx2(\&bodyx_20_39);
1462         &Xloop_avx2(\&bodyx_20_39);
1463
1464 $code.=<<___;
1465         lea     128($inp),$frame
1466         lea     128($inp),%rdi                  # borrow $t0
1467         cmp     $num,$frame
1468         cmovae  $inp,$frame                     # next or previous block
1469
1470         # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c
1471         add     0($ctx),@ROTX[0]                # update context
1472         add     4($ctx),@ROTX[1]
1473         add     8($ctx),@ROTX[3]
1474         mov     @ROTX[0],0($ctx)
1475         add     12($ctx),@ROTX[4]
1476         mov     @ROTX[1],4($ctx)
1477          mov    @ROTX[0],$A                     # A=d
1478         add     16($ctx),@ROTX[5]
1479          mov    @ROTX[3],$a5
1480         mov     @ROTX[3],8($ctx)
1481          mov    @ROTX[4],$D                     # D=b
1482          #xchg  @ROTX[5],$F                     # F=c, C=f
1483         mov     @ROTX[4],12($ctx)
1484          mov    @ROTX[1],$F                     # F=e
1485         mov     @ROTX[5],16($ctx)
1486         #mov    $F,16($ctx)
1487          mov    @ROTX[5],$E                     # E=c
1488          mov    $a5,$C                          # C=f
1489          #xchg  $F,$E                           # E=c, F=e
1490
1491         cmp     $num,$inp
1492         je      .Ldone_avx2
1493 ___
1494
1495 $Xi=4;                          # reset variables
1496 @X=map("%ymm$_",(4..7,0..3));
1497
1498 $code.=<<___;
1499         vmovdqu 64($K_XX_XX),@X[2]              # pbswap mask
1500         cmp     $num,%rdi                       # borrowed $t0
1501         ja      .Last_avx2
1502
1503         vmovdqu         -64(%rdi),%xmm0         # low part of @X[-4&7]
1504         vmovdqu         -48(%rdi),%xmm1
1505         vmovdqu         -32(%rdi),%xmm2
1506         vmovdqu         -16(%rdi),%xmm3
1507         vinserti128     \$1,0($frame),@X[-4&7],@X[-4&7]
1508         vinserti128     \$1,16($frame),@X[-3&7],@X[-3&7]
1509         vinserti128     \$1,32($frame),@X[-2&7],@X[-2&7]
1510         vinserti128     \$1,48($frame),@X[-1&7],@X[-1&7]
1511         jmp     .Last_avx2
1512
1513 .align  32
1514 .Last_avx2:
1515         lea     128+16(%rsp),$frame
1516         rorx    \$2,$F,$B
1517         andn    $D,$F,$t0
1518         and     $C,$F
1519         xor     $t0,$F
1520         sub     \$-128,$inp
1521 ___
1522         $rx=$j=0;       @ROTX=($A,$F,$B,$C,$D,$E);
1523
1524         &Xloop_avx2     (\&bodyx_00_19);
1525         &Xloop_avx2     (\&bodyx_00_19);
1526         &Xloop_avx2     (\&bodyx_00_19);
1527         &Xloop_avx2     (\&bodyx_00_19);
1528
1529         &Xloop_avx2     (\&bodyx_20_39);
1530           &vmovdqu      ($Kx,"-64($K_XX_XX)");          # K_00_19
1531           &vpshufb      (@X[-4&7],@X[-4&7],@X[2]);      # byte swap
1532         &Xloop_avx2     (\&bodyx_20_39);
1533           &vpshufb      (@X[-3&7],@X[-3&7],@X[2]);
1534           &vpaddd       (@Tx[0],@X[-4&7],$Kx);          # add K_00_19
1535         &Xloop_avx2     (\&bodyx_20_39);
1536           &vmovdqu      ("0(%rsp)",@Tx[0]);
1537           &vpshufb      (@X[-2&7],@X[-2&7],@X[2]);
1538           &vpaddd       (@Tx[1],@X[-3&7],$Kx);
1539         &Xloop_avx2     (\&bodyx_20_39);
1540           &vmovdqu      ("32(%rsp)",@Tx[1]);
1541           &vpshufb      (@X[-1&7],@X[-1&7],@X[2]);
1542           &vpaddd       (@X[2],@X[-2&7],$Kx);
1543
1544         &Xloop_avx2     (\&bodyx_40_59);
1545         &align32        ();
1546           &vmovdqu      ("64(%rsp)",@X[2]);
1547           &vpaddd       (@X[3],@X[-1&7],$Kx);
1548         &Xloop_avx2     (\&bodyx_40_59);
1549           &vmovdqu      ("96(%rsp)",@X[3]);
1550         &Xloop_avx2     (\&bodyx_40_59);
1551         &Xupdate_avx2_16_31(\&bodyx_40_59);
1552
1553         &Xupdate_avx2_16_31(\&bodyx_20_39);
1554         &Xupdate_avx2_16_31(\&bodyx_20_39);
1555         &Xupdate_avx2_16_31(\&bodyx_20_39);
1556         &Xloop_avx2     (\&bodyx_20_39);
1557
1558 $code.=<<___;
1559         lea     128(%rsp),$frame
1560
1561         # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c
1562         add     0($ctx),@ROTX[0]                # update context
1563         add     4($ctx),@ROTX[1]
1564         add     8($ctx),@ROTX[3]
1565         mov     @ROTX[0],0($ctx)
1566         add     12($ctx),@ROTX[4]
1567         mov     @ROTX[1],4($ctx)
1568          mov    @ROTX[0],$A                     # A=d
1569         add     16($ctx),@ROTX[5]
1570          mov    @ROTX[3],$a5
1571         mov     @ROTX[3],8($ctx)
1572          mov    @ROTX[4],$D                     # D=b
1573          #xchg  @ROTX[5],$F                     # F=c, C=f
1574         mov     @ROTX[4],12($ctx)
1575          mov    @ROTX[1],$F                     # F=e
1576         mov     @ROTX[5],16($ctx)
1577         #mov    $F,16($ctx)
1578          mov    @ROTX[5],$E                     # E=c
1579          mov    $a5,$C                          # C=f
1580          #xchg  $F,$E                           # E=c, F=e
1581
1582         cmp     $num,$inp
1583         jbe     .Loop_avx2
1584
1585 .Ldone_avx2:
1586         vzeroupper
1587 ___
1588 $code.=<<___ if ($win64);
1589         movaps  -6*16(%r14),%xmm6
1590         movaps  -5*16(%r14),%xmm7
1591         movaps  -4*16(%r14),%xmm8
1592         movaps  -3*16(%r14),%xmm9
1593         movaps  -2*16(%r14),%xmm10
1594         movaps  -1*16(%r14),%xmm11
1595 ___
1596 $code.=<<___;
1597         lea     (%r14),%rsi
1598         mov     0(%rsi),%r14
1599         mov     8(%rsi),%r13
1600         mov     16(%rsi),%r12
1601         mov     24(%rsi),%rbp
1602         mov     32(%rsi),%rbx
1603         lea     40(%rsi),%rsp
1604 .Lepilogue_avx2:
1605         ret
1606 .size   sha1_block_data_order_avx2,.-sha1_block_data_order_avx2
1607 ___
1608 }
1609 }
1610 $code.=<<___;
1611 .align  64
1612 K_XX_XX:
1613 .long   0x5a827999,0x5a827999,0x5a827999,0x5a827999     # K_00_19
1614 .long   0x5a827999,0x5a827999,0x5a827999,0x5a827999     # K_00_19
1615 .long   0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1     # K_20_39
1616 .long   0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1     # K_20_39
1617 .long   0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc     # K_40_59
1618 .long   0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc     # K_40_59
1619 .long   0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6     # K_60_79
1620 .long   0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6     # K_60_79
1621 .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap mask
1622 .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap mask
1623 ___
1624 }}}
1625 $code.=<<___;
1626 .asciz  "SHA1 block transform for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
1627 .align  64
1628 ___
1629
1630 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1631 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
1632 if ($win64) {
1633 $rec="%rcx";
1634 $frame="%rdx";
1635 $context="%r8";
1636 $disp="%r9";
1637
1638 $code.=<<___;
1639 .extern __imp_RtlVirtualUnwind
1640 .type   se_handler,\@abi-omnipotent
1641 .align  16
1642 se_handler:
1643         push    %rsi
1644         push    %rdi
1645         push    %rbx
1646         push    %rbp
1647         push    %r12
1648         push    %r13
1649         push    %r14
1650         push    %r15
1651         pushfq
1652         sub     \$64,%rsp
1653
1654         mov     120($context),%rax      # pull context->Rax
1655         mov     248($context),%rbx      # pull context->Rip
1656
1657         lea     .Lprologue(%rip),%r10
1658         cmp     %r10,%rbx               # context->Rip<.Lprologue
1659         jb      .Lcommon_seh_tail
1660
1661         mov     152($context),%rax      # pull context->Rsp
1662
1663         lea     .Lepilogue(%rip),%r10
1664         cmp     %r10,%rbx               # context->Rip>=.Lepilogue
1665         jae     .Lcommon_seh_tail
1666
1667         mov     `16*4`(%rax),%rax       # pull saved stack pointer
1668         lea     32(%rax),%rax
1669
1670         mov     -8(%rax),%rbx
1671         mov     -16(%rax),%rbp
1672         mov     -24(%rax),%r12
1673         mov     -32(%rax),%r13
1674         mov     %rbx,144($context)      # restore context->Rbx
1675         mov     %rbp,160($context)      # restore context->Rbp
1676         mov     %r12,216($context)      # restore context->R12
1677         mov     %r13,224($context)      # restore context->R13
1678
1679         jmp     .Lcommon_seh_tail
1680 .size   se_handler,.-se_handler
1681
1682 .type   ssse3_handler,\@abi-omnipotent
1683 .align  16
1684 ssse3_handler:
1685         push    %rsi
1686         push    %rdi
1687         push    %rbx
1688         push    %rbp
1689         push    %r12
1690         push    %r13
1691         push    %r14
1692         push    %r15
1693         pushfq
1694         sub     \$64,%rsp
1695
1696         mov     120($context),%rax      # pull context->Rax
1697         mov     248($context),%rbx      # pull context->Rip
1698
1699         mov     8($disp),%rsi           # disp->ImageBase
1700         mov     56($disp),%r11          # disp->HandlerData
1701
1702         mov     0(%r11),%r10d           # HandlerData[0]
1703         lea     (%rsi,%r10),%r10        # prologue label
1704         cmp     %r10,%rbx               # context->Rip<prologue label
1705         jb      .Lcommon_seh_tail
1706
1707         mov     152($context),%rax      # pull context->Rsp
1708
1709         mov     4(%r11),%r10d           # HandlerData[1]
1710         lea     (%rsi,%r10),%r10        # epilogue label
1711         cmp     %r10,%rbx               # context->Rip>=epilogue label
1712         jae     .Lcommon_seh_tail
1713
1714         lea     64(%rax),%rsi
1715         lea     512($context),%rdi      # &context.Xmm6
1716         mov     \$12,%ecx
1717         .long   0xa548f3fc              # cld; rep movsq
1718         lea     `24+64+6*16`(%rax),%rax # adjust stack pointer
1719
1720         mov     -8(%rax),%rbx
1721         mov     -16(%rax),%rbp
1722         mov     -24(%rax),%r12
1723         mov     %rbx,144($context)      # restore context->Rbx
1724         mov     %rbp,160($context)      # restore context->Rbp
1725         mov     %r12,216($context)      # restore cotnext->R12
1726
1727 .Lcommon_seh_tail:
1728         mov     8(%rax),%rdi
1729         mov     16(%rax),%rsi
1730         mov     %rax,152($context)      # restore context->Rsp
1731         mov     %rsi,168($context)      # restore context->Rsi
1732         mov     %rdi,176($context)      # restore context->Rdi
1733
1734         mov     40($disp),%rdi          # disp->ContextRecord
1735         mov     $context,%rsi           # context
1736         mov     \$154,%ecx              # sizeof(CONTEXT)
1737         .long   0xa548f3fc              # cld; rep movsq
1738
1739         mov     $disp,%rsi
1740         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
1741         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
1742         mov     0(%rsi),%r8             # arg3, disp->ControlPc
1743         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
1744         mov     40(%rsi),%r10           # disp->ContextRecord
1745         lea     56(%rsi),%r11           # &disp->HandlerData
1746         lea     24(%rsi),%r12           # &disp->EstablisherFrame
1747         mov     %r10,32(%rsp)           # arg5
1748         mov     %r11,40(%rsp)           # arg6
1749         mov     %r12,48(%rsp)           # arg7
1750         mov     %rcx,56(%rsp)           # arg8, (NULL)
1751         call    *__imp_RtlVirtualUnwind(%rip)
1752
1753         mov     \$1,%eax                # ExceptionContinueSearch
1754         add     \$64,%rsp
1755         popfq
1756         pop     %r15
1757         pop     %r14
1758         pop     %r13
1759         pop     %r12
1760         pop     %rbp
1761         pop     %rbx
1762         pop     %rdi
1763         pop     %rsi
1764         ret
1765 .size   ssse3_handler,.-ssse3_handler
1766
1767 .section        .pdata
1768 .align  4
1769         .rva    .LSEH_begin_sha1_block_data_order
1770         .rva    .LSEH_end_sha1_block_data_order
1771         .rva    .LSEH_info_sha1_block_data_order
1772         .rva    .LSEH_begin_sha1_block_data_order_ssse3
1773         .rva    .LSEH_end_sha1_block_data_order_ssse3
1774         .rva    .LSEH_info_sha1_block_data_order_ssse3
1775 ___
1776 $code.=<<___ if ($avx);
1777         .rva    .LSEH_begin_sha1_block_data_order_avx
1778         .rva    .LSEH_end_sha1_block_data_order_avx
1779         .rva    .LSEH_info_sha1_block_data_order_avx
1780 ___
1781 $code.=<<___ if ($avx>1);
1782         .rva    .LSEH_begin_sha1_block_data_order_avx2
1783         .rva    .LSEH_end_sha1_block_data_order_avx2
1784         .rva    .LSEH_info_sha1_block_data_order_avx2
1785 ___
1786 $code.=<<___;
1787 .section        .xdata
1788 .align  8
1789 .LSEH_info_sha1_block_data_order:
1790         .byte   9,0,0,0
1791         .rva    se_handler
1792 .LSEH_info_sha1_block_data_order_ssse3:
1793         .byte   9,0,0,0
1794         .rva    ssse3_handler
1795         .rva    .Lprologue_ssse3,.Lepilogue_ssse3       # HandlerData[]
1796 ___
1797 $code.=<<___ if ($avx);
1798 .LSEH_info_sha1_block_data_order_avx:
1799         .byte   9,0,0,0
1800         .rva    ssse3_handler
1801         .rva    .Lprologue_avx,.Lepilogue_avx           # HandlerData[]
1802 ___
1803 $code.=<<___ if ($avx>1);
1804 .LSEH_info_sha1_block_data_order_avx2:
1805         .byte   9,0,0,0
1806         .rva    ssse3_handler
1807         .rva    .Lprologue_avx2,.Lepilogue_avx2         # HandlerData[]
1808 ___
1809 }
1810
1811 ####################################################################
1812
1813 $code =~ s/\`([^\`]*)\`/eval $1/gem;
1814 print $code;
1815 close STDOUT;