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