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