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