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