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