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