c4481b56b1d14dfe3f06fd189e48c6a8b26f7f5f
[openssl.git] / crypto / aes / asm / aesv8-armx.pl
1 #!/usr/bin/env perl
2 #
3 # ====================================================================
4 # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
9 #
10 # This module implements support for ARMv8 AES instructions. The
11 # module is endian-agnostic in sense that it supports both big- and
12 # little-endian cases. As does it support both 32- and 64-bit modes
13 # of operation. Latter is achieved by limiting amount of utilized
14 # registers to 16, which implies additional instructions. This has
15 # no effect on mighty Apple A7, as results are literally equal to
16 # the theoretical estimates based on instruction latencies and issue
17 # rate. It remains to be seen how does it affect other platforms...
18 #
19 # Performance in cycles per byte processed with 128-bit key:
20 #
21 #               CBC enc         CBC dec
22 # Apple A7      2.39            1.20
23
24 $flavour = shift;
25 $prefix="AES";
26
27 $code=".text\n";
28 $code.=".arch   armv8-a+crypto\n"       if ($flavour =~ /64/);
29 $code.=".fpu    neon\n.code     32\n"   if ($flavour !~ /64/);
30
31 # Assembler mnemonics are an eclectic mix of 32- and 64-bit syntax,
32 # NEON is mostly 32-bit mnemonics, integer - mostly 64. Goal is to
33 # maintain both 32- and 64-bit codes within single module and
34 # transliterate common code to either flavour with regex vodoo.
35 #
36 {{{
37 my ($inp,$bits,$out,$ptr,$rounds)=("x0","w1","x2","x3","w12");
38 my ($zero,$rcon,$mask,$in0,$in1,$tmp,$key)=
39         $flavour=~/64/? map("q$_",(0..6)) : map("q$_",(0..3,8..10));
40
41
42 $code.=<<___;
43 .align  5
44 rcon:
45 .long   0x01,0x01,0x01,0x01
46 .long   0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d     // rotate-n-splat
47 .long   0x1b,0x1b,0x1b,0x1b
48
49 .globl  ${prefix}_set_encrypt_key
50 .type   ${prefix}_set_encrypt_key,%function
51 .align  5
52 ${prefix}_set_encrypt_key:
53 .Lenc_key:
54 ___
55 $code.=<<___    if ($flavour =~ /64/);
56         stp     x29,x30,[sp,#-16]!
57         add     x29,sp,#0
58 ___
59 $code.=<<___;
60         adr     $ptr,rcon
61         cmp     $bits,#192
62
63         veor    $zero,$zero,$zero
64         vld1.8  {$in0},[$inp],#16
65         mov     $bits,#8                // reuse $bits
66         vld1.32 {$rcon,$mask},[$ptr],#32
67
68         b.lt    .Loop128
69         b.eq    .L192
70         b       .L256
71
72 .align  4
73 .Loop128:
74         vtbl.8  $key,{$in0},$mask
75         vext.8  $tmp,$zero,$in0,#12
76         vst1.32 {$in0},[$out],#16
77         aese    $key,$zero
78         subs    $bits,$bits,#1
79
80         veor    $in0,$in0,$tmp
81         vext.8  $tmp,$zero,$tmp,#12
82         veor    $in0,$in0,$tmp
83         vext.8  $tmp,$zero,$tmp,#12
84          veor   $key,$key,$rcon
85         veor    $in0,$in0,$tmp
86         vshl.u8 $rcon,$rcon,#1
87         veor    $in0,$in0,$key
88         b.ne    .Loop128
89
90         vld1.32 {$rcon},[$ptr]
91
92         vtbl.8  $key,{$in0},$mask
93         vext.8  $tmp,$zero,$in0,#12
94         vst1.32 {$in0},[$out],#16
95         aese    $key,$zero
96
97         veor    $in0,$in0,$tmp
98         vext.8  $tmp,$zero,$tmp,#12
99         veor    $in0,$in0,$tmp
100         vext.8  $tmp,$zero,$tmp,#12
101          veor   $key,$key,$rcon
102         veor    $in0,$in0,$tmp
103         vshl.u8 $rcon,$rcon,#1
104         veor    $in0,$in0,$key
105
106         vtbl.8  $key,{$in0},$mask
107         vext.8  $tmp,$zero,$in0,#12
108         vst1.32 {$in0},[$out],#16
109         aese    $key,$zero
110
111         veor    $in0,$in0,$tmp
112         vext.8  $tmp,$zero,$tmp,#12
113         veor    $in0,$in0,$tmp
114         vext.8  $tmp,$zero,$tmp,#12
115          veor   $key,$key,$rcon
116         veor    $in0,$in0,$tmp
117         veor    $in0,$in0,$key
118         vst1.32 {$in0},[$out]
119         add     $out,$out,#0x50
120
121         mov     $rounds,#10
122         b       .Ldone
123
124 .align  4
125 .L192:
126         vld1.8  {$in1},[$inp],#8
127         vmov.i8 $key,#8                 // borrow $key
128         vst1.32 {$in0},[$out],#16
129         vsub.i8 $mask,$mask,$key        // adjust the mask
130
131 .Loop192:
132         vtbl.8  $key,{$in1},$mask
133         vext.8  $tmp,$zero,$in0,#12
134         vst1.32 {$in1},[$out],#8
135         aese    $key,$zero
136         subs    $bits,$bits,#1
137
138         veor    $in0,$in0,$tmp
139         vext.8  $tmp,$zero,$tmp,#12
140         veor    $in0,$in0,$tmp
141         vext.8  $tmp,$zero,$tmp,#12
142         veor    $in0,$in0,$tmp
143
144         vdup.32 $tmp,${in0}[3]
145         veor    $tmp,$tmp,$in1
146          veor   $key,$key,$rcon
147         vext.8  $in1,$zero,$in1,#12
148         vshl.u8 $rcon,$rcon,#1
149         veor    $in1,$in1,$tmp
150         veor    $in0,$in0,$key
151         veor    $in1,$in1,$key
152         vst1.32 {$in0},[$out],#16
153         b.ne    .Loop192
154
155         mov     $rounds,#12
156         add     $out,$out,#0x20
157         b       .Ldone
158
159 .align  4
160 .L256:
161         vld1.8  {$in1},[$inp]
162         mov     $bits,#7
163         mov     $rounds,#14
164         vst1.32 {$in0},[$out],#16
165
166 .Loop256:
167         vtbl.8  $key,{$in1},$mask
168         vext.8  $tmp,$zero,$in0,#12
169         vst1.32 {$in1},[$out],#16
170         aese    $key,$zero
171         subs    $bits,$bits,#1
172
173         veor    $in0,$in0,$tmp
174         vext.8  $tmp,$zero,$tmp,#12
175         veor    $in0,$in0,$tmp
176         vext.8  $tmp,$zero,$tmp,#12
177          veor   $key,$key,$rcon
178         veor    $in0,$in0,$tmp
179         vshl.u8 $rcon,$rcon,#1
180         veor    $in0,$in0,$key
181         vst1.32 {$in0},[$out],#16
182         b.eq    .Ldone
183
184         vdup.32 $key,${in0}[3]          // just splat
185         vext.8  $tmp,$zero,$in1,#12
186         aese    $key,$zero
187
188         veor    $in1,$in1,$tmp
189         vext.8  $tmp,$zero,$tmp,#12
190         veor    $in1,$in1,$tmp
191         vext.8  $tmp,$zero,$tmp,#12
192         veor    $in1,$in1,$tmp
193
194         veor    $in1,$in1,$key
195         b       .Loop256
196
197 .Ldone:
198         str     $rounds,[$out]
199
200         eor     x0,x0,x0                // return value
201         `"ldr   x29,[sp],#16"           if ($flavour =~ /64/)`
202         ret
203 .size   ${prefix}_set_encrypt_key,.-${prefix}_set_encrypt_key
204
205 .globl  ${prefix}_set_decrypt_key
206 .type   ${prefix}_set_decrypt_key,%function
207 .align  5
208 ${prefix}_set_decrypt_key:
209 ___
210 $code.=<<___    if ($flavour =~ /64/);
211         stp     x29,x30,[sp,#-16]!
212         add     x29,sp,#0
213 ___
214 $code.=<<___    if ($flavour !~ /64/);
215         stmdb   sp!,{r4,lr}
216 ___
217 $code.=<<___;
218         bl      .Lenc_key
219
220         sub     $out,$out,#240          // restore original $out
221         mov     x4,#-16
222         add     $inp,$out,x12,lsl#4     // end of key schedule
223
224         vld1.32 {v0.16b},[$out]
225         vld1.32 {v1.16b},[$inp]
226         vst1.32 {v0.16b},[$inp],x4
227         vst1.32 {v1.16b},[$out],#16
228
229 .Loop_imc:
230         vld1.32 {v0.16b},[$out]
231         vld1.32 {v1.16b},[$inp]
232         aesimc  v0.16b,v0.16b
233         aesimc  v1.16b,v1.16b
234         vst1.32 {v0.16b},[$inp],x4
235         vst1.32 {v1.16b},[$out],#16
236         cmp     $inp,$out
237         b.hi    .Loop_imc
238
239         vld1.32 {v0.16b},[$out]
240         aesimc  v0.16b,v0.16b
241         vst1.32 {v0.16b},[$inp]
242
243         eor     x0,x0,x0                // return value
244 ___
245 $code.=<<___    if ($flavour !~ /64/);
246         ldmia   sp!,{r4,pc}
247 ___
248 $code.=<<___    if ($flavour =~ /64/);
249         ldp     x29,x30,[sp],#16
250         ret
251 ___
252 $code.=<<___;
253 .size   ${prefix}_set_decrypt_key,.-${prefix}_set_decrypt_key
254 ___
255 }}}
256 {{{
257 sub gen_block () {
258 my $dir = shift;
259 my ($e,$mc) = $dir eq "en" ? ("e","mc") : ("d","imc");
260 my ($inp,$out,$key)=map("x$_",(0..2));
261 my $rounds="w3";
262 my ($rndkey0,$rndkey1,$inout)=map("q$_",(0..3));
263
264 $code.=<<___;
265 .globl  ${prefix}_${dir}crypt
266 .type   ${prefix}_${dir}crypt,%function
267 .align  5
268 ${prefix}_${dir}crypt:
269         ldr     $rounds,[$key,#240]
270         vld1.32 {$rndkey0},[$key],#16
271         vld1.8  {$inout},[$inp]
272         sub     $rounds,$rounds,#2
273         vld1.32 {$rndkey1},[$key],#16
274
275 .Loop_${dir}c:
276         aes$e   $inout,$rndkey0
277         vld1.32 {$rndkey0},[$key],#16
278         aes$mc  $inout,$inout
279         subs    $rounds,$rounds,#2
280         aes$e   $inout,$rndkey1
281         vld1.32 {$rndkey1},[$key],#16
282         aes$mc  $inout,$inout
283         b.gt    .Loop_${dir}c
284
285         aes$e   $inout,$rndkey0
286         vld1.32 {$rndkey0},[$key]
287         aes$mc  $inout,$inout
288         aes$e   $inout,$rndkey1
289         veor    $inout,$inout,$rndkey0
290
291         vst1.8  {$inout},[$out]
292         ret
293 .size   ${prefix}_${dir}crypt,.-${prefix}_${dir}crypt
294 ___
295 }
296 &gen_block("en");
297 &gen_block("de");
298 }}}
299 {{{
300 my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4)); my $enc="w5";
301 my ($rounds,$cnt,$key_,$step,$step1)=($enc,"w6","x7","x8","x12");
302 my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7));
303
304 my ($dat,$tmp,$rndzero_n_last)=($dat0,$tmp0,$tmp1);
305
306 ### q8-q15      preloaded key schedule
307
308 $code.=<<___;
309 .globl  ${prefix}_cbc_encrypt
310 .type   ${prefix}_cbc_encrypt,%function
311 .align  5
312 ${prefix}_cbc_encrypt:
313 ___
314 $code.=<<___    if ($flavour =~ /64/);
315         stp     x29,x30,[sp,#-16]!
316         add     x29,sp,#0
317 ___
318 $code.=<<___    if ($flavour !~ /64/);
319         mov     ip,sp
320         stmdb   sp!,{r4-r8,lr}
321         vstmdb  sp!,{d8-d15}            @ ABI specification says so
322         ldmia   ip,{r4-r5}              @ load remaining args
323 ___
324 $code.=<<___;
325         subs    $len,$len,#16
326         mov     $step,#16
327         b.lo    .Lcbc_abort
328         cclr    $step,eq
329
330         cmp     $enc,#0                 // en- or decrypting?
331         ldr     $rounds,[$key,#240]
332         and     $len,$len,#-16
333         vld1.8  {$ivec},[$ivp]
334         vld1.8  {$dat},[$inp],$step
335
336         vld1.32 {q8-q9},[$key]          // load key schedule...
337         sub     $rounds,$rounds,#6
338         add     $key_,$key,x5,lsl#4     // pointer to last 7 round keys
339         sub     $rounds,$rounds,#2
340         vld1.32 {q10-q11},[$key_],#32
341         vld1.32 {q12-q13},[$key_],#32
342         vld1.32 {q14-q15},[$key_],#32
343         vld1.32 {$rndlast},[$key_]
344
345         add     $key_,$key,#32
346         mov     $cnt,$rounds
347         b.eq    .Lcbc_dec
348
349         cmp     $rounds,#2
350         veor    $dat,$dat,$ivec
351         veor    $rndzero_n_last,q8,$rndlast
352         b.eq    .Lcbc_enc128
353
354 .Loop_cbc_enc:
355         aese    $dat,q8
356         vld1.32 {q8},[$key_],#16
357         aesmc   $dat,$dat
358         subs    $cnt,$cnt,#2
359         aese    $dat,q9
360         vld1.32 {q9},[$key_],#16
361         aesmc   $dat,$dat
362         b.gt    .Loop_cbc_enc
363
364         aese    $dat,q8
365         aesmc   $dat,$dat
366          subs   $len,$len,#16
367         aese    $dat,q9
368         aesmc   $dat,$dat
369          cclr   $step,eq
370         aese    $dat,q10
371         aesmc   $dat,$dat
372          add    $key_,$key,#16
373         aese    $dat,q11
374         aesmc   $dat,$dat
375          vld1.8 {q8},[$inp],$step
376         aese    $dat,q12
377         aesmc   $dat,$dat
378          veor   q8,q8,$rndzero_n_last
379         aese    $dat,q13
380         aesmc   $dat,$dat
381          vld1.32 {q9},[$key_],#16       // re-pre-load rndkey[1]
382         aese    $dat,q14
383         aesmc   $dat,$dat
384         aese    $dat,q15
385
386          mov    $cnt,$rounds
387         veor    $ivec,$dat,$rndlast
388         vst1.8  {$ivec},[$out],#16
389         b.hs    .Loop_cbc_enc
390
391         b       .Lcbc_done
392
393 .align  5
394 .Lcbc_enc128:
395         vld1.32 {$in0-$in1},[$key_]
396         aese    $dat,q8
397         aesmc   $dat,$dat
398         b       .Lenter_cbc_enc128
399 .Loop_cbc_enc128:
400         aese    $dat,q8
401         aesmc   $dat,$dat
402          vst1.8 {$ivec},[$out],#16
403 .Lenter_cbc_enc128:
404         aese    $dat,q9
405         aesmc   $dat,$dat
406          subs   $len,$len,#16
407         aese    $dat,$in0
408         aesmc   $dat,$dat
409          cclr   $step,eq
410         aese    $dat,$in1
411         aesmc   $dat,$dat
412         aese    $dat,q10
413         aesmc   $dat,$dat
414         aese    $dat,q11
415         aesmc   $dat,$dat
416          vld1.8 {q8},[$inp],$step
417         aese    $dat,q12
418         aesmc   $dat,$dat
419         aese    $dat,q13
420         aesmc   $dat,$dat
421         aese    $dat,q14
422         aesmc   $dat,$dat
423          veor   q8,q8,$rndzero_n_last
424         aese    $dat,q15
425         veor    $ivec,$dat,$rndlast
426         b.hs    .Loop_cbc_enc128
427
428         vst1.8  {$ivec},[$out],#16
429         b       .Lcbc_done
430
431 .align  5
432 .Lcbc_dec128:
433         vld1.32 {$tmp0-$tmp1},[$key_]
434         veor    $ivec,$ivec,$rndlast
435         veor    $in0,$dat0,$rndlast
436         mov     $step1,$step
437
438 .Loop2x_cbc_dec128:
439         aesd    $dat0,q8
440         aesd    $dat1,q8
441         aesimc  $dat0,$dat0
442         aesimc  $dat1,$dat1
443          subs   $len,$len,#32
444         aesd    $dat0,q9
445         aesd    $dat1,q9
446         aesimc  $dat0,$dat0
447         aesimc  $dat1,$dat1
448          cclr   $step,lo
449         aesd    $dat0,$tmp0
450         aesd    $dat1,$tmp0
451         aesimc  $dat0,$dat0
452         aesimc  $dat1,$dat1
453          cclr   $step1,ls
454         aesd    $dat0,$tmp1
455         aesd    $dat1,$tmp1
456         aesimc  $dat0,$dat0
457         aesimc  $dat1,$dat1
458         aesd    $dat0,q10
459         aesd    $dat1,q10
460         aesimc  $dat0,$dat0
461         aesimc  $dat1,$dat1
462         aesd    $dat0,q11
463         aesd    $dat1,q11
464         aesimc  $dat0,$dat0
465         aesimc  $dat1,$dat1
466         aesd    $dat0,q12
467         aesd    $dat1,q12
468         aesimc  $dat0,$dat0
469         aesimc  $dat1,$dat1
470         aesd    $dat0,q13
471         aesd    $dat1,q13
472         aesimc  $dat0,$dat0
473         aesimc  $dat1,$dat1
474         aesd    $dat0,q14
475         aesd    $dat1,q14
476         aesimc  $dat0,$dat0
477         aesimc  $dat1,$dat1
478         aesd    $dat0,q15
479         aesd    $dat1,q15
480
481         veor    $ivec,$ivec,$dat0
482         veor    $in0,$in0,$dat1
483         vld1.8  {$dat0},[$inp],$step
484         vld1.8  {$dat1},[$inp],$step1
485         vst1.8  {$ivec},[$out],#16
486         veor    $ivec,$in1,$rndlast
487         vst1.8  {$in0},[$out],#16
488         veor    $in0,$dat0,$rndlast
489         vorr    $in1,$dat1,$dat1
490         b.hs    .Loop2x_cbc_dec128
491
492         adds    $len,$len,#32
493         veor    $ivec,$ivec,$rndlast
494         b.eq    .Lcbc_done
495         veor    $in0,$in0,$rndlast
496         b       .Lcbc_dec_tail
497
498 .align  5
499 .Lcbc_dec:
500         subs    $len,$len,#16
501         vorr    $in0,$dat,$dat
502         b.lo    .Lcbc_dec_tail
503
504         cclr    $step,eq
505         cmp     $rounds,#2
506         vld1.8  {$dat1},[$inp],$step
507         vorr    $in1,$dat1,$dat1
508         b.eq    .Lcbc_dec128
509
510 .Loop2x_cbc_dec:
511         aesd    $dat0,q8
512         aesd    $dat1,q8
513         vld1.32 {q8},[$key_],#16
514         aesimc  $dat0,$dat0
515         aesimc  $dat1,$dat1
516         subs    $cnt,$cnt,#2
517         aesd    $dat0,q9
518         aesd    $dat1,q9
519         vld1.32 {q9},[$key_],#16
520         aesimc  $dat0,$dat0
521         aesimc  $dat1,$dat1
522         b.gt    .Loop2x_cbc_dec
523
524         aesd    $dat0,q8
525         aesd    $dat1,q8
526         aesimc  $dat0,$dat0
527         aesimc  $dat1,$dat1
528          veor   $tmp0,$ivec,$rndlast
529          veor   $tmp1,$in0,$rndlast
530         aesd    $dat0,q9
531         aesd    $dat1,q9
532         aesimc  $dat0,$dat0
533         aesimc  $dat1,$dat1
534          vorr   $ivec,$in1,$in1
535          subs   $len,$len,#32
536         aesd    $dat0,q10
537         aesd    $dat1,q10
538         aesimc  $dat0,$dat0
539          cclr   $step,lo
540         aesimc  $dat1,$dat1
541          mov    $key_,$key
542         aesd    $dat0,q11
543         aesd    $dat1,q11
544         aesimc  $dat0,$dat0
545          vld1.8 {$in0},[$inp],$step
546         aesimc  $dat1,$dat1
547          cclr   $step,ls
548         aesd    $dat0,q12
549         aesd    $dat1,q12
550         aesimc  $dat0,$dat0
551         aesimc  $dat1,$dat1
552          vld1.8 {$in1},[$inp],$step
553         aesd    $dat0,q13
554         aesd    $dat1,q13
555         aesimc  $dat0,$dat0
556         aesimc  $dat1,$dat1
557          vld1.32 {q8},[$key_],#16       // re-pre-load rndkey[0]
558         aesd    $dat0,q14
559         aesd    $dat1,q14
560         aesimc  $dat0,$dat0
561         aesimc  $dat1,$dat1
562          vld1.32 {q9},[$key_],#16       // re-pre-load rndkey[1]
563         aesd    $dat0,q15
564         aesd    $dat1,q15
565
566          mov    $cnt,$rounds
567         veor    $tmp0,$tmp0,$dat0
568         veor    $tmp1,$tmp1,$dat1
569          vorr   $dat0,$in0,$in0
570         vst1.8  {$tmp0},[$out],#16
571          vorr   $dat1,$in1,$in1
572         vst1.8  {$tmp1},[$out],#16
573         b.hs    .Loop2x_cbc_dec
574
575         adds    $len,$len,#32
576         b.eq    .Lcbc_done
577
578 .Lcbc_dec_tail:
579         aesd    $dat,q8
580         vld1.32 {q8},[$key_],#16
581         aesimc  $dat,$dat
582         subs    $cnt,$cnt,#2
583         aesd    $dat,q9
584         vld1.32 {q9},[$key_],#16
585         aesimc  $dat,$dat
586         b.gt    .Lcbc_dec_tail
587
588         aesd    $dat,q8
589         aesimc  $dat,$dat
590         aesd    $dat,q9
591         aesimc  $dat,$dat
592          veor   $tmp,$ivec,$rndlast
593         aesd    $dat,q10
594         aesimc  $dat,$dat
595          vorr   $ivec,$in0,$in0
596         aesd    $dat,q11
597         aesimc  $dat,$dat
598         aesd    $dat,q12
599         aesimc  $dat,$dat
600         aesd    $dat,q13
601         aesimc  $dat,$dat
602         aesd    $dat,q14
603         aesimc  $dat,$dat
604         aesd    $dat,q15
605
606         veor    $tmp,$tmp,$dat
607         vst1.8  {$tmp},[$out],#16
608
609 .Lcbc_done:
610         vst1.8  {$ivec},[$ivp]
611 .Lcbc_abort:
612 ___
613 $code.=<<___    if ($flavour !~ /64/);
614         vldmia  sp!,{d8-d15}
615         ldmia   sp!,{r4-r8,pc}
616 ___
617 $code.=<<___    if ($flavour =~ /64/);
618         ldr     x29,[sp],#16
619         ret
620 ___
621 $code.=<<___;
622 .size   ${prefix}_cbc_encrypt,.-${prefix}_cbc_encrypt
623 ___
624 }}}
625 ########################################
626 if ($flavour =~ /64/) {                 ######## 64-bit code
627     my %opcode = (
628         "aesd"  =>      0x4e285800,     "aese"  =>      0x4e284800,
629         "aesimc"=>      0x4e287800,     "aesmc" =>      0x4e286800      );
630
631     sub unaes {
632         my ($mnemonic,$arg)=@_;
633
634         $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o   &&
635         sprintf ".long\t0x%08x\t//%s %s",
636                         $opcode{$mnemonic}|$1|($2<<5),
637                         $mnemonic,$arg;
638     }
639
640     foreach(split("\n",$code)) {
641         s/\`([^\`]*)\`/eval($1)/geo;
642
643         s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo;  # old->new registers
644         s/@\s/\/\//o;                   # old->new style commentary
645
646         #s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo     or
647         s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel $1$2,$1zr,$1$2,$3/o     or
648         s/vmov\.i8/movi/o       or      # fix up legacy mnemonics
649         s/vext\.8/ext/o         or
650         s/vrev32\.8/rev32/o     or
651         s/vtst\.8/cmtst/o       or
652         s/vshr/ushr/o           or
653         s/^(\s+)v/$1/o          or      # strip off v prefix
654         s/\bbx\s+lr\b/ret/o;
655
656         # fix up remainig legacy suffixes
657         s/\.[ui]?8//o;
658         m/\],#8/o and s/\.16b/\.8b/go;
659         s/\.[ui]?32//o and s/\.16b/\.4s/go;
660         s/\.[ui]?64//o and s/\.16b/\.2d/go;
661         s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o;
662
663         print $_,"\n";
664     }
665 } else {                                ######## 32-bit code
666     my %opcode = (
667         "aesd"  =>      0xf3b00340,     "aese"  =>      0xf3b00300,
668         "aesimc"=>      0xf3b003c0,     "aesmc" =>      0xf3b00380      );
669
670     sub unaes {
671         my ($mnemonic,$arg)=@_;
672
673         $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o   &&
674         sprintf ".long\t0x%08x\t@ %s %s",
675                         $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
676                                           |(($2&7)<<1) |(($2&8)<<2),
677                         $mnemonic,$arg;
678     }
679
680     sub unvtbl {
681         my $arg=shift;
682
683         $arg =~ m/q([0-9]+),\s*\{q([0-9]+)\},\s*q([0-9]+)/o &&
684         sprintf "vtbl.8 d%d,{q%d},d%d\n\tvtbl.8 d%d,{q%d},d%d",2*$1,$2,2*$3,2*$1+1,$2,2*$3+1;   
685     }
686
687     sub unvdup32 {
688         my $arg=shift;
689
690         $arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o &&
691         sprintf "vdup.32        q%d,d%d[%d]",$1,2*$2+$3>>1,$3&1;        
692     }
693
694     foreach(split("\n",$code)) {
695         s/\`([^\`]*)\`/eval($1)/geo;
696
697         s/\b[wx]([0-9]+)\b/r$1/go;              # new->old registers
698         s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go;   # new->old registers
699         s/\/\/\s?/@ /o;                         # new->old style commentary
700
701         # fix up remainig new-style suffixes
702         s/\],#[0-9]+/]!/o;
703
704         s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo      or
705         s/cclr\s+([^,]+),\s*([a-z]+)/mov$2      $1,#0/o or
706         s/vtbl\.8\s+(.*)/unvtbl($1)/geo                 or
707         s/vdup\.32\s+(.*)/unvdup32($1)/geo              or
708         s/^(\s+)b\./$1b/o                               or
709         s/^(\s+)ret/$1bx\tlr/o;
710
711         print $_,"\n";
712     }
713 }
714
715 close STDOUT;