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