aes/asm/aesv8-armx.pl: ~20% improvement on ThunderX2.
[openssl.git] / crypto / aes / asm / aesv8-armx.pl
1 #! /usr/bin/env perl
2 # Copyright 2014-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 # This module implements support for ARMv8 AES instructions. The
18 # module is endian-agnostic in sense that it supports both big- and
19 # little-endian cases. As does it support both 32- and 64-bit modes
20 # of operation. Latter is achieved by limiting amount of utilized
21 # registers to 16, which implies additional NEON load and integer
22 # instructions. This has no effect on mighty Apple A7, where results
23 # are literally equal to the theoretical estimates based on AES
24 # instruction latencies and issue rates. On Cortex-A53, an in-order
25 # execution core, this costs up to 10-15%, which is partially
26 # compensated by implementing dedicated code path for 128-bit
27 # CBC encrypt case. On Cortex-A57 parallelizable mode performance
28 # seems to be limited by sheer amount of NEON instructions...
29 #
30 # April 2019
31 #
32 # Key to performance of parallelize-able modes is round instruction
33 # interleaving. But which factor to use? There is optimal one for
34 # each combination of instruction latency and issue rate, beyond
35 # which increasing interleave factor doesn't pay off. While on cons
36 # side we have code size increase and resource waste on platforms for
37 # which interleave factor is too high. In other words you want it to
38 # be just right. So far interleave factor of 3x was serving well all
39 # platforms. But for ThunderX2 optimal interleave factor was measured
40 # to be 5x...
41 #
42 # Performance in cycles per byte processed with 128-bit key:
43 #
44 #               CBC enc         CBC dec         CTR
45 # Apple A7      2.39            1.20            1.20
46 # Cortex-A53    1.32            1.17/1.29(**)   1.36/1.46
47 # Cortex-A57(*) 1.95            0.82/0.85       0.89/0.93
48 # Cortex-A72    1.33            0.85/0.88       0.92/0.96
49 # Denver        1.96            0.65/0.86       0.76/0.80
50 # Mongoose      1.33            1.23/1.20       1.30/1.20
51 # Kryo          1.26            0.87/0.94       1.00/1.00
52 # ThunderX2     5.95            1.25            1.30
53 #
54 # (*)   original 3.64/1.34/1.32 results were for r0p0 revision
55 #       and are still same even for updated module;
56 # (**)  numbers after slash are for 32-bit code, which is 3x-
57 #       interleaved;
58
59 $flavour = shift;
60 $output  = shift;
61
62 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
63 ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
64 ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or
65 die "can't locate arm-xlate.pl";
66
67 open OUT,"| \"$^X\" $xlate $flavour $output";
68 *STDOUT=*OUT;
69
70 $prefix="aes_v8";
71
72 $_byte = ($flavour =~ /win/ ? "DCB" : ".byte");
73
74 $code=<<___;
75 #include "arm_arch.h"
76
77 #if __ARM_MAX_ARCH__>=7
78 ___
79 $code.=".arch   armv8-a+crypto\n.text\n"                if ($flavour =~ /64/);
80 $code.=<<___                                            if ($flavour !~ /64/);
81 .arch   armv7-a // don't confuse not-so-latest binutils with argv8 :-)
82 .fpu    neon
83 #ifdef  __thumb2__
84 .syntax unified
85 .thumb
86 # define INST(a,b,c,d)  $_byte  c,d|0xc,a,b
87 #else
88 .code   32
89 # define INST(a,b,c,d)  $_byte  a,b,c,d
90 #endif
91
92 .text
93 ___
94
95 # Assembler mnemonics are an eclectic mix of 32- and 64-bit syntax,
96 # NEON is mostly 32-bit mnemonics, integer - mostly 64. Goal is to
97 # maintain both 32- and 64-bit codes within single module and
98 # transliterate common code to either flavour with regex vodoo.
99 #
100 {{{
101 my ($inp,$bits,$out,$ptr,$rounds)=("x0","w1","x2","x3","w12");
102 my ($zero,$rcon,$mask,$in0,$in1,$tmp,$key)=
103         $flavour=~/64/? map("q$_",(0..6)) : map("q$_",(0..3,8..10));
104
105
106 $code.=<<___;
107 .align  5
108 .Lrcon:
109 .long   0x01,0x01,0x01,0x01
110 .long   0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d     // rotate-n-splat
111 .long   0x1b,0x1b,0x1b,0x1b
112
113 .globl  ${prefix}_set_encrypt_key
114 .type   ${prefix}_set_encrypt_key,%function
115 .align  5
116 ${prefix}_set_encrypt_key:
117 .Lenc_key:
118 ___
119 $code.=<<___    if ($flavour =~ /64/);
120         stp     x29,x30,[sp,#-16]!
121         add     x29,sp,#0
122 ___
123 $code.=<<___;
124         mov     $ptr,#-1
125         cmp     $inp,#0
126         b.eq    .Lenc_key_abort
127         cmp     $out,#0
128         b.eq    .Lenc_key_abort
129         mov     $ptr,#-2
130         cmp     $bits,#128
131         b.lt    .Lenc_key_abort
132         cmp     $bits,#256
133         b.gt    .Lenc_key_abort
134         tst     $bits,#0x3f
135         b.ne    .Lenc_key_abort
136
137         adr     $ptr,.Lrcon
138         cmp     $bits,#192
139
140         veor    $zero,$zero,$zero
141         vld1.8  {$in0},[$inp],#16
142         mov     $bits,#8                // reuse $bits
143         vld1.32 {$rcon,$mask},[$ptr],#32
144
145         b.lt    .Loop128
146         b.eq    .L192
147         b       .L256
148
149 .align  4
150 .Loop128:
151         vtbl.8  $key,{$in0},$mask
152         vext.8  $tmp,$zero,$in0,#12
153         vst1.32 {$in0},[$out],#16
154         aese    $key,$zero
155         subs    $bits,$bits,#1
156
157         veor    $in0,$in0,$tmp
158         vext.8  $tmp,$zero,$tmp,#12
159         veor    $in0,$in0,$tmp
160         vext.8  $tmp,$zero,$tmp,#12
161          veor   $key,$key,$rcon
162         veor    $in0,$in0,$tmp
163         vshl.u8 $rcon,$rcon,#1
164         veor    $in0,$in0,$key
165         b.ne    .Loop128
166
167         vld1.32 {$rcon},[$ptr]
168
169         vtbl.8  $key,{$in0},$mask
170         vext.8  $tmp,$zero,$in0,#12
171         vst1.32 {$in0},[$out],#16
172         aese    $key,$zero
173
174         veor    $in0,$in0,$tmp
175         vext.8  $tmp,$zero,$tmp,#12
176         veor    $in0,$in0,$tmp
177         vext.8  $tmp,$zero,$tmp,#12
178          veor   $key,$key,$rcon
179         veor    $in0,$in0,$tmp
180         vshl.u8 $rcon,$rcon,#1
181         veor    $in0,$in0,$key
182
183         vtbl.8  $key,{$in0},$mask
184         vext.8  $tmp,$zero,$in0,#12
185         vst1.32 {$in0},[$out],#16
186         aese    $key,$zero
187
188         veor    $in0,$in0,$tmp
189         vext.8  $tmp,$zero,$tmp,#12
190         veor    $in0,$in0,$tmp
191         vext.8  $tmp,$zero,$tmp,#12
192          veor   $key,$key,$rcon
193         veor    $in0,$in0,$tmp
194         veor    $in0,$in0,$key
195         vst1.32 {$in0},[$out]
196         add     $out,$out,#0x50
197
198         mov     $rounds,#10
199         b       .Ldone
200
201 .align  4
202 .L192:
203         vld1.8  {$in1},[$inp],#8
204         vmov.i8 $key,#8                 // borrow $key
205         vst1.32 {$in0},[$out],#16
206         vsub.i8 $mask,$mask,$key        // adjust the mask
207
208 .Loop192:
209         vtbl.8  $key,{$in1},$mask
210         vext.8  $tmp,$zero,$in0,#12
211         vst1.32 {$in1},[$out],#8
212         aese    $key,$zero
213         subs    $bits,$bits,#1
214
215         veor    $in0,$in0,$tmp
216         vext.8  $tmp,$zero,$tmp,#12
217         veor    $in0,$in0,$tmp
218         vext.8  $tmp,$zero,$tmp,#12
219         veor    $in0,$in0,$tmp
220
221         vdup.32 $tmp,${in0}[3]
222         veor    $tmp,$tmp,$in1
223          veor   $key,$key,$rcon
224         vext.8  $in1,$zero,$in1,#12
225         vshl.u8 $rcon,$rcon,#1
226         veor    $in1,$in1,$tmp
227         veor    $in0,$in0,$key
228         veor    $in1,$in1,$key
229         vst1.32 {$in0},[$out],#16
230         b.ne    .Loop192
231
232         mov     $rounds,#12
233         add     $out,$out,#0x20
234         b       .Ldone
235
236 .align  4
237 .L256:
238         vld1.8  {$in1},[$inp]
239         mov     $bits,#7
240         mov     $rounds,#14
241         vst1.32 {$in0},[$out],#16
242
243 .Loop256:
244         vtbl.8  $key,{$in1},$mask
245         vext.8  $tmp,$zero,$in0,#12
246         vst1.32 {$in1},[$out],#16
247         aese    $key,$zero
248         subs    $bits,$bits,#1
249
250         veor    $in0,$in0,$tmp
251         vext.8  $tmp,$zero,$tmp,#12
252         veor    $in0,$in0,$tmp
253         vext.8  $tmp,$zero,$tmp,#12
254          veor   $key,$key,$rcon
255         veor    $in0,$in0,$tmp
256         vshl.u8 $rcon,$rcon,#1
257         veor    $in0,$in0,$key
258         vst1.32 {$in0},[$out],#16
259         b.eq    .Ldone
260
261         vdup.32 $key,${in0}[3]          // just splat
262         vext.8  $tmp,$zero,$in1,#12
263         aese    $key,$zero
264
265         veor    $in1,$in1,$tmp
266         vext.8  $tmp,$zero,$tmp,#12
267         veor    $in1,$in1,$tmp
268         vext.8  $tmp,$zero,$tmp,#12
269         veor    $in1,$in1,$tmp
270
271         veor    $in1,$in1,$key
272         b       .Loop256
273
274 .Ldone:
275         str     $rounds,[$out]
276         mov     $ptr,#0
277
278 .Lenc_key_abort:
279         mov     x0,$ptr                 // return value
280         `"ldr   x29,[sp],#16"           if ($flavour =~ /64/)`
281         ret
282 .size   ${prefix}_set_encrypt_key,.-${prefix}_set_encrypt_key
283
284 .globl  ${prefix}_set_decrypt_key
285 .type   ${prefix}_set_decrypt_key,%function
286 .align  5
287 ${prefix}_set_decrypt_key:
288 ___
289 $code.=<<___    if ($flavour =~ /64/);
290         .inst   0xd503233f              // paciasp
291         stp     x29,x30,[sp,#-16]!
292         add     x29,sp,#0
293 ___
294 $code.=<<___    if ($flavour !~ /64/);
295         stmdb   sp!,{r4,lr}
296 ___
297 $code.=<<___;
298         bl      .Lenc_key
299
300         cmp     x0,#0
301         b.ne    .Ldec_key_abort
302
303         sub     $out,$out,#240          // restore original $out
304         mov     x4,#-16
305         add     $inp,$out,x12,lsl#4     // end of key schedule
306
307         vld1.32 {v0.16b},[$out]
308         vld1.32 {v1.16b},[$inp]
309         vst1.32 {v0.16b},[$inp],x4
310         vst1.32 {v1.16b},[$out],#16
311
312 .Loop_imc:
313         vld1.32 {v0.16b},[$out]
314         vld1.32 {v1.16b},[$inp]
315         aesimc  v0.16b,v0.16b
316         aesimc  v1.16b,v1.16b
317         vst1.32 {v0.16b},[$inp],x4
318         vst1.32 {v1.16b},[$out],#16
319         cmp     $inp,$out
320         b.hi    .Loop_imc
321
322         vld1.32 {v0.16b},[$out]
323         aesimc  v0.16b,v0.16b
324         vst1.32 {v0.16b},[$inp]
325
326         eor     x0,x0,x0                // return value
327 .Ldec_key_abort:
328 ___
329 $code.=<<___    if ($flavour !~ /64/);
330         ldmia   sp!,{r4,pc}
331 ___
332 $code.=<<___    if ($flavour =~ /64/);
333         ldp     x29,x30,[sp],#16
334         .inst   0xd50323bf              // autiasp
335         ret
336 ___
337 $code.=<<___;
338 .size   ${prefix}_set_decrypt_key,.-${prefix}_set_decrypt_key
339 ___
340 }}}
341 {{{
342 sub gen_block () {
343 my $dir = shift;
344 my ($e,$mc) = $dir eq "en" ? ("e","mc") : ("d","imc");
345 my ($inp,$out,$key)=map("x$_",(0..2));
346 my $rounds="w3";
347 my ($rndkey0,$rndkey1,$inout)=map("q$_",(0..3));
348
349 $code.=<<___;
350 .globl  ${prefix}_${dir}crypt
351 .type   ${prefix}_${dir}crypt,%function
352 .align  5
353 ${prefix}_${dir}crypt:
354         ldr     $rounds,[$key,#240]
355         vld1.32 {$rndkey0},[$key],#16
356         vld1.8  {$inout},[$inp]
357         sub     $rounds,$rounds,#2
358         vld1.32 {$rndkey1},[$key],#16
359
360 .Loop_${dir}c:
361         aes$e   $inout,$rndkey0
362         aes$mc  $inout,$inout
363         vld1.32 {$rndkey0},[$key],#16
364         subs    $rounds,$rounds,#2
365         aes$e   $inout,$rndkey1
366         aes$mc  $inout,$inout
367         vld1.32 {$rndkey1},[$key],#16
368         b.gt    .Loop_${dir}c
369
370         aes$e   $inout,$rndkey0
371         aes$mc  $inout,$inout
372         vld1.32 {$rndkey0},[$key]
373         aes$e   $inout,$rndkey1
374         veor    $inout,$inout,$rndkey0
375
376         vst1.8  {$inout},[$out]
377         ret
378 .size   ${prefix}_${dir}crypt,.-${prefix}_${dir}crypt
379 ___
380 }
381 &gen_block("en");
382 &gen_block("de");
383 }}}
384 {{{
385 my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4)); my $enc="w5";
386 my ($rounds,$cnt,$key_,$step,$step1)=($enc,"w6","x7","x8","x12");
387 my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7));
388
389 my ($dat,$tmp,$rndzero_n_last)=($dat0,$tmp0,$tmp1);
390 my ($key4,$key5,$key6,$key7)=("x6","x12","x14",$key);
391
392 ### q8-q15      preloaded key schedule
393
394 $code.=<<___;
395 .globl  ${prefix}_cbc_encrypt
396 .type   ${prefix}_cbc_encrypt,%function
397 .align  5
398 ${prefix}_cbc_encrypt:
399 ___
400 $code.=<<___    if ($flavour =~ /64/);
401         stp     x29,x30,[sp,#-16]!
402         add     x29,sp,#0
403 ___
404 $code.=<<___    if ($flavour !~ /64/);
405         mov     ip,sp
406         stmdb   sp!,{r4-r8,lr}
407         vstmdb  sp!,{d8-d15}            @ ABI specification says so
408         ldmia   ip,{r4-r5}              @ load remaining args
409 ___
410 $code.=<<___;
411         subs    $len,$len,#16
412         mov     $step,#16
413         b.lo    .Lcbc_abort
414         cclr    $step,eq
415
416         cmp     $enc,#0                 // en- or decrypting?
417         ldr     $rounds,[$key,#240]
418         and     $len,$len,#-16
419         vld1.8  {$ivec},[$ivp]
420         vld1.8  {$dat},[$inp],$step
421
422         vld1.32 {q8-q9},[$key]          // load key schedule...
423         sub     $rounds,$rounds,#6
424         add     $key_,$key,x5,lsl#4     // pointer to last 7 round keys
425         sub     $rounds,$rounds,#2
426         vld1.32 {q10-q11},[$key_],#32
427         vld1.32 {q12-q13},[$key_],#32
428         vld1.32 {q14-q15},[$key_],#32
429         vld1.32 {$rndlast},[$key_]
430
431         add     $key_,$key,#32
432         mov     $cnt,$rounds
433         b.eq    .Lcbc_dec
434
435         cmp     $rounds,#2
436         veor    $dat,$dat,$ivec
437         veor    $rndzero_n_last,q8,$rndlast
438         b.eq    .Lcbc_enc128
439
440         vld1.32 {$in0-$in1},[$key_]
441         add     $key_,$key,#16
442         add     $key4,$key,#16*4
443         add     $key5,$key,#16*5
444         aese    $dat,q8
445         aesmc   $dat,$dat
446         add     $key6,$key,#16*6
447         add     $key7,$key,#16*7
448         b       .Lenter_cbc_enc
449
450 .align  4
451 .Loop_cbc_enc:
452         aese    $dat,q8
453         aesmc   $dat,$dat
454          vst1.8 {$ivec},[$out],#16
455 .Lenter_cbc_enc:
456         aese    $dat,q9
457         aesmc   $dat,$dat
458         aese    $dat,$in0
459         aesmc   $dat,$dat
460         vld1.32 {q8},[$key4]
461         cmp     $rounds,#4
462         aese    $dat,$in1
463         aesmc   $dat,$dat
464         vld1.32 {q9},[$key5]
465         b.eq    .Lcbc_enc192
466
467         aese    $dat,q8
468         aesmc   $dat,$dat
469         vld1.32 {q8},[$key6]
470         aese    $dat,q9
471         aesmc   $dat,$dat
472         vld1.32 {q9},[$key7]
473         nop
474
475 .Lcbc_enc192:
476         aese    $dat,q8
477         aesmc   $dat,$dat
478          subs   $len,$len,#16
479         aese    $dat,q9
480         aesmc   $dat,$dat
481          cclr   $step,eq
482         aese    $dat,q10
483         aesmc   $dat,$dat
484         aese    $dat,q11
485         aesmc   $dat,$dat
486          vld1.8 {q8},[$inp],$step
487         aese    $dat,q12
488         aesmc   $dat,$dat
489          veor   q8,q8,$rndzero_n_last
490         aese    $dat,q13
491         aesmc   $dat,$dat
492          vld1.32 {q9},[$key_]           // re-pre-load rndkey[1]
493         aese    $dat,q14
494         aesmc   $dat,$dat
495         aese    $dat,q15
496         veor    $ivec,$dat,$rndlast
497         b.hs    .Loop_cbc_enc
498
499         vst1.8  {$ivec},[$out],#16
500         b       .Lcbc_done
501
502 .align  5
503 .Lcbc_enc128:
504         vld1.32 {$in0-$in1},[$key_]
505         aese    $dat,q8
506         aesmc   $dat,$dat
507         b       .Lenter_cbc_enc128
508 .Loop_cbc_enc128:
509         aese    $dat,q8
510         aesmc   $dat,$dat
511          vst1.8 {$ivec},[$out],#16
512 .Lenter_cbc_enc128:
513         aese    $dat,q9
514         aesmc   $dat,$dat
515          subs   $len,$len,#16
516         aese    $dat,$in0
517         aesmc   $dat,$dat
518          cclr   $step,eq
519         aese    $dat,$in1
520         aesmc   $dat,$dat
521         aese    $dat,q10
522         aesmc   $dat,$dat
523         aese    $dat,q11
524         aesmc   $dat,$dat
525          vld1.8 {q8},[$inp],$step
526         aese    $dat,q12
527         aesmc   $dat,$dat
528         aese    $dat,q13
529         aesmc   $dat,$dat
530         aese    $dat,q14
531         aesmc   $dat,$dat
532          veor   q8,q8,$rndzero_n_last
533         aese    $dat,q15
534         veor    $ivec,$dat,$rndlast
535         b.hs    .Loop_cbc_enc128
536
537         vst1.8  {$ivec},[$out],#16
538         b       .Lcbc_done
539 ___
540 {
541 my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9));
542
543 my ($dat3,$in3,$tmp3);  # used only in 64-bit mode
544 my ($dat4,$in4,$tmp4);
545 if ($flavour =~ /64/) {
546     ($dat2,$dat3,$dat4,$in2,$in3,$in4,$tmp3,$tmp4)=map("q$_",(16..23));
547 }
548
549 $code.=<<___;
550 .align  5
551 .Lcbc_dec:
552         vld1.8  {$dat2},[$inp],#16
553         subs    $len,$len,#32           // bias
554         add     $cnt,$rounds,#2
555         vorr    $in1,$dat,$dat
556         vorr    $dat1,$dat,$dat
557         vorr    $in2,$dat2,$dat2
558         b.lo    .Lcbc_dec_tail
559
560         vorr    $dat1,$dat2,$dat2
561         vld1.8  {$dat2},[$inp],#16
562         vorr    $in0,$dat,$dat
563         vorr    $in1,$dat1,$dat1
564         vorr    $in2,$dat2,$dat2
565 ___
566 $code.=<<___    if ($flavour =~ /64/);
567         cmp     $len,#32
568         b.lo    .Loop3x_cbc_dec
569
570         vld1.8  {$dat3},[$inp],#16
571         vld1.8  {$dat4},[$inp],#16
572         sub     $len,$len,#32           // bias
573         mov     $cnt,$rounds
574         vorr    $in3,$dat3,$dat3
575         vorr    $in4,$dat4,$dat4
576
577 .Loop5x_cbc_dec:
578         aesd    $dat0,q8
579         aesimc  $dat0,$dat0
580         aesd    $dat1,q8
581         aesimc  $dat1,$dat1
582         aesd    $dat2,q8
583         aesimc  $dat2,$dat2
584         aesd    $dat3,q8
585         aesimc  $dat3,$dat3
586         aesd    $dat4,q8
587         aesimc  $dat4,$dat4
588         vld1.32 {q8},[$key_],#16
589         subs    $cnt,$cnt,#2
590         aesd    $dat0,q9
591         aesimc  $dat0,$dat0
592         aesd    $dat1,q9
593         aesimc  $dat1,$dat1
594         aesd    $dat2,q9
595         aesimc  $dat2,$dat2
596         aesd    $dat3,q9
597         aesimc  $dat3,$dat3
598         aesd    $dat4,q9
599         aesimc  $dat4,$dat4
600         vld1.32 {q9},[$key_],#16
601         b.gt    .Loop5x_cbc_dec
602
603         aesd    $dat0,q8
604         aesimc  $dat0,$dat0
605         aesd    $dat1,q8
606         aesimc  $dat1,$dat1
607         aesd    $dat2,q8
608         aesimc  $dat2,$dat2
609         aesd    $dat3,q8
610         aesimc  $dat3,$dat3
611         aesd    $dat4,q8
612         aesimc  $dat4,$dat4
613          cmp    $len,#0x40              // because .Lcbc_tail4x
614          sub    $len,$len,#0x50
615
616         aesd    $dat0,q9
617         aesimc  $dat0,$dat0
618         aesd    $dat1,q9
619         aesimc  $dat1,$dat1
620         aesd    $dat2,q9
621         aesimc  $dat2,$dat2
622         aesd    $dat3,q9
623         aesimc  $dat3,$dat3
624         aesd    $dat4,q9
625         aesimc  $dat4,$dat4
626          csel   x6,xzr,$len,gt          // borrow x6, $cnt, "gt" is not typo
627          mov    $key_,$key
628
629         aesd    $dat0,q10
630         aesimc  $dat0,$dat0
631         aesd    $dat1,q10
632         aesimc  $dat1,$dat1
633         aesd    $dat2,q10
634         aesimc  $dat2,$dat2
635         aesd    $dat3,q10
636         aesimc  $dat3,$dat3
637         aesd    $dat4,q10
638         aesimc  $dat4,$dat4
639          add    $inp,$inp,x6            // $inp is adjusted in such way that
640                                         // at exit from the loop $dat1-$dat4
641                                         // are loaded with last "words"
642          add    x6,$len,#0x60           // because .Lcbc_tail4x
643
644         aesd    $dat0,q11
645         aesimc  $dat0,$dat0
646         aesd    $dat1,q11
647         aesimc  $dat1,$dat1
648         aesd    $dat2,q11
649         aesimc  $dat2,$dat2
650         aesd    $dat3,q11
651         aesimc  $dat3,$dat3
652         aesd    $dat4,q11
653         aesimc  $dat4,$dat4
654
655         aesd    $dat0,q12
656         aesimc  $dat0,$dat0
657         aesd    $dat1,q12
658         aesimc  $dat1,$dat1
659         aesd    $dat2,q12
660         aesimc  $dat2,$dat2
661         aesd    $dat3,q12
662         aesimc  $dat3,$dat3
663         aesd    $dat4,q12
664         aesimc  $dat4,$dat4
665
666         aesd    $dat0,q13
667         aesimc  $dat0,$dat0
668         aesd    $dat1,q13
669         aesimc  $dat1,$dat1
670         aesd    $dat2,q13
671         aesimc  $dat2,$dat2
672         aesd    $dat3,q13
673         aesimc  $dat3,$dat3
674         aesd    $dat4,q13
675         aesimc  $dat4,$dat4
676
677         aesd    $dat0,q14
678         aesimc  $dat0,$dat0
679         aesd    $dat1,q14
680         aesimc  $dat1,$dat1
681         aesd    $dat2,q14
682         aesimc  $dat2,$dat2
683         aesd    $dat3,q14
684         aesimc  $dat3,$dat3
685         aesd    $dat4,q14
686         aesimc  $dat4,$dat4
687
688          veor   $tmp0,$ivec,$rndlast
689         aesd    $dat0,q15
690          veor   $tmp1,$in0,$rndlast
691          vld1.8 {$in0},[$inp],#16
692         aesd    $dat1,q15
693          veor   $tmp2,$in1,$rndlast
694          vld1.8 {$in1},[$inp],#16
695         aesd    $dat2,q15
696          veor   $tmp3,$in2,$rndlast
697          vld1.8 {$in2},[$inp],#16
698         aesd    $dat3,q15
699          veor   $tmp4,$in3,$rndlast
700          vld1.8 {$in3},[$inp],#16
701         aesd    $dat4,q15
702          vorr   $ivec,$in4,$in4
703          vld1.8 {$in4},[$inp],#16
704         cbz     x6,.Lcbc_tail4x
705          vld1.32 {q8},[$key_],#16       // re-pre-load rndkey[0]
706         veor    $tmp0,$tmp0,$dat0
707          vorr   $dat0,$in0,$in0
708         veor    $tmp1,$tmp1,$dat1
709          vorr   $dat1,$in1,$in1
710         veor    $tmp2,$tmp2,$dat2
711          vorr   $dat2,$in2,$in2
712         veor    $tmp3,$tmp3,$dat3
713          vorr   $dat3,$in3,$in3
714         veor    $tmp4,$tmp4,$dat4
715         vst1.8  {$tmp0},[$out],#16
716          vorr   $dat4,$in4,$in4
717         vst1.8  {$tmp1},[$out],#16
718          mov    $cnt,$rounds
719         vst1.8  {$tmp2},[$out],#16
720          vld1.32 {q9},[$key_],#16       // re-pre-load rndkey[1]
721         vst1.8  {$tmp3},[$out],#16
722         vst1.8  {$tmp4},[$out],#16
723         b.hs    .Loop5x_cbc_dec
724
725         add     $len,$len,#0x50
726         cbz     $len,.Lcbc_done
727
728         add     $cnt,$rounds,#2
729         subs    $len,$len,#0x30
730         vorr    $dat0,$in2,$in2
731         vorr    $in0,$in2,$in2
732         vorr    $dat1,$in3,$in3
733         vorr    $in1,$in3,$in3
734         vorr    $dat2,$in4,$in4
735         vorr    $in2,$in4,$in4
736         b.lo    .Lcbc_dec_tail
737
738         b       .Loop3x_cbc_dec
739
740 .align  4
741 .Lcbc_tail4x:
742         veor    $tmp1,$tmp0,$dat1
743         veor    $tmp2,$tmp2,$dat2
744         veor    $tmp3,$tmp3,$dat3
745         veor    $tmp4,$tmp4,$dat4
746         vst1.8  {$tmp1},[$out],#16
747         vst1.8  {$tmp2},[$out],#16
748         vst1.8  {$tmp3},[$out],#16
749         vst1.8  {$tmp4},[$out],#16
750
751         b       .Lcbc_done
752 .align  4
753 ___
754 $code.=<<___;
755 .Loop3x_cbc_dec:
756         aesd    $dat0,q8
757         aesimc  $dat0,$dat0
758         aesd    $dat1,q8
759         aesimc  $dat1,$dat1
760         aesd    $dat2,q8
761         aesimc  $dat2,$dat2
762         vld1.32 {q8},[$key_],#16
763         subs    $cnt,$cnt,#2
764         aesd    $dat0,q9
765         aesimc  $dat0,$dat0
766         aesd    $dat1,q9
767         aesimc  $dat1,$dat1
768         aesd    $dat2,q9
769         aesimc  $dat2,$dat2
770         vld1.32 {q9},[$key_],#16
771         b.gt    .Loop3x_cbc_dec
772
773         aesd    $dat0,q8
774         aesimc  $dat0,$dat0
775         aesd    $dat1,q8
776         aesimc  $dat1,$dat1
777         aesd    $dat2,q8
778         aesimc  $dat2,$dat2
779          veor   $tmp0,$ivec,$rndlast
780          subs   $len,$len,#0x30
781          veor   $tmp1,$in0,$rndlast
782          mov.lo x6,$len                 // x6, $cnt, is zero at this point
783         aesd    $dat0,q9
784         aesimc  $dat0,$dat0
785         aesd    $dat1,q9
786         aesimc  $dat1,$dat1
787         aesd    $dat2,q9
788         aesimc  $dat2,$dat2
789          veor   $tmp2,$in1,$rndlast
790          add    $inp,$inp,x6            // $inp is adjusted in such way that
791                                         // at exit from the loop $dat1-$dat2
792                                         // are loaded with last "words"
793          vorr   $ivec,$in2,$in2
794          mov    $key_,$key
795         aesd    $dat0,q12
796         aesimc  $dat0,$dat0
797         aesd    $dat1,q12
798         aesimc  $dat1,$dat1
799         aesd    $dat2,q12
800         aesimc  $dat2,$dat2
801          vld1.8 {$in0},[$inp],#16
802         aesd    $dat0,q13
803         aesimc  $dat0,$dat0
804         aesd    $dat1,q13
805         aesimc  $dat1,$dat1
806         aesd    $dat2,q13
807         aesimc  $dat2,$dat2
808          vld1.8 {$in1},[$inp],#16
809         aesd    $dat0,q14
810         aesimc  $dat0,$dat0
811         aesd    $dat1,q14
812         aesimc  $dat1,$dat1
813         aesd    $dat2,q14
814         aesimc  $dat2,$dat2
815          vld1.8 {$in2},[$inp],#16
816         aesd    $dat0,q15
817         aesd    $dat1,q15
818         aesd    $dat2,q15
819          vld1.32 {q8},[$key_],#16       // re-pre-load rndkey[0]
820          add    $cnt,$rounds,#2
821         veor    $tmp0,$tmp0,$dat0
822         veor    $tmp1,$tmp1,$dat1
823         veor    $dat2,$dat2,$tmp2
824          vld1.32 {q9},[$key_],#16       // re-pre-load rndkey[1]
825         vst1.8  {$tmp0},[$out],#16
826          vorr   $dat0,$in0,$in0
827         vst1.8  {$tmp1},[$out],#16
828          vorr   $dat1,$in1,$in1
829         vst1.8  {$dat2},[$out],#16
830          vorr   $dat2,$in2,$in2
831         b.hs    .Loop3x_cbc_dec
832
833         cmn     $len,#0x30
834         b.eq    .Lcbc_done
835         nop
836
837 .Lcbc_dec_tail:
838         aesd    $dat1,q8
839         aesimc  $dat1,$dat1
840         aesd    $dat2,q8
841         aesimc  $dat2,$dat2
842         vld1.32 {q8},[$key_],#16
843         subs    $cnt,$cnt,#2
844         aesd    $dat1,q9
845         aesimc  $dat1,$dat1
846         aesd    $dat2,q9
847         aesimc  $dat2,$dat2
848         vld1.32 {q9},[$key_],#16
849         b.gt    .Lcbc_dec_tail
850
851         aesd    $dat1,q8
852         aesimc  $dat1,$dat1
853         aesd    $dat2,q8
854         aesimc  $dat2,$dat2
855         aesd    $dat1,q9
856         aesimc  $dat1,$dat1
857         aesd    $dat2,q9
858         aesimc  $dat2,$dat2
859         aesd    $dat1,q12
860         aesimc  $dat1,$dat1
861         aesd    $dat2,q12
862         aesimc  $dat2,$dat2
863          cmn    $len,#0x20
864         aesd    $dat1,q13
865         aesimc  $dat1,$dat1
866         aesd    $dat2,q13
867         aesimc  $dat2,$dat2
868          veor   $tmp1,$ivec,$rndlast
869         aesd    $dat1,q14
870         aesimc  $dat1,$dat1
871         aesd    $dat2,q14
872         aesimc  $dat2,$dat2
873          veor   $tmp2,$in1,$rndlast
874         aesd    $dat1,q15
875         aesd    $dat2,q15
876         b.eq    .Lcbc_dec_one
877         veor    $tmp1,$tmp1,$dat1
878         veor    $tmp2,$tmp2,$dat2
879          vorr   $ivec,$in2,$in2
880         vst1.8  {$tmp1},[$out],#16
881         vst1.8  {$tmp2},[$out],#16
882         b       .Lcbc_done
883
884 .Lcbc_dec_one:
885         veor    $tmp1,$tmp1,$dat2
886          vorr   $ivec,$in2,$in2
887         vst1.8  {$tmp1},[$out],#16
888
889 .Lcbc_done:
890         vst1.8  {$ivec},[$ivp]
891 .Lcbc_abort:
892 ___
893 }
894 $code.=<<___    if ($flavour !~ /64/);
895         vldmia  sp!,{d8-d15}
896         ldmia   sp!,{r4-r8,pc}
897 ___
898 $code.=<<___    if ($flavour =~ /64/);
899         ldr     x29,[sp],#16
900         ret
901 ___
902 $code.=<<___;
903 .size   ${prefix}_cbc_encrypt,.-${prefix}_cbc_encrypt
904 ___
905 }}}
906 {{{
907 my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4));
908 my ($rounds,$cnt,$key_)=("w5","w6","x7");
909 my ($ctr,$tctr0,$tctr1,$tctr2)=map("w$_",(8..10,12));
910 my $step="x12";         # aliases with $tctr2
911
912 my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7));
913 my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9));
914
915 # used only in 64-bit mode...
916 my ($dat3,$dat4,$in3,$in4)=map("q$_",(16..23));
917
918 my ($dat,$tmp)=($dat0,$tmp0);
919
920 ### q8-q15      preloaded key schedule
921
922 $code.=<<___;
923 .globl  ${prefix}_ctr32_encrypt_blocks
924 .type   ${prefix}_ctr32_encrypt_blocks,%function
925 .align  5
926 ${prefix}_ctr32_encrypt_blocks:
927 ___
928 $code.=<<___    if ($flavour =~ /64/);
929         stp             x29,x30,[sp,#-16]!
930         add             x29,sp,#0
931 ___
932 $code.=<<___    if ($flavour !~ /64/);
933         mov             ip,sp
934         stmdb           sp!,{r4-r10,lr}
935         vstmdb          sp!,{d8-d15}            @ ABI specification says so
936         ldr             r4, [ip]                @ load remaining arg
937 ___
938 $code.=<<___;
939         ldr             $rounds,[$key,#240]
940
941         ldr             $ctr, [$ivp, #12]
942         vld1.32         {$dat0},[$ivp]
943
944         vld1.32         {q8-q9},[$key]          // load key schedule...
945         sub             $rounds,$rounds,#4
946         mov             $step,#16
947         cmp             $len,#2
948         add             $key_,$key,x5,lsl#4     // pointer to last 5 round keys
949         sub             $rounds,$rounds,#2
950         vld1.32         {q12-q13},[$key_],#32
951         vld1.32         {q14-q15},[$key_],#32
952         vld1.32         {$rndlast},[$key_]
953         add             $key_,$key,#32
954         mov             $cnt,$rounds
955         cclr            $step,lo
956 #ifndef __ARMEB__
957         rev             $ctr, $ctr
958 #endif
959         vorr            $dat1,$dat0,$dat0
960         add             $tctr1, $ctr, #1
961         vorr            $dat2,$dat0,$dat0
962         add             $ctr, $ctr, #2
963         vorr            $ivec,$dat0,$dat0
964         rev             $tctr1, $tctr1
965         vmov.32         ${dat1}[3],$tctr1
966         b.ls            .Lctr32_tail
967         rev             $tctr2, $ctr
968         sub             $len,$len,#3            // bias
969         vmov.32         ${dat2}[3],$tctr2
970 ___
971 $code.=<<___    if ($flavour =~ /64/);
972         cmp             $len,#2
973         b.lo            .Loop3x_ctr32
974
975         add             w13,$ctr,#1
976         add             w14,$ctr,#2
977         vorr            $dat3,$dat0,$dat0
978         rev             w13,w13
979         vorr            $dat4,$dat0,$dat0
980         rev             w14,w14
981         vmov.32         ${dat3}[3],w13
982         sub             $len,$len,#2            // bias
983         vmov.32         ${dat4}[3],w14
984         add             $ctr,$ctr,#2
985         b               .Loop5x_ctr32
986
987 .align  4
988 .Loop5x_ctr32:
989         aese            $dat0,q8
990         aesmc           $dat0,$dat0
991         aese            $dat1,q8
992         aesmc           $dat1,$dat1
993         aese            $dat2,q8
994         aesmc           $dat2,$dat2
995         aese            $dat3,q8
996         aesmc           $dat3,$dat3
997         aese            $dat4,q8
998         aesmc           $dat4,$dat4
999         vld1.32         {q8},[$key_],#16
1000         subs            $cnt,$cnt,#2
1001         aese            $dat0,q9
1002         aesmc           $dat0,$dat0
1003         aese            $dat1,q9
1004         aesmc           $dat1,$dat1
1005         aese            $dat2,q9
1006         aesmc           $dat2,$dat2
1007         aese            $dat3,q9
1008         aesmc           $dat3,$dat3
1009         aese            $dat4,q9
1010         aesmc           $dat4,$dat4
1011         vld1.32         {q9},[$key_],#16
1012         b.gt            .Loop5x_ctr32
1013
1014         mov             $key_,$key
1015         aese            $dat0,q8
1016         aesmc           $dat0,$dat0
1017         aese            $dat1,q8
1018         aesmc           $dat1,$dat1
1019         aese            $dat2,q8
1020         aesmc           $dat2,$dat2
1021         aese            $dat3,q8
1022         aesmc           $dat3,$dat3
1023         aese            $dat4,q8
1024         aesmc           $dat4,$dat4
1025         vld1.32         {q8},[$key_],#16        // re-pre-load rndkey[0]
1026
1027         aese            $dat0,q9
1028         aesmc           $dat0,$dat0
1029         aese            $dat1,q9
1030         aesmc           $dat1,$dat1
1031         aese            $dat2,q9
1032         aesmc           $dat2,$dat2
1033         aese            $dat3,q9
1034         aesmc           $dat3,$dat3
1035         aese            $dat4,q9
1036         aesmc           $dat4,$dat4
1037         vld1.32         {q9},[$key_],#16        // re-pre-load rndkey[1]
1038
1039         aese            $dat0,q12
1040         aesmc           $dat0,$dat0
1041          add            $tctr0,$ctr,#1
1042          add            $tctr1,$ctr,#2
1043         aese            $dat1,q12
1044         aesmc           $dat1,$dat1
1045          add            $tctr2,$ctr,#3
1046          add            w13,$ctr,#4
1047         aese            $dat2,q12
1048         aesmc           $dat2,$dat2
1049          add            w14,$ctr,#5
1050          rev            $tctr0,$tctr0
1051         aese            $dat3,q12
1052         aesmc           $dat3,$dat3
1053          rev            $tctr1,$tctr1
1054          rev            $tctr2,$tctr2
1055         aese            $dat4,q12
1056         aesmc           $dat4,$dat4
1057          rev            w13,w13
1058          rev            w14,w14
1059
1060         aese            $dat0,q13
1061         aesmc           $dat0,$dat0
1062         aese            $dat1,q13
1063         aesmc           $dat1,$dat1
1064         aese            $dat2,q13
1065         aesmc           $dat2,$dat2
1066         aese            $dat3,q13
1067         aesmc           $dat3,$dat3
1068         aese            $dat4,q13
1069         aesmc           $dat4,$dat4
1070
1071         aese            $dat0,q14
1072         aesmc           $dat0,$dat0
1073          vld1.8         {$in0},[$inp],#16
1074         aese            $dat1,q14
1075         aesmc           $dat1,$dat1
1076          vld1.8         {$in1},[$inp],#16
1077         aese            $dat2,q14
1078         aesmc           $dat2,$dat2
1079          vld1.8         {$in2},[$inp],#16
1080         aese            $dat3,q14
1081         aesmc           $dat3,$dat3
1082          vld1.8         {$in3},[$inp],#16
1083         aese            $dat4,q14
1084         aesmc           $dat4,$dat4
1085          vld1.8         {$in4},[$inp],#16
1086
1087         aese            $dat0,q15
1088          veor           $in0,$in0,$rndlast
1089         aese            $dat1,q15
1090          veor           $in1,$in1,$rndlast
1091         aese            $dat2,q15
1092          veor           $in2,$in2,$rndlast
1093         aese            $dat3,q15
1094          veor           $in3,$in3,$rndlast
1095         aese            $dat4,q15
1096          veor           $in4,$in4,$rndlast
1097
1098         veor            $in0,$in0,$dat0
1099          vorr           $dat0,$ivec,$ivec
1100         veor            $in1,$in1,$dat1
1101          vorr           $dat1,$ivec,$ivec
1102         veor            $in2,$in2,$dat2
1103          vorr           $dat2,$ivec,$ivec
1104         veor            $in3,$in3,$dat3
1105          vorr           $dat3,$ivec,$ivec
1106         veor            $in4,$in4,$dat4
1107          vorr           $dat4,$ivec,$ivec
1108
1109         vst1.8          {$in0},[$out],#16
1110          vmov.32        ${dat0}[3],$tctr0
1111         vst1.8          {$in1},[$out],#16
1112          vmov.32        ${dat1}[3],$tctr1
1113         vst1.8          {$in2},[$out],#16
1114          vmov.32        ${dat2}[3],$tctr2
1115         vst1.8          {$in3},[$out],#16
1116          vmov.32        ${dat3}[3],w13
1117         vst1.8          {$in4},[$out],#16
1118          vmov.32        ${dat4}[3],w14
1119
1120         mov             $cnt,$rounds
1121         cbz             $len,.Lctr32_done
1122
1123         add             $ctr,$ctr,#5
1124         subs            $len,$len,#5
1125         b.hs            .Loop5x_ctr32
1126
1127         add             $len,$len,#5
1128         sub             $ctr,$ctr,#5
1129
1130         cmp             $len,#2
1131         mov             $step,#16
1132         cclr            $step,lo
1133         b.ls            .Lctr32_tail
1134
1135         sub             $len,$len,#3            // bias
1136         add             $ctr,$ctr,#3
1137 ___
1138 $code.=<<___;
1139         b               .Loop3x_ctr32
1140
1141 .align  4
1142 .Loop3x_ctr32:
1143         aese            $dat0,q8
1144         aesmc           $dat0,$dat0
1145         aese            $dat1,q8
1146         aesmc           $dat1,$dat1
1147         aese            $dat2,q8
1148         aesmc           $dat2,$dat2
1149         vld1.32         {q8},[$key_],#16
1150         subs            $cnt,$cnt,#2
1151         aese            $dat0,q9
1152         aesmc           $dat0,$dat0
1153         aese            $dat1,q9
1154         aesmc           $dat1,$dat1
1155         aese            $dat2,q9
1156         aesmc           $dat2,$dat2
1157         vld1.32         {q9},[$key_],#16
1158         b.gt            .Loop3x_ctr32
1159
1160         aese            $dat0,q8
1161         aesmc           $tmp0,$dat0
1162         aese            $dat1,q8
1163         aesmc           $tmp1,$dat1
1164          vld1.8         {$in0},[$inp],#16
1165          vorr           $dat0,$ivec,$ivec
1166         aese            $dat2,q8
1167         aesmc           $dat2,$dat2
1168          vld1.8         {$in1},[$inp],#16
1169          vorr           $dat1,$ivec,$ivec
1170         aese            $tmp0,q9
1171         aesmc           $tmp0,$tmp0
1172         aese            $tmp1,q9
1173         aesmc           $tmp1,$tmp1
1174          vld1.8         {$in2},[$inp],#16
1175          mov            $key_,$key
1176         aese            $dat2,q9
1177         aesmc           $tmp2,$dat2
1178          vorr           $dat2,$ivec,$ivec
1179          add            $tctr0,$ctr,#1
1180         aese            $tmp0,q12
1181         aesmc           $tmp0,$tmp0
1182         aese            $tmp1,q12
1183         aesmc           $tmp1,$tmp1
1184          veor           $in0,$in0,$rndlast
1185          add            $tctr1,$ctr,#2
1186         aese            $tmp2,q12
1187         aesmc           $tmp2,$tmp2
1188          veor           $in1,$in1,$rndlast
1189          add            $ctr,$ctr,#3
1190         aese            $tmp0,q13
1191         aesmc           $tmp0,$tmp0
1192         aese            $tmp1,q13
1193         aesmc           $tmp1,$tmp1
1194          veor           $in2,$in2,$rndlast
1195          rev            $tctr0,$tctr0
1196         aese            $tmp2,q13
1197         aesmc           $tmp2,$tmp2
1198          vmov.32        ${dat0}[3], $tctr0
1199          rev            $tctr1,$tctr1
1200         aese            $tmp0,q14
1201         aesmc           $tmp0,$tmp0
1202         aese            $tmp1,q14
1203         aesmc           $tmp1,$tmp1
1204          vmov.32        ${dat1}[3], $tctr1
1205          rev            $tctr2,$ctr
1206         aese            $tmp2,q14
1207         aesmc           $tmp2,$tmp2
1208          vmov.32        ${dat2}[3], $tctr2
1209          subs           $len,$len,#3
1210         aese            $tmp0,q15
1211         aese            $tmp1,q15
1212         aese            $tmp2,q15
1213
1214         veor            $in0,$in0,$tmp0
1215          vld1.32         {q8},[$key_],#16       // re-pre-load rndkey[0]
1216         vst1.8          {$in0},[$out],#16
1217         veor            $in1,$in1,$tmp1
1218          mov            $cnt,$rounds
1219         vst1.8          {$in1},[$out],#16
1220         veor            $in2,$in2,$tmp2
1221          vld1.32         {q9},[$key_],#16       // re-pre-load rndkey[1]
1222         vst1.8          {$in2},[$out],#16
1223         b.hs            .Loop3x_ctr32
1224
1225         adds            $len,$len,#3
1226         b.eq            .Lctr32_done
1227         cmp             $len,#1
1228         mov             $step,#16
1229         cclr            $step,eq
1230
1231 .Lctr32_tail:
1232         aese            $dat0,q8
1233         aesmc           $dat0,$dat0
1234         aese            $dat1,q8
1235         aesmc           $dat1,$dat1
1236         vld1.32         {q8},[$key_],#16
1237         subs            $cnt,$cnt,#2
1238         aese            $dat0,q9
1239         aesmc           $dat0,$dat0
1240         aese            $dat1,q9
1241         aesmc           $dat1,$dat1
1242         vld1.32         {q9},[$key_],#16
1243         b.gt            .Lctr32_tail
1244
1245         aese            $dat0,q8
1246         aesmc           $dat0,$dat0
1247         aese            $dat1,q8
1248         aesmc           $dat1,$dat1
1249         aese            $dat0,q9
1250         aesmc           $dat0,$dat0
1251         aese            $dat1,q9
1252         aesmc           $dat1,$dat1
1253          vld1.8         {$in0},[$inp],$step
1254         aese            $dat0,q12
1255         aesmc           $dat0,$dat0
1256         aese            $dat1,q12
1257         aesmc           $dat1,$dat1
1258          vld1.8         {$in1},[$inp]
1259         aese            $dat0,q13
1260         aesmc           $dat0,$dat0
1261         aese            $dat1,q13
1262         aesmc           $dat1,$dat1
1263          veor           $in0,$in0,$rndlast
1264         aese            $dat0,q14
1265         aesmc           $dat0,$dat0
1266         aese            $dat1,q14
1267         aesmc           $dat1,$dat1
1268          veor           $in1,$in1,$rndlast
1269         aese            $dat0,q15
1270         aese            $dat1,q15
1271
1272         cmp             $len,#1
1273         veor            $in0,$in0,$dat0
1274         veor            $in1,$in1,$dat1
1275         vst1.8          {$in0},[$out],#16
1276         b.eq            .Lctr32_done
1277         vst1.8          {$in1},[$out]
1278
1279 .Lctr32_done:
1280 ___
1281 $code.=<<___    if ($flavour !~ /64/);
1282         vldmia          sp!,{d8-d15}
1283         ldmia           sp!,{r4-r10,pc}
1284 ___
1285 $code.=<<___    if ($flavour =~ /64/);
1286         ldr             x29,[sp],#16
1287         ret
1288 ___
1289 $code.=<<___;
1290 .size   ${prefix}_ctr32_encrypt_blocks,.-${prefix}_ctr32_encrypt_blocks
1291 ___
1292 }}}
1293 $code.=<<___;
1294 #endif
1295 ___
1296 ########################################
1297 if ($flavour =~ /64/) {                 ######## 64-bit code
1298     my %opcode = (
1299         "aesd"  =>      0x4e285800,     "aese"  =>      0x4e284800,
1300         "aesimc"=>      0x4e287800,     "aesmc" =>      0x4e286800      );
1301
1302     local *unaes = sub {
1303         my ($mnemonic,$arg)=@_;
1304
1305         $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o   &&
1306         sprintf ".inst\t0x%08x\t//%s %s",
1307                         $opcode{$mnemonic}|$1|($2<<5),
1308                         $mnemonic,$arg;
1309     };
1310
1311     foreach(split("\n",$code)) {
1312         s/\`([^\`]*)\`/eval($1)/geo;
1313
1314         s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo;  # old->new registers
1315         s/@\s/\/\//o;                   # old->new style commentary
1316
1317         #s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo     or
1318         s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel $1$2,$1zr,$1$2,$3/o     or
1319         s/mov\.([a-z]+)\s+([wx][0-9]+),\s*([wx][0-9]+)/csel     $2,$3,$2,$1/o   or
1320         s/vmov\.i8/movi/o       or      # fix up legacy mnemonics
1321         s/vext\.8/ext/o         or
1322         s/vrev32\.8/rev32/o     or
1323         s/vtst\.8/cmtst/o       or
1324         s/vshr/ushr/o           or
1325         s/^(\s+)v/$1/o          or      # strip off v prefix
1326         s/\bbx\s+lr\b/ret/o;
1327
1328         # fix up remaining legacy suffixes
1329         s/\.[ui]?8//o;
1330         m/\],#8/o and s/\.16b/\.8b/go;
1331         s/\.[ui]?32//o and s/\.16b/\.4s/go;
1332         s/\.[ui]?64//o and s/\.16b/\.2d/go;
1333         s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o;
1334
1335         print $_,"\n";
1336     }
1337 } else {                                ######## 32-bit code
1338     my %opcode = (
1339         "aesd"  =>      0xf3b00340,     "aese"  =>      0xf3b00300,
1340         "aesimc"=>      0xf3b003c0,     "aesmc" =>      0xf3b00380      );
1341
1342     local *unaes = sub {
1343         my ($mnemonic,$arg)=@_;
1344
1345         if ($arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o) {
1346             my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
1347                                          |(($2&7)<<1) |(($2&8)<<2);
1348             # since ARMv7 instructions are always encoded little-endian.
1349             # correct solution is to use .inst directive, but older
1350             # assemblers don't implement it:-(
1351             sprintf "INST(0x%02x,0x%02x,0x%02x,0x%02x)\t@ %s %s",
1352                         $word&0xff,($word>>8)&0xff,
1353                         ($word>>16)&0xff,($word>>24)&0xff,
1354                         $mnemonic,$arg;
1355         }
1356     };
1357
1358     sub unvtbl {
1359         my $arg=shift;
1360
1361         $arg =~ m/q([0-9]+),\s*\{q([0-9]+)\},\s*q([0-9]+)/o &&
1362         sprintf "vtbl.8 d%d,{q%d},d%d\n\t".
1363                 "vtbl.8 d%d,{q%d},d%d", 2*$1,$2,2*$3, 2*$1+1,$2,2*$3+1;
1364     }
1365
1366     sub unvdup32 {
1367         my $arg=shift;
1368
1369         $arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o &&
1370         sprintf "vdup.32        q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1;
1371     }
1372
1373     sub unvmov32 {
1374         my $arg=shift;
1375
1376         $arg =~ m/q([0-9]+)\[([0-3])\],(.*)/o &&
1377         sprintf "vmov.32        d%d[%d],%s",2*$1+($2>>1),$2&1,$3;
1378     }
1379
1380     foreach(split("\n",$code)) {
1381         s/\`([^\`]*)\`/eval($1)/geo;
1382
1383         s/\b[wx]([0-9]+)\b/r$1/go;              # new->old registers
1384         s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go;   # new->old registers
1385         s/\/\/\s?/@ /o;                         # new->old style commentary
1386
1387         # fix up remaining new-style suffixes
1388         s/\{q([0-9]+)\},\s*\[(.+)\],#8/sprintf "{d%d},[$2]!",2*$1/eo    or
1389         s/\],#[0-9]+/]!/o;
1390
1391         s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo      or
1392         s/cclr\s+([^,]+),\s*([a-z]+)/mov.$2     $1,#0/o or
1393         s/vtbl\.8\s+(.*)/unvtbl($1)/geo                 or
1394         s/vdup\.32\s+(.*)/unvdup32($1)/geo              or
1395         s/vmov\.32\s+(.*)/unvmov32($1)/geo              or
1396         s/^(\s+)b\./$1b/o                               or
1397         s/^(\s+)ret/$1bx\tlr/o;
1398
1399         if (s/^(\s+)mov\.([a-z]+)/$1mov$2/) {
1400             print "     it      $2\n";
1401         }
1402
1403         print $_,"\n";
1404     }
1405 }
1406
1407 close STDOUT;