aesni-sha1-x86_64.pl: update performance data.
[openssl.git] / crypto / aes / asm / aesni-sha1-x86_64.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9 #
10 # June 2011
11 #
12 # This is AESNI-CBC+SHA1 "stitch" implementation. The idea, as spelled
13 # in http://download.intel.com/design/intarch/papers/323686.pdf, is
14 # that since AESNI-CBC encrypt exhibit *very* low instruction-level
15 # parallelism, interleaving it with another algorithm would allow to
16 # utilize processor resources better and achieve better performance.
17 # SHA1 instruction sequences(*) are taken from sha1-x86_64.pl and
18 # AESNI code is weaved into it. Below are performance numbers in
19 # cycles per processed byte, less is better, for standalone AESNI-CBC
20 # encrypt, sum of the latter and standalone SHA1, and "stitched"
21 # subroutine:
22 #
23 #               AES-128-CBC     +SHA1           stitch      gain
24 # Westmere      3.77[+5.5]      9.26            6.58        +41%
25 # Sandy Bridge  5.05[+5.0(6.2)] 10.06(11.21)    5.98(7.05)  +68%(+59%)
26 # Ivy Bridge    5.05[+4.6]      9.65            5.54        +74%
27 # Haswell       4.43[+3.6(4.4)] 8.00(8.80)      4.55(5.21)  +75%(+69%)
28 # Bulldozer     5.77[+6.0]      11.72           6.37        +84%
29 #
30 #               AES-192-CBC
31 # Westmere      4.51            10.00           6.87        +46%
32 # Sandy Bridge  6.05            11.06(12.21)    6.11(7.20)  +81%(+70%)
33 # Ivy Bridge    6.05            10.65           6.07        +75%
34 # Haswell       5.29            8.86(9.65)      5.32(5.32)  +67%(+81%)
35 # Bulldozer     6.89            12.84           6.96        +84%
36 #
37 #               AES-256-CBC
38 # Westmere      5.25            10.74           7.19        +49%
39 # Sandy Bridge  7.05            12.06(13.21)    7.12(7.68)  +69%(+72%)
40 # Ivy Bridge    7.05            11.65           7.12        +64%
41 # Haswell       6.19            9.76(10.6)      6.21(6.41)  +57%(+65%)
42 # Bulldozer     8.00            13.95           8.25        +69%
43 #
44 # (*)   There are two code paths: SSSE3 and AVX. See sha1-568.pl for
45 #       background information. Above numbers in parentheses are SSSE3
46 #       results collected on AVX-capable CPU, i.e. apply on OSes that
47 #       don't support AVX.
48 #
49 # Needless to mention that it makes no sense to implement "stitched"
50 # *decrypt* subroutine. Because *both* AESNI-CBC decrypt and SHA1
51 # fully utilize parallelism, so stitching would not give any gain
52 # anyway. Well, there might be some, e.g. because of better cache
53 # locality... For reference, here are performance results for
54 # standalone AESNI-CBC decrypt:
55 #
56 #               AES-128-CBC     AES-192-CBC     AES-256-CBC
57 # Westmere      1.25            1.50            1.75
58 # Sandy Bridge  0.74            0.91            1.09
59 # Ivy Bridge    0.74            0.90            1.11
60 # Haswell       0.63            0.76            0.88
61 # Bulldozer     0.70            0.85            0.99
62
63 $flavour = shift;
64 $output  = shift;
65 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
66
67 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
68
69 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
70 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
71 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
72 die "can't locate x86_64-xlate.pl";
73
74 $avx=1 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
75                 =~ /GNU assembler version ([2-9]\.[0-9]+)/ &&
76            $1>=2.19);
77 $avx=1 if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
78            `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ &&
79            $1>=2.09);
80 $avx=1 if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
81            `ml64 2>&1` =~ /Version ([0-9]+)\./ &&
82            $1>=10);
83
84 open OUT,"| \"$^X\" $xlate $flavour $output";
85 *STDOUT=*OUT;
86
87 # void aesni_cbc_sha1_enc(const void *inp,
88 #                       void *out,
89 #                       size_t length,
90 #                       const AES_KEY *key,
91 #                       unsigned char *iv,
92 #                       SHA_CTX *ctx,
93 #                       const void *in0);
94
95 $code.=<<___;
96 .text
97 .extern OPENSSL_ia32cap_P
98
99 .globl  aesni_cbc_sha1_enc
100 .type   aesni_cbc_sha1_enc,\@abi-omnipotent
101 .align  32
102 aesni_cbc_sha1_enc:
103         # caller should check for SSSE3 and AES-NI bits
104         mov     OPENSSL_ia32cap_P+0(%rip),%r10d
105         mov     OPENSSL_ia32cap_P+4(%rip),%r11d
106 ___
107 $code.=<<___ if ($avx);
108         and     \$`1<<28`,%r11d         # mask AVX bit
109         and     \$`1<<30`,%r10d         # mask "Intel CPU" bit
110         or      %r11d,%r10d
111         cmp     \$`1<<28|1<<30`,%r10d
112         je      aesni_cbc_sha1_enc_avx
113 ___
114 $code.=<<___;
115         jmp     aesni_cbc_sha1_enc_ssse3
116         ret
117 .size   aesni_cbc_sha1_enc,.-aesni_cbc_sha1_enc
118 ___
119
120 my ($in0,$out,$len,$key,$ivp,$ctx,$inp)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9","%r10");
121
122 my $Xi=4;
123 my @X=map("%xmm$_",(4..7,0..3));
124 my @Tx=map("%xmm$_",(8..10));
125 my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp");    # size optimization
126 my @T=("%esi","%edi");
127 my $j=0; my $jj=0; my $r=0; my $sn=0; my $rx=0;
128 my $K_XX_XX="%r11";
129 my ($iv,$in,$rndkey0)=map("%xmm$_",(11..13));
130 my @rndkey=("%xmm14","%xmm15");
131
132 if (1) {
133     @X=map("%xmm$_",(4..11));
134     @Tx=map("%xmm$_",(12..14));
135     ($iv,$in,$rndkey0)=map("%xmm$_",(2,3,15));
136     @rndkey=("%xmm0","%xmm1");
137 }
138
139 sub AUTOLOAD()          # thunk [simplified] 32-bit style perlasm
140 { my $opcode = $AUTOLOAD; $opcode =~ s/.*:://;
141   my $arg = pop;
142     $arg = "\$$arg" if ($arg*1 eq $arg);
143     $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n";
144 }
145
146 my $_rol=sub { &rol(@_) };
147 my $_ror=sub { &ror(@_) };
148
149 $code.=<<___;
150 .type   aesni_cbc_sha1_enc_ssse3,\@function,6
151 .align  32
152 aesni_cbc_sha1_enc_ssse3:
153         mov     `($win64?56:8)`(%rsp),$inp      # load 7th argument
154         #shr    \$6,$len                        # debugging artefact
155         #jz     .Lepilogue_ssse3                # debugging artefact
156         push    %rbx
157         push    %rbp
158         push    %r12
159         push    %r13
160         push    %r14
161         push    %r15
162         lea     `-104-($win64?10*16:0)`(%rsp),%rsp
163         #mov    $in0,$inp                       # debugging artefact
164         #lea    64(%rsp),$ctx                   # debugging artefact
165 ___
166 $code.=<<___ if ($win64);
167         movaps  %xmm6,96+0(%rsp)
168         movaps  %xmm7,96+16(%rsp)
169         movaps  %xmm8,96+32(%rsp)
170         movaps  %xmm9,96+48(%rsp)
171         movaps  %xmm10,96+64(%rsp)
172         movaps  %xmm11,96+80(%rsp)
173         movaps  %xmm12,96+96(%rsp)
174         movaps  %xmm13,96+112(%rsp)
175         movaps  %xmm14,96+128(%rsp)
176         movaps  %xmm15,96+144(%rsp)
177 .Lprologue_ssse3:
178 ___
179 $code.=<<___;
180         mov     $in0,%r12                       # reassign arguments
181         mov     $out,%r13
182         mov     $len,%r14
183         mov     $key,%r15
184         movdqu  ($ivp),$iv                      # load IV
185         mov     $ivp,88(%rsp)                   # save $ivp
186 ___
187 my ($in0,$out,$len,$key)=map("%r$_",(12..15));  # reassign arguments
188 my $rounds="${ivp}d";
189 $code.=<<___;
190         shl     \$6,$len
191         sub     $in0,$out
192         mov     240($key),$rounds
193         add     $inp,$len               # end of input
194
195         lea     K_XX_XX(%rip),$K_XX_XX
196         mov     0($ctx),$A              # load context
197         mov     4($ctx),$B
198         mov     8($ctx),$C
199         mov     12($ctx),$D
200         mov     $B,@T[0]                # magic seed
201         mov     16($ctx),$E
202         mov     $C,@T[1]
203         xor     $D,@T[1]
204         and     @T[1],@T[0]
205
206         movdqa  64($K_XX_XX),@X[2]      # pbswap mask
207         movdqa  0($K_XX_XX),@Tx[1]      # K_00_19
208         movdqu  0($inp),@X[-4&7]        # load input to %xmm[0-3]
209         movdqu  16($inp),@X[-3&7]
210         movdqu  32($inp),@X[-2&7]
211         movdqu  48($inp),@X[-1&7]
212         pshufb  @X[2],@X[-4&7]          # byte swap
213         add     \$64,$inp
214         pshufb  @X[2],@X[-3&7]
215         pshufb  @X[2],@X[-2&7]
216         pshufb  @X[2],@X[-1&7]
217         paddd   @Tx[1],@X[-4&7]         # add K_00_19
218         paddd   @Tx[1],@X[-3&7]
219         paddd   @Tx[1],@X[-2&7]
220         movdqa  @X[-4&7],0(%rsp)        # X[]+K xfer to IALU
221         psubd   @Tx[1],@X[-4&7]         # restore X[]
222         movdqa  @X[-3&7],16(%rsp)
223         psubd   @Tx[1],@X[-3&7]
224         movdqa  @X[-2&7],32(%rsp)
225         psubd   @Tx[1],@X[-2&7]
226         movups  ($key),$rndkey0         # $key[0]
227         movups  16($key),$rndkey[0]     # forward reference
228         jmp     .Loop_ssse3
229 ___
230
231 my $aesenc=sub {
232   use integer;
233   my ($n,$k)=($r/10,$r%10);
234     if ($k==0) {
235       $code.=<<___;
236         movups          `16*$n`($in0),$in               # load input
237         xorps           $rndkey0,$in
238 ___
239       $code.=<<___ if ($n);
240         movups          $iv,`16*($n-1)`($out,$in0)      # write output
241 ___
242       $code.=<<___;
243         xorps           $in,$iv
244         aesenc          $rndkey[0],$iv
245         movups          `32+16*$k`($key),$rndkey[1]
246 ___
247     } elsif ($k==9) {
248       $sn++;
249       $code.=<<___;
250         cmp             \$11,$rounds
251         jb              .Laesenclast$sn
252         movups          `32+16*($k+0)`($key),$rndkey[1]
253         aesenc          $rndkey[0],$iv
254         movups          `32+16*($k+1)`($key),$rndkey[0]
255         aesenc          $rndkey[1],$iv
256         je              .Laesenclast$sn
257         movups          `32+16*($k+2)`($key),$rndkey[1]
258         aesenc          $rndkey[0],$iv
259         movups          `32+16*($k+3)`($key),$rndkey[0]
260         aesenc          $rndkey[1],$iv
261 .Laesenclast$sn:
262         aesenclast      $rndkey[0],$iv
263         movups          16($key),$rndkey[1]             # forward reference
264 ___
265     } else {
266       $code.=<<___;
267         aesenc          $rndkey[0],$iv
268         movups          `32+16*$k`($key),$rndkey[1]
269 ___
270     }
271     $r++;       unshift(@rndkey,pop(@rndkey));
272 };
273
274 sub Xupdate_ssse3_16_31()               # recall that $Xi starts wtih 4
275 { use integer;
276   my $body = shift;
277   my @insns = (&$body,&$body,&$body,&$body);    # 40 instructions
278   my ($a,$b,$c,$d,$e);
279
280         &movdqa (@X[0],@X[-3&7]);
281          eval(shift(@insns));
282          eval(shift(@insns));
283         &movdqa (@Tx[0],@X[-1&7]);
284         &palignr(@X[0],@X[-4&7],8);     # compose "X[-14]" in "X[0]"
285          eval(shift(@insns));
286          eval(shift(@insns));
287
288           &paddd        (@Tx[1],@X[-1&7]);
289          eval(shift(@insns));
290          eval(shift(@insns));
291         &psrldq (@Tx[0],4);             # "X[-3]", 3 dwords
292          eval(shift(@insns));
293          eval(shift(@insns));
294         &pxor   (@X[0],@X[-4&7]);       # "X[0]"^="X[-16]"
295          eval(shift(@insns));
296          eval(shift(@insns));
297
298         &pxor   (@Tx[0],@X[-2&7]);      # "X[-3]"^"X[-8]"
299          eval(shift(@insns));
300          eval(shift(@insns));
301          eval(shift(@insns));
302          eval(shift(@insns));
303
304         &pxor   (@X[0],@Tx[0]);         # "X[0]"^="X[-3]"^"X[-8]"
305          eval(shift(@insns));
306          eval(shift(@insns));
307           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
308          eval(shift(@insns));
309          eval(shift(@insns));
310
311         &movdqa (@Tx[2],@X[0]);
312         &movdqa (@Tx[0],@X[0]);
313          eval(shift(@insns));
314          eval(shift(@insns));
315          eval(shift(@insns));
316          eval(shift(@insns));
317
318         &pslldq (@Tx[2],12);            # "X[0]"<<96, extract one dword
319         &paddd  (@X[0],@X[0]);
320          eval(shift(@insns));
321          eval(shift(@insns));
322          eval(shift(@insns));
323          eval(shift(@insns));
324
325         &psrld  (@Tx[0],31);
326          eval(shift(@insns));
327          eval(shift(@insns));
328         &movdqa (@Tx[1],@Tx[2]);
329          eval(shift(@insns));
330          eval(shift(@insns));
331
332         &psrld  (@Tx[2],30);
333         &por    (@X[0],@Tx[0]);         # "X[0]"<<<=1
334          eval(shift(@insns));
335          eval(shift(@insns));
336          eval(shift(@insns));
337          eval(shift(@insns));
338
339         &pslld  (@Tx[1],2);
340         &pxor   (@X[0],@Tx[2]);
341          eval(shift(@insns));
342          eval(shift(@insns));
343           &movdqa       (@Tx[2],eval(16*(($Xi)/5))."($K_XX_XX)");       # K_XX_XX
344          eval(shift(@insns));
345          eval(shift(@insns));
346
347         &pxor   (@X[0],@Tx[1]);         # "X[0]"^=("X[0]">>96)<<<2
348
349          foreach (@insns) { eval; }     # remaining instructions [if any]
350
351   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
352                 push(@Tx,shift(@Tx));
353 }
354
355 sub Xupdate_ssse3_32_79()
356 { use integer;
357   my $body = shift;
358   my @insns = (&$body,&$body,&$body,&$body);    # 32 to 48 instructions
359   my ($a,$b,$c,$d,$e);
360
361         &movdqa (@Tx[0],@X[-1&7])       if ($Xi==8);
362          eval(shift(@insns));           # body_20_39
363         &pxor   (@X[0],@X[-4&7]);       # "X[0]"="X[-32]"^"X[-16]"
364         &palignr(@Tx[0],@X[-2&7],8);    # compose "X[-6]"
365          eval(shift(@insns));
366          eval(shift(@insns));
367          eval(shift(@insns));           # rol
368
369         &pxor   (@X[0],@X[-7&7]);       # "X[0]"^="X[-28]"
370          eval(shift(@insns));
371          eval(shift(@insns))    if (@insns[0] !~ /&ro[rl]/);
372         if ($Xi%5) {
373           &movdqa       (@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX...
374         } else {                        # ... or load next one
375           &movdqa       (@Tx[2],eval(16*($Xi/5))."($K_XX_XX)");
376         }
377           &paddd        (@Tx[1],@X[-1&7]);
378          eval(shift(@insns));           # ror
379          eval(shift(@insns));
380
381         &pxor   (@X[0],@Tx[0]);         # "X[0]"^="X[-6]"
382          eval(shift(@insns));           # body_20_39
383          eval(shift(@insns));
384          eval(shift(@insns));
385          eval(shift(@insns));           # rol
386
387         &movdqa (@Tx[0],@X[0]);
388           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
389          eval(shift(@insns));
390          eval(shift(@insns));
391          eval(shift(@insns));           # ror
392          eval(shift(@insns));
393
394         &pslld  (@X[0],2);
395          eval(shift(@insns));           # body_20_39
396          eval(shift(@insns));
397         &psrld  (@Tx[0],30);
398          eval(shift(@insns));
399          eval(shift(@insns));           # rol
400          eval(shift(@insns));
401          eval(shift(@insns));
402          eval(shift(@insns));           # ror
403          eval(shift(@insns));
404
405         &por    (@X[0],@Tx[0]);         # "X[0]"<<<=2
406          eval(shift(@insns));           # body_20_39
407          eval(shift(@insns));
408           &movdqa       (@Tx[1],@X[0])  if ($Xi<19);
409          eval(shift(@insns));
410          eval(shift(@insns));           # rol
411          eval(shift(@insns));
412          eval(shift(@insns));
413          eval(shift(@insns));           # rol
414          eval(shift(@insns));
415
416          foreach (@insns) { eval; }     # remaining instructions
417
418   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
419                 push(@Tx,shift(@Tx));
420 }
421
422 sub Xuplast_ssse3_80()
423 { use integer;
424   my $body = shift;
425   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
426   my ($a,$b,$c,$d,$e);
427
428          eval(shift(@insns));
429           &paddd        (@Tx[1],@X[-1&7]);
430          eval(shift(@insns));
431          eval(shift(@insns));
432          eval(shift(@insns));
433          eval(shift(@insns));
434
435           &movdqa       (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
436
437          foreach (@insns) { eval; }             # remaining instructions
438
439         &cmp    ($inp,$len);
440         &je     (".Ldone_ssse3");
441
442         unshift(@Tx,pop(@Tx));
443
444         &movdqa (@X[2],"64($K_XX_XX)");         # pbswap mask
445         &movdqa (@Tx[1],"0($K_XX_XX)");         # K_00_19
446         &movdqu (@X[-4&7],"0($inp)");           # load input
447         &movdqu (@X[-3&7],"16($inp)");
448         &movdqu (@X[-2&7],"32($inp)");
449         &movdqu (@X[-1&7],"48($inp)");
450         &pshufb (@X[-4&7],@X[2]);               # byte swap
451         &add    ($inp,64);
452
453   $Xi=0;
454 }
455
456 sub Xloop_ssse3()
457 { use integer;
458   my $body = shift;
459   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
460   my ($a,$b,$c,$d,$e);
461
462          eval(shift(@insns));
463          eval(shift(@insns));
464         &pshufb (@X[($Xi-3)&7],@X[2]);
465          eval(shift(@insns));
466          eval(shift(@insns));
467         &paddd  (@X[($Xi-4)&7],@Tx[1]);
468          eval(shift(@insns));
469          eval(shift(@insns));
470          eval(shift(@insns));
471          eval(shift(@insns));
472         &movdqa (eval(16*$Xi)."(%rsp)",@X[($Xi-4)&7]);  # X[]+K xfer to IALU
473          eval(shift(@insns));
474          eval(shift(@insns));
475         &psubd  (@X[($Xi-4)&7],@Tx[1]);
476
477         foreach (@insns) { eval; }
478   $Xi++;
479 }
480
481 sub Xtail_ssse3()
482 { use integer;
483   my $body = shift;
484   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
485   my ($a,$b,$c,$d,$e);
486
487         foreach (@insns) { eval; }
488 }
489
490 sub body_00_19 () {     # ((c^d)&b)^d
491   # on start @T[0]=(c^d)&b
492   return &body_20_39() if ($rx==19); $rx++;
493
494   use integer;
495   my ($k,$n);
496   my @r=(
497         '($a,$b,$c,$d,$e)=@V;'.
498         '&$_ror ($b,$j?7:2);',  # $b>>>2
499         '&xor   (@T[0],$d);',
500         '&mov   (@T[1],$a);',   # $b for next round
501
502         '&add   ($e,eval(4*($j&15))."(%rsp)");',# X[]+K xfer
503         '&xor   ($b,$c);',      # $c^$d for next round
504
505         '&$_rol ($a,5);',
506         '&add   ($e,@T[0]);',
507         '&and   (@T[1],$b);',   # ($b&($c^$d)) for next round
508
509         '&xor   ($b,$c);',      # restore $b
510         '&add   ($e,$a);'       .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
511         );
512         $n = scalar(@r);
513         $k = (($jj+1)*12/20)*20*$n/12;  # 12 aesencs per these 20 rounds
514         @r[$k%$n].='&$aesenc();'        if ($jj==$k/$n);
515         $jj++;
516     return @r;
517 }
518
519 sub body_20_39 () {     # b^d^c
520   # on entry @T[0]=b^d
521   return &body_40_59() if ($rx==39); $rx++;
522
523   use integer;
524   my ($k,$n);
525   my @r=(
526         '($a,$b,$c,$d,$e)=@V;'.
527         '&add   ($e,eval(4*($j&15))."(%rsp)");',# X[]+K xfer
528         '&xor   (@T[0],$d)      if($j==19);'.
529         '&xor   (@T[0],$c)      if($j> 19);',   # ($b^$d^$c)
530         '&mov   (@T[1],$a);',   # $b for next round
531
532         '&$_rol ($a,5);',
533         '&add   ($e,@T[0]);',
534         '&xor   (@T[1],$c)      if ($j< 79);',  # $b^$d for next round
535
536         '&$_ror ($b,7);',       # $b>>>2
537         '&add   ($e,$a);'       .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
538         );
539         $n = scalar(@r);
540         $k = (($jj+1)*8/20)*20*$n/8;    # 8 aesencs per these 20 rounds
541         @r[$k%$n].='&$aesenc();'        if ($jj==$k/$n && $rx!=20);
542         $jj++;
543     return @r;
544 }
545
546 sub body_40_59 () {     # ((b^c)&(c^d))^c
547   # on entry @T[0]=(b^c), (c^=d)
548   $rx++;
549
550   use integer;
551   my ($k,$n);
552   my @r=(
553         '($a,$b,$c,$d,$e)=@V;'.
554         '&add   ($e,eval(4*($j&15))."(%rsp)");',# X[]+K xfer
555         '&and   (@T[0],$c)      if ($j>=40);',  # (b^c)&(c^d)
556         '&xor   ($c,$d)         if ($j>=40);',  # restore $c
557
558         '&$_ror ($b,7);',       # $b>>>2
559         '&mov   (@T[1],$a);',   # $b for next round
560         '&xor   (@T[0],$c);',
561
562         '&$_rol ($a,5);',
563         '&add   ($e,@T[0]);',
564         '&xor   (@T[1],$c)      if ($j==59);'.
565         '&xor   (@T[1],$b)      if ($j< 59);',  # b^c for next round
566
567         '&xor   ($b,$c)         if ($j< 59);',  # c^d for next round
568         '&add   ($e,$a);'       .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));'
569         );
570         $n = scalar(@r);
571         $k=(($jj+1)*12/20)*20*$n/12;    # 12 aesencs per these 20 rounds
572         @r[$k%$n].='&$aesenc();'        if ($jj==$k/$n && $rx!=40);
573         $jj++;
574     return @r;
575 }
576 $code.=<<___;
577 .align  32
578 .Loop_ssse3:
579 ___
580         &Xupdate_ssse3_16_31(\&body_00_19);
581         &Xupdate_ssse3_16_31(\&body_00_19);
582         &Xupdate_ssse3_16_31(\&body_00_19);
583         &Xupdate_ssse3_16_31(\&body_00_19);
584         &Xupdate_ssse3_32_79(\&body_00_19);
585         &Xupdate_ssse3_32_79(\&body_20_39);
586         &Xupdate_ssse3_32_79(\&body_20_39);
587         &Xupdate_ssse3_32_79(\&body_20_39);
588         &Xupdate_ssse3_32_79(\&body_20_39);
589         &Xupdate_ssse3_32_79(\&body_20_39);
590         &Xupdate_ssse3_32_79(\&body_40_59);
591         &Xupdate_ssse3_32_79(\&body_40_59);
592         &Xupdate_ssse3_32_79(\&body_40_59);
593         &Xupdate_ssse3_32_79(\&body_40_59);
594         &Xupdate_ssse3_32_79(\&body_40_59);
595         &Xupdate_ssse3_32_79(\&body_20_39);
596         &Xuplast_ssse3_80(\&body_20_39);        # can jump to "done"
597
598                                 $saved_j=$j; @saved_V=@V;
599                                 $saved_r=$r; @saved_rndkey=@rndkey;
600
601         &Xloop_ssse3(\&body_20_39);
602         &Xloop_ssse3(\&body_20_39);
603         &Xloop_ssse3(\&body_20_39);
604
605 $code.=<<___;
606         movups  $iv,48($out,$in0)               # write output
607         lea     64($in0),$in0
608
609         add     0($ctx),$A                      # update context
610         add     4($ctx),@T[0]
611         add     8($ctx),$C
612         add     12($ctx),$D
613         mov     $A,0($ctx)
614         add     16($ctx),$E
615         mov     @T[0],4($ctx)
616         mov     @T[0],$B                        # magic seed
617         mov     $C,8($ctx)
618         mov     $C,@T[1]
619         mov     $D,12($ctx)
620         xor     $D,@T[1]
621         mov     $E,16($ctx)
622         and     @T[1],@T[0]
623         jmp     .Loop_ssse3
624
625 .Ldone_ssse3:
626 ___
627                                 $jj=$j=$saved_j; @V=@saved_V;
628                                 $r=$saved_r;     @rndkey=@saved_rndkey;
629
630         &Xtail_ssse3(\&body_20_39);
631         &Xtail_ssse3(\&body_20_39);
632         &Xtail_ssse3(\&body_20_39);
633
634 $code.=<<___;
635         movups  $iv,48($out,$in0)               # write output
636         mov     88(%rsp),$ivp                   # restore $ivp
637
638         add     0($ctx),$A                      # update context
639         add     4($ctx),@T[0]
640         add     8($ctx),$C
641         mov     $A,0($ctx)
642         add     12($ctx),$D
643         mov     @T[0],4($ctx)
644         add     16($ctx),$E
645         mov     $C,8($ctx)
646         mov     $D,12($ctx)
647         mov     $E,16($ctx)
648         movups  $iv,($ivp)                      # write IV
649 ___
650 $code.=<<___ if ($win64);
651         movaps  96+0(%rsp),%xmm6
652         movaps  96+16(%rsp),%xmm7
653         movaps  96+32(%rsp),%xmm8
654         movaps  96+48(%rsp),%xmm9
655         movaps  96+64(%rsp),%xmm10
656         movaps  96+80(%rsp),%xmm11
657         movaps  96+96(%rsp),%xmm12
658         movaps  96+112(%rsp),%xmm13
659         movaps  96+128(%rsp),%xmm14
660         movaps  96+144(%rsp),%xmm15
661 ___
662 $code.=<<___;
663         lea     `104+($win64?10*16:0)`(%rsp),%rsi
664         mov     0(%rsi),%r15
665         mov     8(%rsi),%r14
666         mov     16(%rsi),%r13
667         mov     24(%rsi),%r12
668         mov     32(%rsi),%rbp
669         mov     40(%rsi),%rbx
670         lea     48(%rsi),%rsp
671 .Lepilogue_ssse3:
672         ret
673 .size   aesni_cbc_sha1_enc_ssse3,.-aesni_cbc_sha1_enc_ssse3
674 ___
675
676 $j=$jj=$r=$sn=$rx=0;
677
678 if ($avx) {
679 my ($in0,$out,$len,$key,$ivp,$ctx,$inp)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9","%r10");
680
681 my $Xi=4;
682 my @X=map("%xmm$_",(4..7,0..3));
683 my @Tx=map("%xmm$_",(8..10));
684 my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp");    # size optimization
685 my @T=("%esi","%edi");
686 my ($iv,$in,$rndkey0)=map("%xmm$_",(11..13));
687 my @rndkey=("%xmm14","%xmm15");
688 my $Kx=$rndkey0;
689
690 my $_rol=sub { &shld(@_[0],@_) };
691 my $_ror=sub { &shrd(@_[0],@_) };
692
693 $code.=<<___;
694 .type   aesni_cbc_sha1_enc_avx,\@function,6
695 .align  32
696 aesni_cbc_sha1_enc_avx:
697         mov     `($win64?56:8)`(%rsp),$inp      # load 7th argument
698         #shr    \$6,$len                        # debugging artefact
699         #jz     .Lepilogue_avx                  # debugging artefact
700         push    %rbx
701         push    %rbp
702         push    %r12
703         push    %r13
704         push    %r14
705         push    %r15
706         lea     `-104-($win64?10*16:0)`(%rsp),%rsp
707         #mov    $in0,$inp                       # debugging artefact
708         #lea    64(%rsp),$ctx                   # debugging artefact
709 ___
710 $code.=<<___ if ($win64);
711         movaps  %xmm6,96+0(%rsp)
712         movaps  %xmm7,96+16(%rsp)
713         movaps  %xmm8,96+32(%rsp)
714         movaps  %xmm9,96+48(%rsp)
715         movaps  %xmm10,96+64(%rsp)
716         movaps  %xmm11,96+80(%rsp)
717         movaps  %xmm12,96+96(%rsp)
718         movaps  %xmm13,96+112(%rsp)
719         movaps  %xmm14,96+128(%rsp)
720         movaps  %xmm15,96+144(%rsp)
721 .Lprologue_avx:
722 ___
723 $code.=<<___;
724         vzeroall
725         mov     $in0,%r12                       # reassign arguments
726         mov     $out,%r13
727         mov     $len,%r14
728         mov     $key,%r15
729         vmovdqu ($ivp),$iv                      # load IV
730         mov     $ivp,88(%rsp)                   # save $ivp
731 ___
732 my ($in0,$out,$len,$key)=map("%r$_",(12..15));  # reassign arguments
733 my $rounds="${ivp}d";
734 $code.=<<___;
735         shl     \$6,$len
736         sub     $in0,$out
737         mov     240($key),$rounds
738         add     \$112,$key              # size optimization
739         add     $inp,$len               # end of input
740
741         lea     K_XX_XX(%rip),$K_XX_XX
742         mov     0($ctx),$A              # load context
743         mov     4($ctx),$B
744         mov     8($ctx),$C
745         mov     12($ctx),$D
746         mov     $B,@T[0]                # magic seed
747         mov     16($ctx),$E
748         mov     $C,@T[1]
749         xor     $D,@T[1]
750         and     @T[1],@T[0]
751
752         vmovdqa 64($K_XX_XX),@X[2]      # pbswap mask
753         vmovdqa 0($K_XX_XX),$Kx         # K_00_19
754         vmovdqu 0($inp),@X[-4&7]        # load input to %xmm[0-3]
755         vmovdqu 16($inp),@X[-3&7]
756         vmovdqu 32($inp),@X[-2&7]
757         vmovdqu 48($inp),@X[-1&7]
758         vpshufb @X[2],@X[-4&7],@X[-4&7] # byte swap
759         add     \$64,$inp
760         vpshufb @X[2],@X[-3&7],@X[-3&7]
761         vpshufb @X[2],@X[-2&7],@X[-2&7]
762         vpshufb @X[2],@X[-1&7],@X[-1&7]
763         vpaddd  $Kx,@X[-4&7],@X[0]      # add K_00_19
764         vpaddd  $Kx,@X[-3&7],@X[1]
765         vpaddd  $Kx,@X[-2&7],@X[2]
766         vmovdqa @X[0],0(%rsp)           # X[]+K xfer to IALU
767         vmovdqa @X[1],16(%rsp)
768         vmovdqa @X[2],32(%rsp)
769         vmovups -112($key),$rndkey[1]   # $key[0]
770         vmovups 16-112($key),$rndkey[0] # forward reference
771         jmp     .Loop_avx
772 ___
773
774 my $aesenc=sub {
775   use integer;
776   my ($n,$k)=($r/10,$r%10);
777     if ($k==0) {
778       $code.=<<___;
779         vmovdqu         `16*$n`($in0),$in               # load input
780         vpxor           $rndkey[1],$in,$in
781 ___
782       $code.=<<___ if ($n);
783         vmovups         $iv,`16*($n-1)`($out,$in0)      # write output
784 ___
785       $code.=<<___;
786         vpxor           $in,$iv,$iv
787         vaesenc         $rndkey[0],$iv,$iv
788         vmovups         `32+16*$k-112`($key),$rndkey[1]
789 ___
790     } elsif ($k==9) {
791       $sn++;
792       $code.=<<___;
793         cmp             \$11,$rounds
794         jb              .Lvaesenclast$sn
795         vaesenc         $rndkey[0],$iv,$iv
796         vmovups         `32+16*($k+0)-112`($key),$rndkey[1]
797         vaesenc         $rndkey[1],$iv,$iv
798         vmovups         `32+16*($k+1)-112`($key),$rndkey[0]
799         je              .Lvaesenclast$sn
800         vaesenc         $rndkey[0],$iv,$iv
801         vmovups         `32+16*($k+2)-112`($key),$rndkey[1]
802         vaesenc         $rndkey[1],$iv,$iv
803         vmovups         `32+16*($k+3)-112`($key),$rndkey[0]
804 .Lvaesenclast$sn:
805         vaesenclast     $rndkey[0],$iv,$iv
806         vmovups         -112($key),$rndkey[0]
807         vmovups         16-112($key),$rndkey[1]         # forward reference
808 ___
809     } else {
810       $code.=<<___;
811         vaesenc         $rndkey[0],$iv,$iv
812         vmovups         `32+16*$k-112`($key),$rndkey[1]
813 ___
814     }
815     $r++;       unshift(@rndkey,pop(@rndkey));
816 };
817
818 sub Xupdate_avx_16_31()         # recall that $Xi starts wtih 4
819 { use integer;
820   my $body = shift;
821   my @insns = (&$body,&$body,&$body,&$body);    # 40 instructions
822   my ($a,$b,$c,$d,$e);
823
824          eval(shift(@insns));
825          eval(shift(@insns));
826         &vpalignr(@X[0],@X[-3&7],@X[-4&7],8);   # compose "X[-14]" in "X[0]"
827          eval(shift(@insns));
828          eval(shift(@insns));
829
830           &vpaddd       (@Tx[1],$Kx,@X[-1&7]);
831          eval(shift(@insns));
832          eval(shift(@insns));
833         &vpsrldq(@Tx[0],@X[-1&7],4);            # "X[-3]", 3 dwords
834          eval(shift(@insns));
835          eval(shift(@insns));
836         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"^="X[-16]"
837          eval(shift(@insns));
838          eval(shift(@insns));
839
840         &vpxor  (@Tx[0],@Tx[0],@X[-2&7]);       # "X[-3]"^"X[-8]"
841          eval(shift(@insns));
842          eval(shift(@insns));
843          eval(shift(@insns));
844          eval(shift(@insns));
845
846         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-3]"^"X[-8]"
847          eval(shift(@insns));
848          eval(shift(@insns));
849           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
850          eval(shift(@insns));
851          eval(shift(@insns));
852
853         &vpsrld (@Tx[0],@X[0],31);
854          eval(shift(@insns));
855          eval(shift(@insns));
856          eval(shift(@insns));
857          eval(shift(@insns));
858
859         &vpslldq(@Tx[2],@X[0],12);              # "X[0]"<<96, extract one dword
860         &vpaddd (@X[0],@X[0],@X[0]);
861          eval(shift(@insns));
862          eval(shift(@insns));
863          eval(shift(@insns));
864          eval(shift(@insns));
865
866         &vpsrld (@Tx[1],@Tx[2],30);
867         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=1
868          eval(shift(@insns));
869          eval(shift(@insns));
870          eval(shift(@insns));
871          eval(shift(@insns));
872
873         &vpslld (@Tx[2],@Tx[2],2);
874         &vpxor  (@X[0],@X[0],@Tx[1]);
875          eval(shift(@insns));
876          eval(shift(@insns));
877          eval(shift(@insns));
878          eval(shift(@insns));
879
880         &vpxor  (@X[0],@X[0],@Tx[2]);           # "X[0]"^=("X[0]">>96)<<<2
881          eval(shift(@insns));
882          eval(shift(@insns));
883           &vmovdqa      ($Kx,eval(16*(($Xi)/5))."($K_XX_XX)")   if ($Xi%5==0);  # K_XX_XX
884          eval(shift(@insns));
885          eval(shift(@insns));
886
887
888          foreach (@insns) { eval; }     # remaining instructions [if any]
889
890   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
891 }
892
893 sub Xupdate_avx_32_79()
894 { use integer;
895   my $body = shift;
896   my @insns = (&$body,&$body,&$body,&$body);    # 32 to 48 instructions
897   my ($a,$b,$c,$d,$e);
898
899         &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8);  # compose "X[-6]"
900         &vpxor  (@X[0],@X[0],@X[-4&7]);         # "X[0]"="X[-32]"^"X[-16]"
901          eval(shift(@insns));           # body_20_39
902          eval(shift(@insns));
903          eval(shift(@insns));
904          eval(shift(@insns));           # rol
905
906         &vpxor  (@X[0],@X[0],@X[-7&7]);         # "X[0]"^="X[-28]"
907          eval(shift(@insns));
908          eval(shift(@insns))    if (@insns[0] !~ /&ro[rl]/);
909           &vpaddd       (@Tx[1],$Kx,@X[-1&7]);
910           &vmovdqa      ($Kx,eval(16*($Xi/5))."($K_XX_XX)")     if ($Xi%5==0);
911          eval(shift(@insns));           # ror
912          eval(shift(@insns));
913
914         &vpxor  (@X[0],@X[0],@Tx[0]);           # "X[0]"^="X[-6]"
915          eval(shift(@insns));           # body_20_39
916          eval(shift(@insns));
917          eval(shift(@insns));
918          eval(shift(@insns));           # rol
919
920         &vpsrld (@Tx[0],@X[0],30);
921           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU
922          eval(shift(@insns));
923          eval(shift(@insns));
924          eval(shift(@insns));           # ror
925          eval(shift(@insns));
926
927         &vpslld (@X[0],@X[0],2);
928          eval(shift(@insns));           # body_20_39
929          eval(shift(@insns));
930          eval(shift(@insns));
931          eval(shift(@insns));           # rol
932          eval(shift(@insns));
933          eval(shift(@insns));
934          eval(shift(@insns));           # ror
935          eval(shift(@insns));
936
937         &vpor   (@X[0],@X[0],@Tx[0]);           # "X[0]"<<<=2
938          eval(shift(@insns));           # body_20_39
939          eval(shift(@insns));
940          eval(shift(@insns));
941          eval(shift(@insns));           # rol
942          eval(shift(@insns));
943          eval(shift(@insns));
944          eval(shift(@insns));           # rol
945          eval(shift(@insns));
946
947          foreach (@insns) { eval; }     # remaining instructions
948
949   $Xi++;        push(@X,shift(@X));     # "rotate" X[]
950 }
951
952 sub Xuplast_avx_80()
953 { use integer;
954   my $body = shift;
955   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
956   my ($a,$b,$c,$d,$e);
957
958          eval(shift(@insns));
959           &vpaddd       (@Tx[1],$Kx,@X[-1&7]);
960          eval(shift(@insns));
961          eval(shift(@insns));
962          eval(shift(@insns));
963          eval(shift(@insns));
964
965           &vmovdqa      (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU
966
967          foreach (@insns) { eval; }             # remaining instructions
968
969         &cmp    ($inp,$len);
970         &je     (".Ldone_avx");
971
972         unshift(@Tx,pop(@Tx));
973
974         &vmovdqa(@X[2],"64($K_XX_XX)");         # pbswap mask
975         &vmovdqa($Kx,"0($K_XX_XX)");            # K_00_19
976         &vmovdqu(@X[-4&7],"0($inp)");           # load input
977         &vmovdqu(@X[-3&7],"16($inp)");
978         &vmovdqu(@X[-2&7],"32($inp)");
979         &vmovdqu(@X[-1&7],"48($inp)");
980         &vpshufb(@X[-4&7],@X[-4&7],@X[2]);      # byte swap
981         &add    ($inp,64);
982
983   $Xi=0;
984 }
985
986 sub Xloop_avx()
987 { use integer;
988   my $body = shift;
989   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
990   my ($a,$b,$c,$d,$e);
991
992          eval(shift(@insns));
993          eval(shift(@insns));
994         &vpshufb(@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]);
995          eval(shift(@insns));
996          eval(shift(@insns));
997         &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],$Kx);
998          eval(shift(@insns));
999          eval(shift(@insns));
1000          eval(shift(@insns));
1001          eval(shift(@insns));
1002         &vmovdqa(eval(16*$Xi)."(%rsp)",@X[$Xi&7]);      # X[]+K xfer to IALU
1003          eval(shift(@insns));
1004          eval(shift(@insns));
1005
1006         foreach (@insns) { eval; }
1007   $Xi++;
1008 }
1009
1010 sub Xtail_avx()
1011 { use integer;
1012   my $body = shift;
1013   my @insns = (&$body,&$body,&$body,&$body);    # 32 instructions
1014   my ($a,$b,$c,$d,$e);
1015
1016         foreach (@insns) { eval; }
1017 }
1018
1019 $code.=<<___;
1020 .align  32
1021 .Loop_avx:
1022 ___
1023         &Xupdate_avx_16_31(\&body_00_19);
1024         &Xupdate_avx_16_31(\&body_00_19);
1025         &Xupdate_avx_16_31(\&body_00_19);
1026         &Xupdate_avx_16_31(\&body_00_19);
1027         &Xupdate_avx_32_79(\&body_00_19);
1028         &Xupdate_avx_32_79(\&body_20_39);
1029         &Xupdate_avx_32_79(\&body_20_39);
1030         &Xupdate_avx_32_79(\&body_20_39);
1031         &Xupdate_avx_32_79(\&body_20_39);
1032         &Xupdate_avx_32_79(\&body_20_39);
1033         &Xupdate_avx_32_79(\&body_40_59);
1034         &Xupdate_avx_32_79(\&body_40_59);
1035         &Xupdate_avx_32_79(\&body_40_59);
1036         &Xupdate_avx_32_79(\&body_40_59);
1037         &Xupdate_avx_32_79(\&body_40_59);
1038         &Xupdate_avx_32_79(\&body_20_39);
1039         &Xuplast_avx_80(\&body_20_39);  # can jump to "done"
1040
1041                                 $saved_j=$j; @saved_V=@V;
1042                                 $saved_r=$r; @saved_rndkey=@rndkey;
1043
1044         &Xloop_avx(\&body_20_39);
1045         &Xloop_avx(\&body_20_39);
1046         &Xloop_avx(\&body_20_39);
1047
1048 $code.=<<___;
1049         vmovups $iv,48($out,$in0)               # write output
1050         lea     64($in0),$in0
1051
1052         add     0($ctx),$A                      # update context
1053         add     4($ctx),@T[0]
1054         add     8($ctx),$C
1055         add     12($ctx),$D
1056         mov     $A,0($ctx)
1057         add     16($ctx),$E
1058         mov     @T[0],4($ctx)
1059         mov     @T[0],$B                        # magic seed
1060         mov     $C,8($ctx)
1061         mov     $C,@T[1]
1062         mov     $D,12($ctx)
1063         xor     $D,@T[1]
1064         mov     $E,16($ctx)
1065         and     @T[1],@T[0]
1066         jmp     .Loop_avx
1067
1068 .Ldone_avx:
1069 ___
1070                                 $jj=$j=$saved_j; @V=@saved_V;
1071                                 $r=$saved_r;     @rndkey=@saved_rndkey;
1072
1073         &Xtail_avx(\&body_20_39);
1074         &Xtail_avx(\&body_20_39);
1075         &Xtail_avx(\&body_20_39);
1076
1077 $code.=<<___;
1078         vmovups $iv,48($out,$in0)               # write output
1079         mov     88(%rsp),$ivp                   # restore $ivp
1080
1081         add     0($ctx),$A                      # update context
1082         add     4($ctx),@T[0]
1083         add     8($ctx),$C
1084         mov     $A,0($ctx)
1085         add     12($ctx),$D
1086         mov     @T[0],4($ctx)
1087         add     16($ctx),$E
1088         mov     $C,8($ctx)
1089         mov     $D,12($ctx)
1090         mov     $E,16($ctx)
1091         vmovups $iv,($ivp)                      # write IV
1092         vzeroall
1093 ___
1094 $code.=<<___ if ($win64);
1095         movaps  96+0(%rsp),%xmm6
1096         movaps  96+16(%rsp),%xmm7
1097         movaps  96+32(%rsp),%xmm8
1098         movaps  96+48(%rsp),%xmm9
1099         movaps  96+64(%rsp),%xmm10
1100         movaps  96+80(%rsp),%xmm11
1101         movaps  96+96(%rsp),%xmm12
1102         movaps  96+112(%rsp),%xmm13
1103         movaps  96+128(%rsp),%xmm14
1104         movaps  96+144(%rsp),%xmm15
1105 ___
1106 $code.=<<___;
1107         lea     `104+($win64?10*16:0)`(%rsp),%rsi
1108         mov     0(%rsi),%r15
1109         mov     8(%rsi),%r14
1110         mov     16(%rsi),%r13
1111         mov     24(%rsi),%r12
1112         mov     32(%rsi),%rbp
1113         mov     40(%rsi),%rbx
1114         lea     48(%rsi),%rsp
1115 .Lepilogue_avx:
1116         ret
1117 .size   aesni_cbc_sha1_enc_avx,.-aesni_cbc_sha1_enc_avx
1118 ___
1119 }
1120 $code.=<<___;
1121 .align  64
1122 K_XX_XX:
1123 .long   0x5a827999,0x5a827999,0x5a827999,0x5a827999     # K_00_19
1124 .long   0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1     # K_20_39
1125 .long   0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc     # K_40_59
1126 .long   0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6     # K_60_79
1127 .long   0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f     # pbswap mask
1128
1129 .asciz  "AESNI-CBC+SHA1 stitch for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
1130 .align  64
1131 ___
1132
1133 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1134 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
1135 if ($win64) {
1136 $rec="%rcx";
1137 $frame="%rdx";
1138 $context="%r8";
1139 $disp="%r9";
1140
1141 $code.=<<___;
1142 .extern __imp_RtlVirtualUnwind
1143 .type   ssse3_handler,\@abi-omnipotent
1144 .align  16
1145 ssse3_handler:
1146         push    %rsi
1147         push    %rdi
1148         push    %rbx
1149         push    %rbp
1150         push    %r12
1151         push    %r13
1152         push    %r14
1153         push    %r15
1154         pushfq
1155         sub     \$64,%rsp
1156
1157         mov     120($context),%rax      # pull context->Rax
1158         mov     248($context),%rbx      # pull context->Rip
1159
1160         mov     8($disp),%rsi           # disp->ImageBase
1161         mov     56($disp),%r11          # disp->HandlerData
1162
1163         mov     0(%r11),%r10d           # HandlerData[0]
1164         lea     (%rsi,%r10),%r10        # prologue label
1165         cmp     %r10,%rbx               # context->Rip<prologue label
1166         jb      .Lcommon_seh_tail
1167
1168         mov     152($context),%rax      # pull context->Rsp
1169
1170         mov     4(%r11),%r10d           # HandlerData[1]
1171         lea     (%rsi,%r10),%r10        # epilogue label
1172         cmp     %r10,%rbx               # context->Rip>=epilogue label
1173         jae     .Lcommon_seh_tail
1174
1175         lea     96(%rax),%rsi
1176         lea     512($context),%rdi      # &context.Xmm6
1177         mov     \$20,%ecx
1178         .long   0xa548f3fc              # cld; rep movsq
1179         lea     `104+10*16`(%rax),%rax  # adjust stack pointer
1180
1181         mov     0(%rax),%r15
1182         mov     8(%rax),%r14
1183         mov     16(%rax),%r13
1184         mov     24(%rax),%r12
1185         mov     32(%rax),%rbp
1186         mov     40(%rax),%rbx
1187         lea     48(%rax),%rax
1188         mov     %rbx,144($context)      # restore context->Rbx
1189         mov     %rbp,160($context)      # restore context->Rbp
1190         mov     %r12,216($context)      # restore context->R12
1191         mov     %r13,224($context)      # restore context->R13
1192         mov     %r14,232($context)      # restore context->R14
1193         mov     %r15,240($context)      # restore context->R15
1194
1195 .Lcommon_seh_tail:
1196         mov     8(%rax),%rdi
1197         mov     16(%rax),%rsi
1198         mov     %rax,152($context)      # restore context->Rsp
1199         mov     %rsi,168($context)      # restore context->Rsi
1200         mov     %rdi,176($context)      # restore context->Rdi
1201
1202         mov     40($disp),%rdi          # disp->ContextRecord
1203         mov     $context,%rsi           # context
1204         mov     \$154,%ecx              # sizeof(CONTEXT)
1205         .long   0xa548f3fc              # cld; rep movsq
1206
1207         mov     $disp,%rsi
1208         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
1209         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
1210         mov     0(%rsi),%r8             # arg3, disp->ControlPc
1211         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
1212         mov     40(%rsi),%r10           # disp->ContextRecord
1213         lea     56(%rsi),%r11           # &disp->HandlerData
1214         lea     24(%rsi),%r12           # &disp->EstablisherFrame
1215         mov     %r10,32(%rsp)           # arg5
1216         mov     %r11,40(%rsp)           # arg6
1217         mov     %r12,48(%rsp)           # arg7
1218         mov     %rcx,56(%rsp)           # arg8, (NULL)
1219         call    *__imp_RtlVirtualUnwind(%rip)
1220
1221         mov     \$1,%eax                # ExceptionContinueSearch
1222         add     \$64,%rsp
1223         popfq
1224         pop     %r15
1225         pop     %r14
1226         pop     %r13
1227         pop     %r12
1228         pop     %rbp
1229         pop     %rbx
1230         pop     %rdi
1231         pop     %rsi
1232         ret
1233 .size   ssse3_handler,.-ssse3_handler
1234
1235 .section        .pdata
1236 .align  4
1237         .rva    .LSEH_begin_aesni_cbc_sha1_enc_ssse3
1238         .rva    .LSEH_end_aesni_cbc_sha1_enc_ssse3
1239         .rva    .LSEH_info_aesni_cbc_sha1_enc_ssse3
1240 ___
1241 $code.=<<___ if ($avx);
1242         .rva    .LSEH_begin_aesni_cbc_sha1_enc_avx
1243         .rva    .LSEH_end_aesni_cbc_sha1_enc_avx
1244         .rva    .LSEH_info_aesni_cbc_sha1_enc_avx
1245 ___
1246 $code.=<<___;
1247 .section        .xdata
1248 .align  8
1249 .LSEH_info_aesni_cbc_sha1_enc_ssse3:
1250         .byte   9,0,0,0
1251         .rva    ssse3_handler
1252         .rva    .Lprologue_ssse3,.Lepilogue_ssse3       # HandlerData[]
1253 ___
1254 $code.=<<___ if ($avx);
1255 .LSEH_info_aesni_cbc_sha1_enc_avx:
1256         .byte   9,0,0,0
1257         .rva    ssse3_handler
1258         .rva    .Lprologue_avx,.Lepilogue_avx           # HandlerData[]
1259 ___
1260 }
1261
1262 ####################################################################
1263 sub rex {
1264   local *opcode=shift;
1265   my ($dst,$src)=@_;
1266   my $rex=0;
1267
1268     $rex|=0x04                  if($dst>=8);
1269     $rex|=0x01                  if($src>=8);
1270     push @opcode,$rex|0x40      if($rex);
1271 }
1272
1273 sub aesni {
1274   my $line=shift;
1275   my @opcode=(0x66);
1276
1277     if ($line=~/(aes[a-z]+)\s+%xmm([0-9]+),\s*%xmm([0-9]+)/) {
1278         my %opcodelet = (
1279                 "aesenc" => 0xdc,       "aesenclast" => 0xdd
1280         );
1281         return undef if (!defined($opcodelet{$1}));
1282         rex(\@opcode,$3,$2);
1283         push @opcode,0x0f,0x38,$opcodelet{$1};
1284         push @opcode,0xc0|($2&7)|(($3&7)<<3);   # ModR/M
1285         return ".byte\t".join(',',@opcode);
1286     }
1287     return $line;
1288 }
1289
1290 $code =~ s/\`([^\`]*)\`/eval($1)/gem;
1291 $code =~ s/\b(aes.*%xmm[0-9]+).*$/aesni($1)/gem;
1292
1293 print $code;
1294 close STDOUT;