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