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