Following the license change, modify the boilerplates in crypto/aes/
[openssl.git] / crypto / aes / asm / aesni-mb-x86_64.pl
1 #! /usr/bin/env perl
2 # Copyright 2013-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 # Multi-buffer AES-NI procedures process several independent buffers
18 # in parallel by interleaving independent instructions.
19 #
20 # Cycles per byte for interleave factor 4:
21 #
22 #                       asymptotic      measured
23 #                       ---------------------------
24 # Westmere              5.00/4=1.25     5.13/4=1.28
25 # Atom                  15.0/4=3.75     ?15.7/4=3.93
26 # Sandy Bridge          5.06/4=1.27     5.18/4=1.29
27 # Ivy Bridge            5.06/4=1.27     5.14/4=1.29
28 # Haswell               4.44/4=1.11     4.44/4=1.11
29 # Bulldozer             5.75/4=1.44     5.76/4=1.44
30 #
31 # Cycles per byte for interleave factor 8 (not implemented for
32 # pre-AVX processors, where higher interleave factor incidentally
33 # doesn't result in improvement):
34 #
35 #                       asymptotic      measured
36 #                       ---------------------------
37 # Sandy Bridge          5.06/8=0.64     7.10/8=0.89(*)
38 # Ivy Bridge            5.06/8=0.64     7.14/8=0.89(*)
39 # Haswell               5.00/8=0.63     5.00/8=0.63
40 # Bulldozer             5.75/8=0.72     5.77/8=0.72
41 #
42 # (*)   Sandy/Ivy Bridge are known to handle high interleave factors
43 #       suboptimally;
44
45 $flavour = shift;
46 $output  = shift;
47 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
48
49 $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/);
50
51 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
52 ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
53 ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
54 die "can't locate x86_64-xlate.pl";
55
56 $avx=0;
57
58 if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1`
59                 =~ /GNU assembler version ([2-9]\.[0-9]+)/) {
60         $avx = ($1>=2.19) + ($1>=2.22);
61 }
62
63 if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) &&
64            `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) {
65         $avx = ($1>=2.09) + ($1>=2.10);
66 }
67
68 if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) &&
69            `ml64 2>&1` =~ /Version ([0-9]+)\./) {
70         $avx = ($1>=10) + ($1>=11);
71 }
72
73 if (!$avx && `$ENV{CC} -v 2>&1` =~ /((?:^clang|LLVM) version|.*based on LLVM) ([3-9]\.[0-9]+)/) {
74         $avx = ($2>=3.0) + ($2>3.0);
75 }
76
77 open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
78 *STDOUT=*OUT;
79
80 # void aesni_multi_cbc_encrypt (
81 #     struct {  void *inp,*out; int blocks; double iv[2]; } inp[8];
82 #     const AES_KEY *key,
83 #     int num);         /* 1 or 2 */
84 #
85 $inp="%rdi";    # 1st arg
86 $key="%rsi";    # 2nd arg
87 $num="%edx";
88
89 @inptr=map("%r$_",(8..11));
90 @outptr=map("%r$_",(12..15));
91
92 ($rndkey0,$rndkey1)=("%xmm0","%xmm1");
93 @out=map("%xmm$_",(2..5));
94 @inp=map("%xmm$_",(6..9));
95 ($counters,$mask,$zero)=map("%xmm$_",(10..12));
96
97 ($rounds,$one,$sink,$offset)=("%eax","%ecx","%rbp","%rbx");
98
99 $code.=<<___;
100 .text
101
102 .extern OPENSSL_ia32cap_P
103
104 .globl  aesni_multi_cbc_encrypt
105 .type   aesni_multi_cbc_encrypt,\@function,3
106 .align  32
107 aesni_multi_cbc_encrypt:
108 .cfi_startproc
109 ___
110 $code.=<<___ if ($avx);
111         cmp     \$2,$num
112         jb      .Lenc_non_avx
113         mov     OPENSSL_ia32cap_P+4(%rip),%ecx
114         test    \$`1<<28`,%ecx                  # AVX bit
115         jnz     _avx_cbc_enc_shortcut
116         jmp     .Lenc_non_avx
117 .align  16
118 .Lenc_non_avx:
119 ___
120 $code.=<<___;
121         mov     %rsp,%rax
122 .cfi_def_cfa_register   %rax
123         push    %rbx
124 .cfi_push       %rbx
125         push    %rbp
126 .cfi_push       %rbp
127         push    %r12
128 .cfi_push       %r12
129         push    %r13
130 .cfi_push       %r13
131         push    %r14
132 .cfi_push       %r14
133         push    %r15
134 .cfi_push       %r15
135 ___
136 $code.=<<___ if ($win64);
137         lea     -0xa8(%rsp),%rsp
138         movaps  %xmm6,(%rsp)
139         movaps  %xmm7,0x10(%rsp)
140         movaps  %xmm8,0x20(%rsp)
141         movaps  %xmm9,0x30(%rsp)
142         movaps  %xmm10,0x40(%rsp)
143         movaps  %xmm11,0x50(%rsp)
144         movaps  %xmm12,0x60(%rsp)
145         movaps  %xmm13,-0x68(%rax)      # not used, saved to share se_handler
146         movaps  %xmm14,-0x58(%rax)
147         movaps  %xmm15,-0x48(%rax)
148 ___
149 $code.=<<___;
150         # stack layout
151         #
152         # +0    output sink
153         # +16   input sink [original %rsp and $num]
154         # +32   counters
155
156         sub     \$48,%rsp
157         and     \$-64,%rsp
158         mov     %rax,16(%rsp)                   # original %rsp
159 .cfi_cfa_expression     %rsp+16,deref,+8
160
161 .Lenc4x_body:
162         movdqu  ($key),$zero                    # 0-round key
163         lea     0x78($key),$key                 # size optimization
164         lea     40*2($inp),$inp
165
166 .Lenc4x_loop_grande:
167         mov     $num,24(%rsp)                   # original $num
168         xor     $num,$num
169 ___
170 for($i=0;$i<4;$i++) {
171     $code.=<<___;
172         mov     `40*$i+16-40*2`($inp),$one      # borrow $one for number of blocks
173         mov     `40*$i+0-40*2`($inp),@inptr[$i]
174         cmp     $num,$one
175         mov     `40*$i+8-40*2`($inp),@outptr[$i]
176         cmovg   $one,$num                       # find maximum
177         test    $one,$one
178         movdqu  `40*$i+24-40*2`($inp),@out[$i]  # load IV
179         mov     $one,`32+4*$i`(%rsp)            # initialize counters
180         cmovle  %rsp,@inptr[$i]                 # cancel input
181 ___
182 }
183 $code.=<<___;
184         test    $num,$num
185         jz      .Lenc4x_done
186
187         movups  0x10-0x78($key),$rndkey1
188          pxor   $zero,@out[0]
189         movups  0x20-0x78($key),$rndkey0
190          pxor   $zero,@out[1]
191         mov     0xf0-0x78($key),$rounds
192          pxor   $zero,@out[2]
193         movdqu  (@inptr[0]),@inp[0]             # load inputs
194          pxor   $zero,@out[3]
195         movdqu  (@inptr[1]),@inp[1]
196          pxor   @inp[0],@out[0]
197         movdqu  (@inptr[2]),@inp[2]
198          pxor   @inp[1],@out[1]
199         movdqu  (@inptr[3]),@inp[3]
200          pxor   @inp[2],@out[2]
201          pxor   @inp[3],@out[3]
202         movdqa  32(%rsp),$counters              # load counters
203         xor     $offset,$offset
204         jmp     .Loop_enc4x
205
206 .align  32
207 .Loop_enc4x:
208         add     \$16,$offset
209         lea     16(%rsp),$sink                  # sink pointer
210         mov     \$1,$one                        # constant of 1
211         sub     $offset,$sink
212
213         aesenc          $rndkey1,@out[0]
214         prefetcht0      31(@inptr[0],$offset)   # prefetch input
215         prefetcht0      31(@inptr[1],$offset)
216         aesenc          $rndkey1,@out[1]
217         prefetcht0      31(@inptr[2],$offset)
218         prefetcht0      31(@inptr[2],$offset)
219         aesenc          $rndkey1,@out[2]
220         aesenc          $rndkey1,@out[3]
221         movups          0x30-0x78($key),$rndkey1
222 ___
223 for($i=0;$i<4;$i++) {
224 my $rndkey = ($i&1) ? $rndkey1 : $rndkey0;
225 $code.=<<___;
226          cmp            `32+4*$i`(%rsp),$one
227         aesenc          $rndkey,@out[0]
228         aesenc          $rndkey,@out[1]
229         aesenc          $rndkey,@out[2]
230          cmovge         $sink,@inptr[$i]        # cancel input
231          cmovg          $sink,@outptr[$i]       # sink output
232         aesenc          $rndkey,@out[3]
233         movups          `0x40+16*$i-0x78`($key),$rndkey
234 ___
235 }
236 $code.=<<___;
237          movdqa         $counters,$mask
238         aesenc          $rndkey0,@out[0]
239         prefetcht0      15(@outptr[0],$offset)  # prefetch output
240         prefetcht0      15(@outptr[1],$offset)
241         aesenc          $rndkey0,@out[1]
242         prefetcht0      15(@outptr[2],$offset)
243         prefetcht0      15(@outptr[3],$offset)
244         aesenc          $rndkey0,@out[2]
245         aesenc          $rndkey0,@out[3]
246         movups          0x80-0x78($key),$rndkey0
247          pxor           $zero,$zero
248
249         aesenc          $rndkey1,@out[0]
250          pcmpgtd        $zero,$mask
251          movdqu         -0x78($key),$zero       # reload 0-round key
252         aesenc          $rndkey1,@out[1]
253          paddd          $mask,$counters         # decrement counters
254          movdqa         $counters,32(%rsp)      # update counters
255         aesenc          $rndkey1,@out[2]
256         aesenc          $rndkey1,@out[3]
257         movups          0x90-0x78($key),$rndkey1
258
259         cmp     \$11,$rounds
260
261         aesenc          $rndkey0,@out[0]
262         aesenc          $rndkey0,@out[1]
263         aesenc          $rndkey0,@out[2]
264         aesenc          $rndkey0,@out[3]
265         movups          0xa0-0x78($key),$rndkey0
266
267         jb      .Lenc4x_tail
268
269         aesenc          $rndkey1,@out[0]
270         aesenc          $rndkey1,@out[1]
271         aesenc          $rndkey1,@out[2]
272         aesenc          $rndkey1,@out[3]
273         movups          0xb0-0x78($key),$rndkey1
274
275         aesenc          $rndkey0,@out[0]
276         aesenc          $rndkey0,@out[1]
277         aesenc          $rndkey0,@out[2]
278         aesenc          $rndkey0,@out[3]
279         movups          0xc0-0x78($key),$rndkey0
280
281         je      .Lenc4x_tail
282
283         aesenc          $rndkey1,@out[0]
284         aesenc          $rndkey1,@out[1]
285         aesenc          $rndkey1,@out[2]
286         aesenc          $rndkey1,@out[3]
287         movups          0xd0-0x78($key),$rndkey1
288
289         aesenc          $rndkey0,@out[0]
290         aesenc          $rndkey0,@out[1]
291         aesenc          $rndkey0,@out[2]
292         aesenc          $rndkey0,@out[3]
293         movups          0xe0-0x78($key),$rndkey0
294         jmp     .Lenc4x_tail
295
296 .align  32
297 .Lenc4x_tail:
298         aesenc          $rndkey1,@out[0]
299         aesenc          $rndkey1,@out[1]
300         aesenc          $rndkey1,@out[2]
301         aesenc          $rndkey1,@out[3]
302          movdqu         (@inptr[0],$offset),@inp[0]
303         movdqu          0x10-0x78($key),$rndkey1
304
305         aesenclast      $rndkey0,@out[0]
306          movdqu         (@inptr[1],$offset),@inp[1]
307          pxor           $zero,@inp[0]
308         aesenclast      $rndkey0,@out[1]
309          movdqu         (@inptr[2],$offset),@inp[2]
310          pxor           $zero,@inp[1]
311         aesenclast      $rndkey0,@out[2]
312          movdqu         (@inptr[3],$offset),@inp[3]
313          pxor           $zero,@inp[2]
314         aesenclast      $rndkey0,@out[3]
315         movdqu          0x20-0x78($key),$rndkey0
316          pxor           $zero,@inp[3]
317
318         movups          @out[0],-16(@outptr[0],$offset)
319          pxor           @inp[0],@out[0]
320         movups          @out[1],-16(@outptr[1],$offset)
321          pxor           @inp[1],@out[1]
322         movups          @out[2],-16(@outptr[2],$offset)
323          pxor           @inp[2],@out[2]
324         movups          @out[3],-16(@outptr[3],$offset)
325          pxor           @inp[3],@out[3]
326
327         dec     $num
328         jnz     .Loop_enc4x
329
330         mov     16(%rsp),%rax                   # original %rsp
331 .cfi_def_cfa    %rax,8
332         mov     24(%rsp),$num
333
334         #pxor   @inp[0],@out[0]
335         #pxor   @inp[1],@out[1]
336         #movdqu @out[0],`40*0+24-40*2`($inp)    # output iv FIX ME!
337         #pxor   @inp[2],@out[2]
338         #movdqu @out[1],`40*1+24-40*2`($inp)
339         #pxor   @inp[3],@out[3]
340         #movdqu @out[2],`40*2+24-40*2`($inp)    # won't fix, let caller
341         #movdqu @out[3],`40*3+24-40*2`($inp)    # figure this out...
342
343         lea     `40*4`($inp),$inp
344         dec     $num
345         jnz     .Lenc4x_loop_grande
346
347 .Lenc4x_done:
348 ___
349 $code.=<<___ if ($win64);
350         movaps  -0xd8(%rax),%xmm6
351         movaps  -0xc8(%rax),%xmm7
352         movaps  -0xb8(%rax),%xmm8
353         movaps  -0xa8(%rax),%xmm9
354         movaps  -0x98(%rax),%xmm10
355         movaps  -0x88(%rax),%xmm11
356         movaps  -0x78(%rax),%xmm12
357         #movaps -0x68(%rax),%xmm13
358         #movaps -0x58(%rax),%xmm14
359         #movaps -0x48(%rax),%xmm15
360 ___
361 $code.=<<___;
362         mov     -48(%rax),%r15
363 .cfi_restore    %r15
364         mov     -40(%rax),%r14
365 .cfi_restore    %r14
366         mov     -32(%rax),%r13
367 .cfi_restore    %r13
368         mov     -24(%rax),%r12
369 .cfi_restore    %r12
370         mov     -16(%rax),%rbp
371 .cfi_restore    %rbp
372         mov     -8(%rax),%rbx
373 .cfi_restore    %rbx
374         lea     (%rax),%rsp
375 .cfi_def_cfa_register   %rsp
376 .Lenc4x_epilogue:
377         ret
378 .cfi_endproc
379 .size   aesni_multi_cbc_encrypt,.-aesni_multi_cbc_encrypt
380
381 .globl  aesni_multi_cbc_decrypt
382 .type   aesni_multi_cbc_decrypt,\@function,3
383 .align  32
384 aesni_multi_cbc_decrypt:
385 .cfi_startproc
386 ___
387 $code.=<<___ if ($avx);
388         cmp     \$2,$num
389         jb      .Ldec_non_avx
390         mov     OPENSSL_ia32cap_P+4(%rip),%ecx
391         test    \$`1<<28`,%ecx                  # AVX bit
392         jnz     _avx_cbc_dec_shortcut
393         jmp     .Ldec_non_avx
394 .align  16
395 .Ldec_non_avx:
396 ___
397 $code.=<<___;
398         mov     %rsp,%rax
399 .cfi_def_cfa_register   %rax
400         push    %rbx
401 .cfi_push       %rbx
402         push    %rbp
403 .cfi_push       %rbp
404         push    %r12
405 .cfi_push       %r12
406         push    %r13
407 .cfi_push       %r13
408         push    %r14
409 .cfi_push       %r14
410         push    %r15
411 .cfi_push       %r15
412 ___
413 $code.=<<___ if ($win64);
414         lea     -0xa8(%rsp),%rsp
415         movaps  %xmm6,(%rsp)
416         movaps  %xmm7,0x10(%rsp)
417         movaps  %xmm8,0x20(%rsp)
418         movaps  %xmm9,0x30(%rsp)
419         movaps  %xmm10,0x40(%rsp)
420         movaps  %xmm11,0x50(%rsp)
421         movaps  %xmm12,0x60(%rsp)
422         movaps  %xmm13,-0x68(%rax)      # not used, saved to share se_handler
423         movaps  %xmm14,-0x58(%rax)
424         movaps  %xmm15,-0x48(%rax)
425 ___
426 $code.=<<___;
427         # stack layout
428         #
429         # +0    output sink
430         # +16   input sink [original %rsp and $num]
431         # +32   counters
432
433         sub     \$48,%rsp
434         and     \$-64,%rsp
435         mov     %rax,16(%rsp)                   # original %rsp
436 .cfi_cfa_expression     %rsp+16,deref,+8
437
438 .Ldec4x_body:
439         movdqu  ($key),$zero                    # 0-round key
440         lea     0x78($key),$key                 # size optimization
441         lea     40*2($inp),$inp
442
443 .Ldec4x_loop_grande:
444         mov     $num,24(%rsp)                   # original $num
445         xor     $num,$num
446 ___
447 for($i=0;$i<4;$i++) {
448     $code.=<<___;
449         mov     `40*$i+16-40*2`($inp),$one      # borrow $one for number of blocks
450         mov     `40*$i+0-40*2`($inp),@inptr[$i]
451         cmp     $num,$one
452         mov     `40*$i+8-40*2`($inp),@outptr[$i]
453         cmovg   $one,$num                       # find maximum
454         test    $one,$one
455         movdqu  `40*$i+24-40*2`($inp),@inp[$i]  # load IV
456         mov     $one,`32+4*$i`(%rsp)            # initialize counters
457         cmovle  %rsp,@inptr[$i]                 # cancel input
458 ___
459 }
460 $code.=<<___;
461         test    $num,$num
462         jz      .Ldec4x_done
463
464         movups  0x10-0x78($key),$rndkey1
465         movups  0x20-0x78($key),$rndkey0
466         mov     0xf0-0x78($key),$rounds
467         movdqu  (@inptr[0]),@out[0]             # load inputs
468         movdqu  (@inptr[1]),@out[1]
469          pxor   $zero,@out[0]
470         movdqu  (@inptr[2]),@out[2]
471          pxor   $zero,@out[1]
472         movdqu  (@inptr[3]),@out[3]
473          pxor   $zero,@out[2]
474          pxor   $zero,@out[3]
475         movdqa  32(%rsp),$counters              # load counters
476         xor     $offset,$offset
477         jmp     .Loop_dec4x
478
479 .align  32
480 .Loop_dec4x:
481         add     \$16,$offset
482         lea     16(%rsp),$sink                  # sink pointer
483         mov     \$1,$one                        # constant of 1
484         sub     $offset,$sink
485
486         aesdec          $rndkey1,@out[0]
487         prefetcht0      31(@inptr[0],$offset)   # prefetch input
488         prefetcht0      31(@inptr[1],$offset)
489         aesdec          $rndkey1,@out[1]
490         prefetcht0      31(@inptr[2],$offset)
491         prefetcht0      31(@inptr[3],$offset)
492         aesdec          $rndkey1,@out[2]
493         aesdec          $rndkey1,@out[3]
494         movups          0x30-0x78($key),$rndkey1
495 ___
496 for($i=0;$i<4;$i++) {
497 my $rndkey = ($i&1) ? $rndkey1 : $rndkey0;
498 $code.=<<___;
499          cmp            `32+4*$i`(%rsp),$one
500         aesdec          $rndkey,@out[0]
501         aesdec          $rndkey,@out[1]
502         aesdec          $rndkey,@out[2]
503          cmovge         $sink,@inptr[$i]        # cancel input
504          cmovg          $sink,@outptr[$i]       # sink output
505         aesdec          $rndkey,@out[3]
506         movups          `0x40+16*$i-0x78`($key),$rndkey
507 ___
508 }
509 $code.=<<___;
510          movdqa         $counters,$mask
511         aesdec          $rndkey0,@out[0]
512         prefetcht0      15(@outptr[0],$offset)  # prefetch output
513         prefetcht0      15(@outptr[1],$offset)
514         aesdec          $rndkey0,@out[1]
515         prefetcht0      15(@outptr[2],$offset)
516         prefetcht0      15(@outptr[3],$offset)
517         aesdec          $rndkey0,@out[2]
518         aesdec          $rndkey0,@out[3]
519         movups          0x80-0x78($key),$rndkey0
520          pxor           $zero,$zero
521
522         aesdec          $rndkey1,@out[0]
523          pcmpgtd        $zero,$mask
524          movdqu         -0x78($key),$zero       # reload 0-round key
525         aesdec          $rndkey1,@out[1]
526          paddd          $mask,$counters         # decrement counters
527          movdqa         $counters,32(%rsp)      # update counters
528         aesdec          $rndkey1,@out[2]
529         aesdec          $rndkey1,@out[3]
530         movups          0x90-0x78($key),$rndkey1
531
532         cmp     \$11,$rounds
533
534         aesdec          $rndkey0,@out[0]
535         aesdec          $rndkey0,@out[1]
536         aesdec          $rndkey0,@out[2]
537         aesdec          $rndkey0,@out[3]
538         movups          0xa0-0x78($key),$rndkey0
539
540         jb      .Ldec4x_tail
541
542         aesdec          $rndkey1,@out[0]
543         aesdec          $rndkey1,@out[1]
544         aesdec          $rndkey1,@out[2]
545         aesdec          $rndkey1,@out[3]
546         movups          0xb0-0x78($key),$rndkey1
547
548         aesdec          $rndkey0,@out[0]
549         aesdec          $rndkey0,@out[1]
550         aesdec          $rndkey0,@out[2]
551         aesdec          $rndkey0,@out[3]
552         movups          0xc0-0x78($key),$rndkey0
553
554         je      .Ldec4x_tail
555
556         aesdec          $rndkey1,@out[0]
557         aesdec          $rndkey1,@out[1]
558         aesdec          $rndkey1,@out[2]
559         aesdec          $rndkey1,@out[3]
560         movups          0xd0-0x78($key),$rndkey1
561
562         aesdec          $rndkey0,@out[0]
563         aesdec          $rndkey0,@out[1]
564         aesdec          $rndkey0,@out[2]
565         aesdec          $rndkey0,@out[3]
566         movups          0xe0-0x78($key),$rndkey0
567         jmp     .Ldec4x_tail
568
569 .align  32
570 .Ldec4x_tail:
571         aesdec          $rndkey1,@out[0]
572         aesdec          $rndkey1,@out[1]
573         aesdec          $rndkey1,@out[2]
574          pxor           $rndkey0,@inp[0]
575          pxor           $rndkey0,@inp[1]
576         aesdec          $rndkey1,@out[3]
577         movdqu          0x10-0x78($key),$rndkey1
578          pxor           $rndkey0,@inp[2]
579          pxor           $rndkey0,@inp[3]
580         movdqu          0x20-0x78($key),$rndkey0
581
582         aesdeclast      @inp[0],@out[0]
583         aesdeclast      @inp[1],@out[1]
584          movdqu         -16(@inptr[0],$offset),@inp[0]  # load next IV
585          movdqu         -16(@inptr[1],$offset),@inp[1]
586         aesdeclast      @inp[2],@out[2]
587         aesdeclast      @inp[3],@out[3]
588          movdqu         -16(@inptr[2],$offset),@inp[2]
589          movdqu         -16(@inptr[3],$offset),@inp[3]
590
591         movups          @out[0],-16(@outptr[0],$offset)
592          movdqu         (@inptr[0],$offset),@out[0]
593         movups          @out[1],-16(@outptr[1],$offset)
594          movdqu         (@inptr[1],$offset),@out[1]
595          pxor           $zero,@out[0]
596         movups          @out[2],-16(@outptr[2],$offset)
597          movdqu         (@inptr[2],$offset),@out[2]
598          pxor           $zero,@out[1]
599         movups          @out[3],-16(@outptr[3],$offset)
600          movdqu         (@inptr[3],$offset),@out[3]
601          pxor           $zero,@out[2]
602          pxor           $zero,@out[3]
603
604         dec     $num
605         jnz     .Loop_dec4x
606
607         mov     16(%rsp),%rax                   # original %rsp
608 .cfi_def_cfa    %rax,8
609         mov     24(%rsp),$num
610
611         lea     `40*4`($inp),$inp
612         dec     $num
613         jnz     .Ldec4x_loop_grande
614
615 .Ldec4x_done:
616 ___
617 $code.=<<___ if ($win64);
618         movaps  -0xd8(%rax),%xmm6
619         movaps  -0xc8(%rax),%xmm7
620         movaps  -0xb8(%rax),%xmm8
621         movaps  -0xa8(%rax),%xmm9
622         movaps  -0x98(%rax),%xmm10
623         movaps  -0x88(%rax),%xmm11
624         movaps  -0x78(%rax),%xmm12
625         #movaps -0x68(%rax),%xmm13
626         #movaps -0x58(%rax),%xmm14
627         #movaps -0x48(%rax),%xmm15
628 ___
629 $code.=<<___;
630         mov     -48(%rax),%r15
631 .cfi_restore    %r15
632         mov     -40(%rax),%r14
633 .cfi_restore    %r14
634         mov     -32(%rax),%r13
635 .cfi_restore    %r13
636         mov     -24(%rax),%r12
637 .cfi_restore    %r12
638         mov     -16(%rax),%rbp
639 .cfi_restore    %rbp
640         mov     -8(%rax),%rbx
641 .cfi_restore    %rbx
642         lea     (%rax),%rsp
643 .cfi_def_cfa_register   %rsp
644 .Ldec4x_epilogue:
645         ret
646 .cfi_endproc
647 .size   aesni_multi_cbc_decrypt,.-aesni_multi_cbc_decrypt
648 ___
649
650                                                 if ($avx) {{{
651 my @ptr=map("%r$_",(8..15));
652 my $offload=$sink;
653
654 my @out=map("%xmm$_",(2..9));
655 my @inp=map("%xmm$_",(10..13));
656 my ($counters,$zero)=("%xmm14","%xmm15");
657
658 $code.=<<___;
659 .type   aesni_multi_cbc_encrypt_avx,\@function,3
660 .align  32
661 aesni_multi_cbc_encrypt_avx:
662 .cfi_startproc
663 _avx_cbc_enc_shortcut:
664         mov     %rsp,%rax
665 .cfi_def_cfa_register   %rax
666         push    %rbx
667 .cfi_push       %rbx
668         push    %rbp
669 .cfi_push       %rbp
670         push    %r12
671 .cfi_push       %r12
672         push    %r13
673 .cfi_push       %r13
674         push    %r14
675 .cfi_push       %r14
676         push    %r15
677 .cfi_push       %r15
678 ___
679 $code.=<<___ if ($win64);
680         lea     -0xa8(%rsp),%rsp
681         movaps  %xmm6,(%rsp)
682         movaps  %xmm7,0x10(%rsp)
683         movaps  %xmm8,0x20(%rsp)
684         movaps  %xmm9,0x30(%rsp)
685         movaps  %xmm10,0x40(%rsp)
686         movaps  %xmm11,0x50(%rsp)
687         movaps  %xmm12,-0x78(%rax)
688         movaps  %xmm13,-0x68(%rax)
689         movaps  %xmm14,-0x58(%rax)
690         movaps  %xmm15,-0x48(%rax)
691 ___
692 $code.=<<___;
693         # stack layout
694         #
695         # +0    output sink
696         # +16   input sink [original %rsp and $num]
697         # +32   counters
698         # +64   distances between inputs and outputs
699         # +128  off-load area for @inp[0..3]
700
701         sub     \$192,%rsp
702         and     \$-128,%rsp
703         mov     %rax,16(%rsp)                   # original %rsp
704 .cfi_cfa_expression     %rsp+16,deref,+8
705
706 .Lenc8x_body:
707         vzeroupper
708         vmovdqu ($key),$zero                    # 0-round key
709         lea     0x78($key),$key                 # size optimization
710         lea     40*4($inp),$inp
711         shr     \$1,$num
712
713 .Lenc8x_loop_grande:
714         #mov    $num,24(%rsp)                   # original $num
715         xor     $num,$num
716 ___
717 for($i=0;$i<8;$i++) {
718   my $temp = $i ? $offload : $offset;
719     $code.=<<___;
720         mov     `40*$i+16-40*4`($inp),$one      # borrow $one for number of blocks
721         mov     `40*$i+0-40*4`($inp),@ptr[$i]   # input pointer
722         cmp     $num,$one
723         mov     `40*$i+8-40*4`($inp),$temp      # output pointer
724         cmovg   $one,$num                       # find maximum
725         test    $one,$one
726         vmovdqu `40*$i+24-40*4`($inp),@out[$i]  # load IV
727         mov     $one,`32+4*$i`(%rsp)            # initialize counters
728         cmovle  %rsp,@ptr[$i]                   # cancel input
729         sub     @ptr[$i],$temp                  # distance between input and output
730         mov     $temp,`64+8*$i`(%rsp)           # initialize distances
731 ___
732 }
733 $code.=<<___;
734         test    $num,$num
735         jz      .Lenc8x_done
736
737         vmovups 0x10-0x78($key),$rndkey1
738         vmovups 0x20-0x78($key),$rndkey0
739         mov     0xf0-0x78($key),$rounds
740
741         vpxor   (@ptr[0]),$zero,@inp[0]         # load inputs and xor with 0-round
742          lea    128(%rsp),$offload              # offload area
743         vpxor   (@ptr[1]),$zero,@inp[1]
744         vpxor   (@ptr[2]),$zero,@inp[2]
745         vpxor   (@ptr[3]),$zero,@inp[3]
746          vpxor  @inp[0],@out[0],@out[0]
747         vpxor   (@ptr[4]),$zero,@inp[0]
748          vpxor  @inp[1],@out[1],@out[1]
749         vpxor   (@ptr[5]),$zero,@inp[1]
750          vpxor  @inp[2],@out[2],@out[2]
751         vpxor   (@ptr[6]),$zero,@inp[2]
752          vpxor  @inp[3],@out[3],@out[3]
753         vpxor   (@ptr[7]),$zero,@inp[3]
754          vpxor  @inp[0],@out[4],@out[4]
755         mov     \$1,$one                        # constant of 1
756          vpxor  @inp[1],@out[5],@out[5]
757          vpxor  @inp[2],@out[6],@out[6]
758          vpxor  @inp[3],@out[7],@out[7]
759         jmp     .Loop_enc8x
760
761 .align  32
762 .Loop_enc8x:
763 ___
764 for($i=0;$i<8;$i++) {
765 my $rndkey=($i&1)?$rndkey0:$rndkey1;
766 $code.=<<___;
767         vaesenc         $rndkey,@out[0],@out[0]
768          cmp            32+4*$i(%rsp),$one
769 ___
770 $code.=<<___ if ($i);
771          mov            64+8*$i(%rsp),$offset
772 ___
773 $code.=<<___;
774         vaesenc         $rndkey,@out[1],@out[1]
775         prefetcht0      31(@ptr[$i])                    # prefetch input
776         vaesenc         $rndkey,@out[2],@out[2]
777 ___
778 $code.=<<___ if ($i>1);
779         prefetcht0      15(@ptr[$i-2])                  # prefetch output
780 ___
781 $code.=<<___;
782         vaesenc         $rndkey,@out[3],@out[3]
783          lea            (@ptr[$i],$offset),$offset
784          cmovge         %rsp,@ptr[$i]                   # cancel input
785         vaesenc         $rndkey,@out[4],@out[4]
786          cmovg          %rsp,$offset                    # sink output
787         vaesenc         $rndkey,@out[5],@out[5]
788          sub            @ptr[$i],$offset
789         vaesenc         $rndkey,@out[6],@out[6]
790          vpxor          16(@ptr[$i]),$zero,@inp[$i%4]   # load input and xor with 0-round
791          mov            $offset,64+8*$i(%rsp)
792         vaesenc         $rndkey,@out[7],@out[7]
793         vmovups         `16*(3+$i)-0x78`($key),$rndkey
794          lea            16(@ptr[$i],$offset),@ptr[$i]   # switch to output
795 ___
796 $code.=<<___ if ($i<4)
797          vmovdqu        @inp[$i%4],`16*$i`($offload)    # off-load
798 ___
799 }
800 $code.=<<___;
801          vmovdqu        32(%rsp),$counters
802         prefetcht0      15(@ptr[$i-2])                  # prefetch output
803         prefetcht0      15(@ptr[$i-1])
804         cmp     \$11,$rounds
805         jb      .Lenc8x_tail
806
807         vaesenc         $rndkey1,@out[0],@out[0]
808         vaesenc         $rndkey1,@out[1],@out[1]
809         vaesenc         $rndkey1,@out[2],@out[2]
810         vaesenc         $rndkey1,@out[3],@out[3]
811         vaesenc         $rndkey1,@out[4],@out[4]
812         vaesenc         $rndkey1,@out[5],@out[5]
813         vaesenc         $rndkey1,@out[6],@out[6]
814         vaesenc         $rndkey1,@out[7],@out[7]
815         vmovups         0xb0-0x78($key),$rndkey1
816
817         vaesenc         $rndkey0,@out[0],@out[0]
818         vaesenc         $rndkey0,@out[1],@out[1]
819         vaesenc         $rndkey0,@out[2],@out[2]
820         vaesenc         $rndkey0,@out[3],@out[3]
821         vaesenc         $rndkey0,@out[4],@out[4]
822         vaesenc         $rndkey0,@out[5],@out[5]
823         vaesenc         $rndkey0,@out[6],@out[6]
824         vaesenc         $rndkey0,@out[7],@out[7]
825         vmovups         0xc0-0x78($key),$rndkey0
826         je      .Lenc8x_tail
827
828         vaesenc         $rndkey1,@out[0],@out[0]
829         vaesenc         $rndkey1,@out[1],@out[1]
830         vaesenc         $rndkey1,@out[2],@out[2]
831         vaesenc         $rndkey1,@out[3],@out[3]
832         vaesenc         $rndkey1,@out[4],@out[4]
833         vaesenc         $rndkey1,@out[5],@out[5]
834         vaesenc         $rndkey1,@out[6],@out[6]
835         vaesenc         $rndkey1,@out[7],@out[7]
836         vmovups         0xd0-0x78($key),$rndkey1
837
838         vaesenc         $rndkey0,@out[0],@out[0]
839         vaesenc         $rndkey0,@out[1],@out[1]
840         vaesenc         $rndkey0,@out[2],@out[2]
841         vaesenc         $rndkey0,@out[3],@out[3]
842         vaesenc         $rndkey0,@out[4],@out[4]
843         vaesenc         $rndkey0,@out[5],@out[5]
844         vaesenc         $rndkey0,@out[6],@out[6]
845         vaesenc         $rndkey0,@out[7],@out[7]
846         vmovups         0xe0-0x78($key),$rndkey0
847
848 .Lenc8x_tail:
849         vaesenc         $rndkey1,@out[0],@out[0]
850          vpxor          $zero,$zero,$zero
851         vaesenc         $rndkey1,@out[1],@out[1]
852         vaesenc         $rndkey1,@out[2],@out[2]
853          vpcmpgtd       $zero,$counters,$zero
854         vaesenc         $rndkey1,@out[3],@out[3]
855         vaesenc         $rndkey1,@out[4],@out[4]
856          vpaddd         $counters,$zero,$zero           # decrement counters
857          vmovdqu        48(%rsp),$counters
858         vaesenc         $rndkey1,@out[5],@out[5]
859          mov            64(%rsp),$offset                # pre-load 1st offset
860         vaesenc         $rndkey1,@out[6],@out[6]
861         vaesenc         $rndkey1,@out[7],@out[7]
862         vmovups         0x10-0x78($key),$rndkey1
863
864         vaesenclast     $rndkey0,@out[0],@out[0]
865          vmovdqa        $zero,32(%rsp)                  # update counters
866          vpxor          $zero,$zero,$zero
867         vaesenclast     $rndkey0,@out[1],@out[1]
868         vaesenclast     $rndkey0,@out[2],@out[2]
869          vpcmpgtd       $zero,$counters,$zero
870         vaesenclast     $rndkey0,@out[3],@out[3]
871         vaesenclast     $rndkey0,@out[4],@out[4]
872          vpaddd         $zero,$counters,$counters       # decrement counters
873          vmovdqu        -0x78($key),$zero               # 0-round
874         vaesenclast     $rndkey0,@out[5],@out[5]
875         vaesenclast     $rndkey0,@out[6],@out[6]
876          vmovdqa        $counters,48(%rsp)              # update counters
877         vaesenclast     $rndkey0,@out[7],@out[7]
878         vmovups         0x20-0x78($key),$rndkey0
879
880         vmovups         @out[0],-16(@ptr[0])            # write output
881          sub            $offset,@ptr[0]                 # switch to input
882          vpxor          0x00($offload),@out[0],@out[0]
883         vmovups         @out[1],-16(@ptr[1])
884          sub            `64+1*8`(%rsp),@ptr[1]
885          vpxor          0x10($offload),@out[1],@out[1]
886         vmovups         @out[2],-16(@ptr[2])
887          sub            `64+2*8`(%rsp),@ptr[2]
888          vpxor          0x20($offload),@out[2],@out[2]
889         vmovups         @out[3],-16(@ptr[3])
890          sub            `64+3*8`(%rsp),@ptr[3]
891          vpxor          0x30($offload),@out[3],@out[3]
892         vmovups         @out[4],-16(@ptr[4])
893          sub            `64+4*8`(%rsp),@ptr[4]
894          vpxor          @inp[0],@out[4],@out[4]
895         vmovups         @out[5],-16(@ptr[5])
896          sub            `64+5*8`(%rsp),@ptr[5]
897          vpxor          @inp[1],@out[5],@out[5]
898         vmovups         @out[6],-16(@ptr[6])
899          sub            `64+6*8`(%rsp),@ptr[6]
900          vpxor          @inp[2],@out[6],@out[6]
901         vmovups         @out[7],-16(@ptr[7])
902          sub            `64+7*8`(%rsp),@ptr[7]
903          vpxor          @inp[3],@out[7],@out[7]
904
905         dec     $num
906         jnz     .Loop_enc8x
907
908         mov     16(%rsp),%rax                   # original %rsp
909 .cfi_def_cfa    %rax,8
910         #mov    24(%rsp),$num
911         #lea    `40*8`($inp),$inp
912         #dec    $num
913         #jnz    .Lenc8x_loop_grande
914
915 .Lenc8x_done:
916         vzeroupper
917 ___
918 $code.=<<___ if ($win64);
919         movaps  -0xd8(%rax),%xmm6
920         movaps  -0xc8(%rax),%xmm7
921         movaps  -0xb8(%rax),%xmm8
922         movaps  -0xa8(%rax),%xmm9
923         movaps  -0x98(%rax),%xmm10
924         movaps  -0x88(%rax),%xmm11
925         movaps  -0x78(%rax),%xmm12
926         movaps  -0x68(%rax),%xmm13
927         movaps  -0x58(%rax),%xmm14
928         movaps  -0x48(%rax),%xmm15
929 ___
930 $code.=<<___;
931         mov     -48(%rax),%r15
932 .cfi_restore    %r15
933         mov     -40(%rax),%r14
934 .cfi_restore    %r14
935         mov     -32(%rax),%r13
936 .cfi_restore    %r13
937         mov     -24(%rax),%r12
938 .cfi_restore    %r12
939         mov     -16(%rax),%rbp
940 .cfi_restore    %rbp
941         mov     -8(%rax),%rbx
942 .cfi_restore    %rbx
943         lea     (%rax),%rsp
944 .cfi_def_cfa_register   %rsp
945 .Lenc8x_epilogue:
946         ret
947 .cfi_endproc
948 .size   aesni_multi_cbc_encrypt_avx,.-aesni_multi_cbc_encrypt_avx
949
950 .type   aesni_multi_cbc_decrypt_avx,\@function,3
951 .align  32
952 aesni_multi_cbc_decrypt_avx:
953 .cfi_startproc
954 _avx_cbc_dec_shortcut:
955         mov     %rsp,%rax
956 .cfi_def_cfa_register   %rax
957         push    %rbx
958 .cfi_push       %rbx
959         push    %rbp
960 .cfi_push       %rbp
961         push    %r12
962 .cfi_push       %r12
963         push    %r13
964 .cfi_push       %r13
965         push    %r14
966 .cfi_push       %r14
967         push    %r15
968 .cfi_push       %r15
969 ___
970 $code.=<<___ if ($win64);
971         lea     -0xa8(%rsp),%rsp
972         movaps  %xmm6,(%rsp)
973         movaps  %xmm7,0x10(%rsp)
974         movaps  %xmm8,0x20(%rsp)
975         movaps  %xmm9,0x30(%rsp)
976         movaps  %xmm10,0x40(%rsp)
977         movaps  %xmm11,0x50(%rsp)
978         movaps  %xmm12,-0x78(%rax)
979         movaps  %xmm13,-0x68(%rax)
980         movaps  %xmm14,-0x58(%rax)
981         movaps  %xmm15,-0x48(%rax)
982 ___
983 $code.=<<___;
984         # stack layout
985         #
986         # +0    output sink
987         # +16   input sink [original %rsp and $num]
988         # +32   counters
989         # +64   distances between inputs and outputs
990         # +128  off-load area for @inp[0..3]
991         # +192  IV/input offload
992
993         sub     \$256,%rsp
994         and     \$-256,%rsp
995         sub     \$192,%rsp
996         mov     %rax,16(%rsp)                   # original %rsp
997 .cfi_cfa_expression     %rsp+16,deref,+8
998
999 .Ldec8x_body:
1000         vzeroupper
1001         vmovdqu ($key),$zero                    # 0-round key
1002         lea     0x78($key),$key                 # size optimization
1003         lea     40*4($inp),$inp
1004         shr     \$1,$num
1005
1006 .Ldec8x_loop_grande:
1007         #mov    $num,24(%rsp)                   # original $num
1008         xor     $num,$num
1009 ___
1010 for($i=0;$i<8;$i++) {
1011   my $temp = $i ? $offload : $offset;
1012     $code.=<<___;
1013         mov     `40*$i+16-40*4`($inp),$one      # borrow $one for number of blocks
1014         mov     `40*$i+0-40*4`($inp),@ptr[$i]   # input pointer
1015         cmp     $num,$one
1016         mov     `40*$i+8-40*4`($inp),$temp      # output pointer
1017         cmovg   $one,$num                       # find maximum
1018         test    $one,$one
1019         vmovdqu `40*$i+24-40*4`($inp),@out[$i]  # load IV
1020         mov     $one,`32+4*$i`(%rsp)            # initialize counters
1021         cmovle  %rsp,@ptr[$i]                   # cancel input
1022         sub     @ptr[$i],$temp                  # distance between input and output
1023         mov     $temp,`64+8*$i`(%rsp)           # initialize distances
1024         vmovdqu @out[$i],`192+16*$i`(%rsp)      # offload IV
1025 ___
1026 }
1027 $code.=<<___;
1028         test    $num,$num
1029         jz      .Ldec8x_done
1030
1031         vmovups 0x10-0x78($key),$rndkey1
1032         vmovups 0x20-0x78($key),$rndkey0
1033         mov     0xf0-0x78($key),$rounds
1034          lea    192+128(%rsp),$offload          # offload area
1035
1036         vmovdqu (@ptr[0]),@out[0]               # load inputs
1037         vmovdqu (@ptr[1]),@out[1]
1038         vmovdqu (@ptr[2]),@out[2]
1039         vmovdqu (@ptr[3]),@out[3]
1040         vmovdqu (@ptr[4]),@out[4]
1041         vmovdqu (@ptr[5]),@out[5]
1042         vmovdqu (@ptr[6]),@out[6]
1043         vmovdqu (@ptr[7]),@out[7]
1044         vmovdqu @out[0],0x00($offload)          # offload inputs
1045         vpxor   $zero,@out[0],@out[0]           # xor inputs with 0-round
1046         vmovdqu @out[1],0x10($offload)
1047         vpxor   $zero,@out[1],@out[1]
1048         vmovdqu @out[2],0x20($offload)
1049         vpxor   $zero,@out[2],@out[2]
1050         vmovdqu @out[3],0x30($offload)
1051         vpxor   $zero,@out[3],@out[3]
1052         vmovdqu @out[4],0x40($offload)
1053         vpxor   $zero,@out[4],@out[4]
1054         vmovdqu @out[5],0x50($offload)
1055         vpxor   $zero,@out[5],@out[5]
1056         vmovdqu @out[6],0x60($offload)
1057         vpxor   $zero,@out[6],@out[6]
1058         vmovdqu @out[7],0x70($offload)
1059         vpxor   $zero,@out[7],@out[7]
1060         xor     \$0x80,$offload
1061         mov     \$1,$one                        # constant of 1
1062         jmp     .Loop_dec8x
1063
1064 .align  32
1065 .Loop_dec8x:
1066 ___
1067 for($i=0;$i<8;$i++) {
1068 my $rndkey=($i&1)?$rndkey0:$rndkey1;
1069 $code.=<<___;
1070         vaesdec         $rndkey,@out[0],@out[0]
1071          cmp            32+4*$i(%rsp),$one
1072 ___
1073 $code.=<<___ if ($i);
1074          mov            64+8*$i(%rsp),$offset
1075 ___
1076 $code.=<<___;
1077         vaesdec         $rndkey,@out[1],@out[1]
1078         prefetcht0      31(@ptr[$i])                    # prefetch input
1079         vaesdec         $rndkey,@out[2],@out[2]
1080 ___
1081 $code.=<<___ if ($i>1);
1082         prefetcht0      15(@ptr[$i-2])                  # prefetch output
1083 ___
1084 $code.=<<___;
1085         vaesdec         $rndkey,@out[3],@out[3]
1086          lea            (@ptr[$i],$offset),$offset
1087          cmovge         %rsp,@ptr[$i]                   # cancel input
1088         vaesdec         $rndkey,@out[4],@out[4]
1089          cmovg          %rsp,$offset                    # sink output
1090         vaesdec         $rndkey,@out[5],@out[5]
1091          sub            @ptr[$i],$offset
1092         vaesdec         $rndkey,@out[6],@out[6]
1093          vmovdqu        16(@ptr[$i]),@inp[$i%4]         # load input
1094          mov            $offset,64+8*$i(%rsp)
1095         vaesdec         $rndkey,@out[7],@out[7]
1096         vmovups         `16*(3+$i)-0x78`($key),$rndkey
1097          lea            16(@ptr[$i],$offset),@ptr[$i]   # switch to output
1098 ___
1099 $code.=<<___ if ($i<4);
1100          vmovdqu        @inp[$i%4],`128+16*$i`(%rsp)    # off-load
1101 ___
1102 }
1103 $code.=<<___;
1104          vmovdqu        32(%rsp),$counters
1105         prefetcht0      15(@ptr[$i-2])                  # prefetch output
1106         prefetcht0      15(@ptr[$i-1])
1107         cmp     \$11,$rounds
1108         jb      .Ldec8x_tail
1109
1110         vaesdec         $rndkey1,@out[0],@out[0]
1111         vaesdec         $rndkey1,@out[1],@out[1]
1112         vaesdec         $rndkey1,@out[2],@out[2]
1113         vaesdec         $rndkey1,@out[3],@out[3]
1114         vaesdec         $rndkey1,@out[4],@out[4]
1115         vaesdec         $rndkey1,@out[5],@out[5]
1116         vaesdec         $rndkey1,@out[6],@out[6]
1117         vaesdec         $rndkey1,@out[7],@out[7]
1118         vmovups         0xb0-0x78($key),$rndkey1
1119
1120         vaesdec         $rndkey0,@out[0],@out[0]
1121         vaesdec         $rndkey0,@out[1],@out[1]
1122         vaesdec         $rndkey0,@out[2],@out[2]
1123         vaesdec         $rndkey0,@out[3],@out[3]
1124         vaesdec         $rndkey0,@out[4],@out[4]
1125         vaesdec         $rndkey0,@out[5],@out[5]
1126         vaesdec         $rndkey0,@out[6],@out[6]
1127         vaesdec         $rndkey0,@out[7],@out[7]
1128         vmovups         0xc0-0x78($key),$rndkey0
1129         je      .Ldec8x_tail
1130
1131         vaesdec         $rndkey1,@out[0],@out[0]
1132         vaesdec         $rndkey1,@out[1],@out[1]
1133         vaesdec         $rndkey1,@out[2],@out[2]
1134         vaesdec         $rndkey1,@out[3],@out[3]
1135         vaesdec         $rndkey1,@out[4],@out[4]
1136         vaesdec         $rndkey1,@out[5],@out[5]
1137         vaesdec         $rndkey1,@out[6],@out[6]
1138         vaesdec         $rndkey1,@out[7],@out[7]
1139         vmovups         0xd0-0x78($key),$rndkey1
1140
1141         vaesdec         $rndkey0,@out[0],@out[0]
1142         vaesdec         $rndkey0,@out[1],@out[1]
1143         vaesdec         $rndkey0,@out[2],@out[2]
1144         vaesdec         $rndkey0,@out[3],@out[3]
1145         vaesdec         $rndkey0,@out[4],@out[4]
1146         vaesdec         $rndkey0,@out[5],@out[5]
1147         vaesdec         $rndkey0,@out[6],@out[6]
1148         vaesdec         $rndkey0,@out[7],@out[7]
1149         vmovups         0xe0-0x78($key),$rndkey0
1150
1151 .Ldec8x_tail:
1152         vaesdec         $rndkey1,@out[0],@out[0]
1153          vpxor          $zero,$zero,$zero
1154         vaesdec         $rndkey1,@out[1],@out[1]
1155         vaesdec         $rndkey1,@out[2],@out[2]
1156          vpcmpgtd       $zero,$counters,$zero
1157         vaesdec         $rndkey1,@out[3],@out[3]
1158         vaesdec         $rndkey1,@out[4],@out[4]
1159          vpaddd         $counters,$zero,$zero           # decrement counters
1160          vmovdqu        48(%rsp),$counters
1161         vaesdec         $rndkey1,@out[5],@out[5]
1162          mov            64(%rsp),$offset                # pre-load 1st offset
1163         vaesdec         $rndkey1,@out[6],@out[6]
1164         vaesdec         $rndkey1,@out[7],@out[7]
1165         vmovups         0x10-0x78($key),$rndkey1
1166
1167         vaesdeclast     $rndkey0,@out[0],@out[0]
1168          vmovdqa        $zero,32(%rsp)                  # update counters
1169          vpxor          $zero,$zero,$zero
1170         vaesdeclast     $rndkey0,@out[1],@out[1]
1171         vpxor           0x00($offload),@out[0],@out[0]  # xor with IV
1172         vaesdeclast     $rndkey0,@out[2],@out[2]
1173         vpxor           0x10($offload),@out[1],@out[1]
1174          vpcmpgtd       $zero,$counters,$zero
1175         vaesdeclast     $rndkey0,@out[3],@out[3]
1176         vpxor           0x20($offload),@out[2],@out[2]
1177         vaesdeclast     $rndkey0,@out[4],@out[4]
1178         vpxor           0x30($offload),@out[3],@out[3]
1179          vpaddd         $zero,$counters,$counters       # decrement counters
1180          vmovdqu        -0x78($key),$zero               # 0-round
1181         vaesdeclast     $rndkey0,@out[5],@out[5]
1182         vpxor           0x40($offload),@out[4],@out[4]
1183         vaesdeclast     $rndkey0,@out[6],@out[6]
1184         vpxor           0x50($offload),@out[5],@out[5]
1185          vmovdqa        $counters,48(%rsp)              # update counters
1186         vaesdeclast     $rndkey0,@out[7],@out[7]
1187         vpxor           0x60($offload),@out[6],@out[6]
1188         vmovups         0x20-0x78($key),$rndkey0
1189
1190         vmovups         @out[0],-16(@ptr[0])            # write output
1191          sub            $offset,@ptr[0]                 # switch to input
1192          vmovdqu        128+0(%rsp),@out[0]
1193         vpxor           0x70($offload),@out[7],@out[7]
1194         vmovups         @out[1],-16(@ptr[1])
1195          sub            `64+1*8`(%rsp),@ptr[1]
1196          vmovdqu        @out[0],0x00($offload)
1197          vpxor          $zero,@out[0],@out[0]
1198          vmovdqu        128+16(%rsp),@out[1]
1199         vmovups         @out[2],-16(@ptr[2])
1200          sub            `64+2*8`(%rsp),@ptr[2]
1201          vmovdqu        @out[1],0x10($offload)
1202          vpxor          $zero,@out[1],@out[1]
1203          vmovdqu        128+32(%rsp),@out[2]
1204         vmovups         @out[3],-16(@ptr[3])
1205          sub            `64+3*8`(%rsp),@ptr[3]
1206          vmovdqu        @out[2],0x20($offload)
1207          vpxor          $zero,@out[2],@out[2]
1208          vmovdqu        128+48(%rsp),@out[3]
1209         vmovups         @out[4],-16(@ptr[4])
1210          sub            `64+4*8`(%rsp),@ptr[4]
1211          vmovdqu        @out[3],0x30($offload)
1212          vpxor          $zero,@out[3],@out[3]
1213          vmovdqu        @inp[0],0x40($offload)
1214          vpxor          @inp[0],$zero,@out[4]
1215         vmovups         @out[5],-16(@ptr[5])
1216          sub            `64+5*8`(%rsp),@ptr[5]
1217          vmovdqu        @inp[1],0x50($offload)
1218          vpxor          @inp[1],$zero,@out[5]
1219         vmovups         @out[6],-16(@ptr[6])
1220          sub            `64+6*8`(%rsp),@ptr[6]
1221          vmovdqu        @inp[2],0x60($offload)
1222          vpxor          @inp[2],$zero,@out[6]
1223         vmovups         @out[7],-16(@ptr[7])
1224          sub            `64+7*8`(%rsp),@ptr[7]
1225          vmovdqu        @inp[3],0x70($offload)
1226          vpxor          @inp[3],$zero,@out[7]
1227
1228         xor     \$128,$offload
1229         dec     $num
1230         jnz     .Loop_dec8x
1231
1232         mov     16(%rsp),%rax                   # original %rsp
1233 .cfi_def_cfa    %rax,8
1234         #mov    24(%rsp),$num
1235         #lea    `40*8`($inp),$inp
1236         #dec    $num
1237         #jnz    .Ldec8x_loop_grande
1238
1239 .Ldec8x_done:
1240         vzeroupper
1241 ___
1242 $code.=<<___ if ($win64);
1243         movaps  -0xd8(%rax),%xmm6
1244         movaps  -0xc8(%rax),%xmm7
1245         movaps  -0xb8(%rax),%xmm8
1246         movaps  -0xa8(%rax),%xmm9
1247         movaps  -0x98(%rax),%xmm10
1248         movaps  -0x88(%rax),%xmm11
1249         movaps  -0x78(%rax),%xmm12
1250         movaps  -0x68(%rax),%xmm13
1251         movaps  -0x58(%rax),%xmm14
1252         movaps  -0x48(%rax),%xmm15
1253 ___
1254 $code.=<<___;
1255         mov     -48(%rax),%r15
1256 .cfi_restore    %r15
1257         mov     -40(%rax),%r14
1258 .cfi_restore    %r14
1259         mov     -32(%rax),%r13
1260 .cfi_restore    %r13
1261         mov     -24(%rax),%r12
1262 .cfi_restore    %r12
1263         mov     -16(%rax),%rbp
1264 .cfi_restore    %rbp
1265         mov     -8(%rax),%rbx
1266 .cfi_restore    %rbx
1267         lea     (%rax),%rsp
1268 .cfi_def_cfa_register   %rsp
1269 .Ldec8x_epilogue:
1270         ret
1271 .cfi_endproc
1272 .size   aesni_multi_cbc_decrypt_avx,.-aesni_multi_cbc_decrypt_avx
1273 ___
1274                                                 }}}
1275
1276 if ($win64) {
1277 # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame,
1278 #               CONTEXT *context,DISPATCHER_CONTEXT *disp)
1279 $rec="%rcx";
1280 $frame="%rdx";
1281 $context="%r8";
1282 $disp="%r9";
1283
1284 $code.=<<___;
1285 .extern __imp_RtlVirtualUnwind
1286 .type   se_handler,\@abi-omnipotent
1287 .align  16
1288 se_handler:
1289         push    %rsi
1290         push    %rdi
1291         push    %rbx
1292         push    %rbp
1293         push    %r12
1294         push    %r13
1295         push    %r14
1296         push    %r15
1297         pushfq
1298         sub     \$64,%rsp
1299
1300         mov     120($context),%rax      # pull context->Rax
1301         mov     248($context),%rbx      # pull context->Rip
1302
1303         mov     8($disp),%rsi           # disp->ImageBase
1304         mov     56($disp),%r11          # disp->HandlerData
1305
1306         mov     0(%r11),%r10d           # HandlerData[0]
1307         lea     (%rsi,%r10),%r10        # prologue label
1308         cmp     %r10,%rbx               # context->Rip<.Lprologue
1309         jb      .Lin_prologue
1310
1311         mov     152($context),%rax      # pull context->Rsp
1312
1313         mov     4(%r11),%r10d           # HandlerData[1]
1314         lea     (%rsi,%r10),%r10        # epilogue label
1315         cmp     %r10,%rbx               # context->Rip>=.Lepilogue
1316         jae     .Lin_prologue
1317
1318         mov     16(%rax),%rax           # pull saved stack pointer
1319
1320         mov     -8(%rax),%rbx
1321         mov     -16(%rax),%rbp
1322         mov     -24(%rax),%r12
1323         mov     -32(%rax),%r13
1324         mov     -40(%rax),%r14
1325         mov     -48(%rax),%r15
1326         mov     %rbx,144($context)      # restore context->Rbx
1327         mov     %rbp,160($context)      # restore context->Rbp
1328         mov     %r12,216($context)      # restore context->R12
1329         mov     %r13,224($context)      # restore context->R13
1330         mov     %r14,232($context)      # restore context->R14
1331         mov     %r15,240($context)      # restore context->R15
1332
1333         lea     -56-10*16(%rax),%rsi
1334         lea     512($context),%rdi      # &context.Xmm6
1335         mov     \$20,%ecx
1336         .long   0xa548f3fc              # cld; rep movsq
1337
1338 .Lin_prologue:
1339         mov     8(%rax),%rdi
1340         mov     16(%rax),%rsi
1341         mov     %rax,152($context)      # restore context->Rsp
1342         mov     %rsi,168($context)      # restore context->Rsi
1343         mov     %rdi,176($context)      # restore context->Rdi
1344
1345         mov     40($disp),%rdi          # disp->ContextRecord
1346         mov     $context,%rsi           # context
1347         mov     \$154,%ecx              # sizeof(CONTEXT)
1348         .long   0xa548f3fc              # cld; rep movsq
1349
1350         mov     $disp,%rsi
1351         xor     %rcx,%rcx               # arg1, UNW_FLAG_NHANDLER
1352         mov     8(%rsi),%rdx            # arg2, disp->ImageBase
1353         mov     0(%rsi),%r8             # arg3, disp->ControlPc
1354         mov     16(%rsi),%r9            # arg4, disp->FunctionEntry
1355         mov     40(%rsi),%r10           # disp->ContextRecord
1356         lea     56(%rsi),%r11           # &disp->HandlerData
1357         lea     24(%rsi),%r12           # &disp->EstablisherFrame
1358         mov     %r10,32(%rsp)           # arg5
1359         mov     %r11,40(%rsp)           # arg6
1360         mov     %r12,48(%rsp)           # arg7
1361         mov     %rcx,56(%rsp)           # arg8, (NULL)
1362         call    *__imp_RtlVirtualUnwind(%rip)
1363
1364         mov     \$1,%eax                # ExceptionContinueSearch
1365         add     \$64,%rsp
1366         popfq
1367         pop     %r15
1368         pop     %r14
1369         pop     %r13
1370         pop     %r12
1371         pop     %rbp
1372         pop     %rbx
1373         pop     %rdi
1374         pop     %rsi
1375         ret
1376 .size   se_handler,.-se_handler
1377
1378 .section        .pdata
1379 .align  4
1380         .rva    .LSEH_begin_aesni_multi_cbc_encrypt
1381         .rva    .LSEH_end_aesni_multi_cbc_encrypt
1382         .rva    .LSEH_info_aesni_multi_cbc_encrypt
1383         .rva    .LSEH_begin_aesni_multi_cbc_decrypt
1384         .rva    .LSEH_end_aesni_multi_cbc_decrypt
1385         .rva    .LSEH_info_aesni_multi_cbc_decrypt
1386 ___
1387 $code.=<<___ if ($avx);
1388         .rva    .LSEH_begin_aesni_multi_cbc_encrypt_avx
1389         .rva    .LSEH_end_aesni_multi_cbc_encrypt_avx
1390         .rva    .LSEH_info_aesni_multi_cbc_encrypt_avx
1391         .rva    .LSEH_begin_aesni_multi_cbc_decrypt_avx
1392         .rva    .LSEH_end_aesni_multi_cbc_decrypt_avx
1393         .rva    .LSEH_info_aesni_multi_cbc_decrypt_avx
1394 ___
1395 $code.=<<___;
1396 .section        .xdata
1397 .align  8
1398 .LSEH_info_aesni_multi_cbc_encrypt:
1399         .byte   9,0,0,0
1400         .rva    se_handler
1401         .rva    .Lenc4x_body,.Lenc4x_epilogue           # HandlerData[]
1402 .LSEH_info_aesni_multi_cbc_decrypt:
1403         .byte   9,0,0,0
1404         .rva    se_handler
1405         .rva    .Ldec4x_body,.Ldec4x_epilogue           # HandlerData[]
1406 ___
1407 $code.=<<___ if ($avx);
1408 .LSEH_info_aesni_multi_cbc_encrypt_avx:
1409         .byte   9,0,0,0
1410         .rva    se_handler
1411         .rva    .Lenc8x_body,.Lenc8x_epilogue           # HandlerData[]
1412 .LSEH_info_aesni_multi_cbc_decrypt_avx:
1413         .byte   9,0,0,0
1414         .rva    se_handler
1415         .rva    .Ldec8x_body,.Ldec8x_epilogue           # HandlerData[]
1416 ___
1417 }
1418 ####################################################################
1419
1420 sub rex {
1421   local *opcode=shift;
1422   my ($dst,$src)=@_;
1423   my $rex=0;
1424
1425     $rex|=0x04                  if($dst>=8);
1426     $rex|=0x01                  if($src>=8);
1427     push @opcode,$rex|0x40      if($rex);
1428 }
1429
1430 sub aesni {
1431   my $line=shift;
1432   my @opcode=(0x66);
1433
1434     if ($line=~/(aeskeygenassist)\s+\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) {
1435         rex(\@opcode,$4,$3);
1436         push @opcode,0x0f,0x3a,0xdf;
1437         push @opcode,0xc0|($3&7)|(($4&7)<<3);   # ModR/M
1438         my $c=$2;
1439         push @opcode,$c=~/^0/?oct($c):$c;
1440         return ".byte\t".join(',',@opcode);
1441     }
1442     elsif ($line=~/(aes[a-z]+)\s+%xmm([0-9]+),\s*%xmm([0-9]+)/) {
1443         my %opcodelet = (
1444                 "aesimc" => 0xdb,
1445                 "aesenc" => 0xdc,       "aesenclast" => 0xdd,
1446                 "aesdec" => 0xde,       "aesdeclast" => 0xdf
1447         );
1448         return undef if (!defined($opcodelet{$1}));
1449         rex(\@opcode,$3,$2);
1450         push @opcode,0x0f,0x38,$opcodelet{$1};
1451         push @opcode,0xc0|($2&7)|(($3&7)<<3);   # ModR/M
1452         return ".byte\t".join(',',@opcode);
1453     }
1454     elsif ($line=~/(aes[a-z]+)\s+([0x1-9a-fA-F]*)\(%rsp\),\s*%xmm([0-9]+)/) {
1455         my %opcodelet = (
1456                 "aesenc" => 0xdc,       "aesenclast" => 0xdd,
1457                 "aesdec" => 0xde,       "aesdeclast" => 0xdf
1458         );
1459         return undef if (!defined($opcodelet{$1}));
1460         my $off = $2;
1461         push @opcode,0x44 if ($3>=8);
1462         push @opcode,0x0f,0x38,$opcodelet{$1};
1463         push @opcode,0x44|(($3&7)<<3),0x24;     # ModR/M
1464         push @opcode,($off=~/^0/?oct($off):$off)&0xff;
1465         return ".byte\t".join(',',@opcode);
1466     }
1467     return $line;
1468 }
1469
1470 $code =~ s/\`([^\`]*)\`/eval($1)/gem;
1471 $code =~ s/\b(aes.*%xmm[0-9]+).*$/aesni($1)/gem;
1472
1473 print $code;
1474 close STDOUT;