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