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