1289848Sjkim#!/usr/bin/env perl
2289848Sjkim#
3289848Sjkim# ====================================================================
4289848Sjkim# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
5289848Sjkim# project. The module is, however, dual licensed under OpenSSL and
6289848Sjkim# CRYPTOGAMS licenses depending on where you obtain it. For further
7289848Sjkim# details see http://www.openssl.org/~appro/cryptogams/.
8289848Sjkim# ====================================================================
9289848Sjkim#
10289848Sjkim# This module implements support for ARMv8 AES instructions. The
11289848Sjkim# module is endian-agnostic in sense that it supports both big- and
12289848Sjkim# little-endian cases. As does it support both 32- and 64-bit modes
13289848Sjkim# of operation. Latter is achieved by limiting amount of utilized
14289848Sjkim# registers to 16, which implies additional NEON load and integer
15289848Sjkim# instructions. This has no effect on mighty Apple A7, where results
16289848Sjkim# are literally equal to the theoretical estimates based on AES
17289848Sjkim# instruction latencies and issue rates. On Cortex-A53, an in-order
18289848Sjkim# execution core, this costs up to 10-15%, which is partially
19289848Sjkim# compensated by implementing dedicated code path for 128-bit
20289848Sjkim# CBC encrypt case. On Cortex-A57 parallelizable mode performance
21289848Sjkim# seems to be limited by sheer amount of NEON instructions...
22289848Sjkim#
23289848Sjkim# Performance in cycles per byte processed with 128-bit key:
24289848Sjkim#
25289848Sjkim#		CBC enc		CBC dec		CTR
26289848Sjkim# Apple A7	2.39		1.20		1.20
27289848Sjkim# Cortex-A53	1.32		1.29		1.46
28289848Sjkim# Cortex-A57(*)	1.95		0.85		0.93
29289848Sjkim# Denver	1.96		0.86		0.80
30289848Sjkim#
31289848Sjkim# (*)	original 3.64/1.34/1.32 results were for r0p0 revision
32289848Sjkim#	and are still same even for updated module;
33289848Sjkim
34289848Sjkim$flavour = shift;
35289848Sjkimopen STDOUT,">".shift;
36289848Sjkim
37289848Sjkim$prefix="aes_v8";
38289848Sjkim
39289848Sjkim$code=<<___;
40289848Sjkim#include "arm_arch.h"
41289848Sjkim
42289848Sjkim#if __ARM_MAX_ARCH__>=7
43289848Sjkim.text
44289848Sjkim___
45325333Sjkim# $code.=".arch	armv8-a+crypto\n"			if ($flavour =~ /64/);
46289848Sjkim$code.=".arch	armv7-a\n.fpu	neon\n.code	32\n"	if ($flavour !~ /64/);
47289848Sjkim		#^^^^^^ this is done to simplify adoption by not depending
48289848Sjkim		#	on latest binutils.
49289848Sjkim
50289848Sjkim# Assembler mnemonics are an eclectic mix of 32- and 64-bit syntax,
51289848Sjkim# NEON is mostly 32-bit mnemonics, integer - mostly 64. Goal is to
52289848Sjkim# maintain both 32- and 64-bit codes within single module and
53289848Sjkim# transliterate common code to either flavour with regex vodoo.
54289848Sjkim#
55289848Sjkim{{{
56289848Sjkimmy ($inp,$bits,$out,$ptr,$rounds)=("x0","w1","x2","x3","w12");
57289848Sjkimmy ($zero,$rcon,$mask,$in0,$in1,$tmp,$key)=
58289848Sjkim	$flavour=~/64/? map("q$_",(0..6)) : map("q$_",(0..3,8..10));
59289848Sjkim
60289848Sjkim
61289848Sjkim$code.=<<___;
62289848Sjkim.align	5
63289848Sjkimrcon:
64289848Sjkim.long	0x01,0x01,0x01,0x01
65289848Sjkim.long	0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d	// rotate-n-splat
66289848Sjkim.long	0x1b,0x1b,0x1b,0x1b
67289848Sjkim
68289848Sjkim.globl	${prefix}_set_encrypt_key
69289848Sjkim.type	${prefix}_set_encrypt_key,%function
70289848Sjkim.align	5
71289848Sjkim${prefix}_set_encrypt_key:
72289848Sjkim.Lenc_key:
73289848Sjkim___
74289848Sjkim$code.=<<___	if ($flavour =~ /64/);
75289848Sjkim	stp	x29,x30,[sp,#-16]!
76289848Sjkim	add	x29,sp,#0
77289848Sjkim___
78289848Sjkim$code.=<<___;
79289848Sjkim	mov	$ptr,#-1
80289848Sjkim	cmp	$inp,#0
81289848Sjkim	b.eq	.Lenc_key_abort
82289848Sjkim	cmp	$out,#0
83289848Sjkim	b.eq	.Lenc_key_abort
84289848Sjkim	mov	$ptr,#-2
85289848Sjkim	cmp	$bits,#128
86289848Sjkim	b.lt	.Lenc_key_abort
87289848Sjkim	cmp	$bits,#256
88289848Sjkim	b.gt	.Lenc_key_abort
89289848Sjkim	tst	$bits,#0x3f
90289848Sjkim	b.ne	.Lenc_key_abort
91289848Sjkim
92289848Sjkim	adr	$ptr,rcon
93289848Sjkim	cmp	$bits,#192
94289848Sjkim
95289848Sjkim	veor	$zero,$zero,$zero
96289848Sjkim	vld1.8	{$in0},[$inp],#16
97289848Sjkim	mov	$bits,#8		// reuse $bits
98289848Sjkim	vld1.32	{$rcon,$mask},[$ptr],#32
99289848Sjkim
100289848Sjkim	b.lt	.Loop128
101289848Sjkim	b.eq	.L192
102289848Sjkim	b	.L256
103289848Sjkim
104289848Sjkim.align	4
105289848Sjkim.Loop128:
106289848Sjkim	vtbl.8	$key,{$in0},$mask
107289848Sjkim	vext.8	$tmp,$zero,$in0,#12
108289848Sjkim	vst1.32	{$in0},[$out],#16
109289848Sjkim	aese	$key,$zero
110289848Sjkim	subs	$bits,$bits,#1
111289848Sjkim
112289848Sjkim	veor	$in0,$in0,$tmp
113289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
114289848Sjkim	veor	$in0,$in0,$tmp
115289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
116289848Sjkim	 veor	$key,$key,$rcon
117289848Sjkim	veor	$in0,$in0,$tmp
118289848Sjkim	vshl.u8	$rcon,$rcon,#1
119289848Sjkim	veor	$in0,$in0,$key
120289848Sjkim	b.ne	.Loop128
121289848Sjkim
122289848Sjkim	vld1.32	{$rcon},[$ptr]
123289848Sjkim
124289848Sjkim	vtbl.8	$key,{$in0},$mask
125289848Sjkim	vext.8	$tmp,$zero,$in0,#12
126289848Sjkim	vst1.32	{$in0},[$out],#16
127289848Sjkim	aese	$key,$zero
128289848Sjkim
129289848Sjkim	veor	$in0,$in0,$tmp
130289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
131289848Sjkim	veor	$in0,$in0,$tmp
132289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
133289848Sjkim	 veor	$key,$key,$rcon
134289848Sjkim	veor	$in0,$in0,$tmp
135289848Sjkim	vshl.u8	$rcon,$rcon,#1
136289848Sjkim	veor	$in0,$in0,$key
137289848Sjkim
138289848Sjkim	vtbl.8	$key,{$in0},$mask
139289848Sjkim	vext.8	$tmp,$zero,$in0,#12
140289848Sjkim	vst1.32	{$in0},[$out],#16
141289848Sjkim	aese	$key,$zero
142289848Sjkim
143289848Sjkim	veor	$in0,$in0,$tmp
144289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
145289848Sjkim	veor	$in0,$in0,$tmp
146289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
147289848Sjkim	 veor	$key,$key,$rcon
148289848Sjkim	veor	$in0,$in0,$tmp
149289848Sjkim	veor	$in0,$in0,$key
150289848Sjkim	vst1.32	{$in0},[$out]
151289848Sjkim	add	$out,$out,#0x50
152289848Sjkim
153289848Sjkim	mov	$rounds,#10
154289848Sjkim	b	.Ldone
155289848Sjkim
156289848Sjkim.align	4
157289848Sjkim.L192:
158289848Sjkim	vld1.8	{$in1},[$inp],#8
159289848Sjkim	vmov.i8	$key,#8			// borrow $key
160289848Sjkim	vst1.32	{$in0},[$out],#16
161289848Sjkim	vsub.i8	$mask,$mask,$key	// adjust the mask
162289848Sjkim
163289848Sjkim.Loop192:
164289848Sjkim	vtbl.8	$key,{$in1},$mask
165289848Sjkim	vext.8	$tmp,$zero,$in0,#12
166289848Sjkim	vst1.32	{$in1},[$out],#8
167289848Sjkim	aese	$key,$zero
168289848Sjkim	subs	$bits,$bits,#1
169289848Sjkim
170289848Sjkim	veor	$in0,$in0,$tmp
171289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
172289848Sjkim	veor	$in0,$in0,$tmp
173289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
174289848Sjkim	veor	$in0,$in0,$tmp
175289848Sjkim
176289848Sjkim	vdup.32	$tmp,${in0}[3]
177289848Sjkim	veor	$tmp,$tmp,$in1
178289848Sjkim	 veor	$key,$key,$rcon
179289848Sjkim	vext.8	$in1,$zero,$in1,#12
180289848Sjkim	vshl.u8	$rcon,$rcon,#1
181289848Sjkim	veor	$in1,$in1,$tmp
182289848Sjkim	veor	$in0,$in0,$key
183289848Sjkim	veor	$in1,$in1,$key
184289848Sjkim	vst1.32	{$in0},[$out],#16
185289848Sjkim	b.ne	.Loop192
186289848Sjkim
187289848Sjkim	mov	$rounds,#12
188289848Sjkim	add	$out,$out,#0x20
189289848Sjkim	b	.Ldone
190289848Sjkim
191289848Sjkim.align	4
192289848Sjkim.L256:
193289848Sjkim	vld1.8	{$in1},[$inp]
194289848Sjkim	mov	$bits,#7
195289848Sjkim	mov	$rounds,#14
196289848Sjkim	vst1.32	{$in0},[$out],#16
197289848Sjkim
198289848Sjkim.Loop256:
199289848Sjkim	vtbl.8	$key,{$in1},$mask
200289848Sjkim	vext.8	$tmp,$zero,$in0,#12
201289848Sjkim	vst1.32	{$in1},[$out],#16
202289848Sjkim	aese	$key,$zero
203289848Sjkim	subs	$bits,$bits,#1
204289848Sjkim
205289848Sjkim	veor	$in0,$in0,$tmp
206289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
207289848Sjkim	veor	$in0,$in0,$tmp
208289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
209289848Sjkim	 veor	$key,$key,$rcon
210289848Sjkim	veor	$in0,$in0,$tmp
211289848Sjkim	vshl.u8	$rcon,$rcon,#1
212289848Sjkim	veor	$in0,$in0,$key
213289848Sjkim	vst1.32	{$in0},[$out],#16
214289848Sjkim	b.eq	.Ldone
215289848Sjkim
216289848Sjkim	vdup.32	$key,${in0}[3]		// just splat
217289848Sjkim	vext.8	$tmp,$zero,$in1,#12
218289848Sjkim	aese	$key,$zero
219289848Sjkim
220289848Sjkim	veor	$in1,$in1,$tmp
221289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
222289848Sjkim	veor	$in1,$in1,$tmp
223289848Sjkim	vext.8	$tmp,$zero,$tmp,#12
224289848Sjkim	veor	$in1,$in1,$tmp
225289848Sjkim
226289848Sjkim	veor	$in1,$in1,$key
227289848Sjkim	b	.Loop256
228289848Sjkim
229289848Sjkim.Ldone:
230289848Sjkim	str	$rounds,[$out]
231289848Sjkim	mov	$ptr,#0
232289848Sjkim
233289848Sjkim.Lenc_key_abort:
234289848Sjkim	mov	x0,$ptr			// return value
235289848Sjkim	`"ldr	x29,[sp],#16"		if ($flavour =~ /64/)`
236289848Sjkim	ret
237289848Sjkim.size	${prefix}_set_encrypt_key,.-${prefix}_set_encrypt_key
238289848Sjkim
239289848Sjkim.globl	${prefix}_set_decrypt_key
240289848Sjkim.type	${prefix}_set_decrypt_key,%function
241289848Sjkim.align	5
242289848Sjkim${prefix}_set_decrypt_key:
243289848Sjkim___
244289848Sjkim$code.=<<___	if ($flavour =~ /64/);
245289848Sjkim	stp	x29,x30,[sp,#-16]!
246289848Sjkim	add	x29,sp,#0
247289848Sjkim___
248289848Sjkim$code.=<<___	if ($flavour !~ /64/);
249289848Sjkim	stmdb	sp!,{r4,lr}
250289848Sjkim___
251289848Sjkim$code.=<<___;
252289848Sjkim	bl	.Lenc_key
253289848Sjkim
254289848Sjkim	cmp	x0,#0
255289848Sjkim	b.ne	.Ldec_key_abort
256289848Sjkim
257289848Sjkim	sub	$out,$out,#240		// restore original $out
258289848Sjkim	mov	x4,#-16
259289848Sjkim	add	$inp,$out,x12,lsl#4	// end of key schedule
260289848Sjkim
261289848Sjkim	vld1.32	{v0.16b},[$out]
262289848Sjkim	vld1.32	{v1.16b},[$inp]
263289848Sjkim	vst1.32	{v0.16b},[$inp],x4
264289848Sjkim	vst1.32	{v1.16b},[$out],#16
265289848Sjkim
266289848Sjkim.Loop_imc:
267289848Sjkim	vld1.32	{v0.16b},[$out]
268289848Sjkim	vld1.32	{v1.16b},[$inp]
269289848Sjkim	aesimc	v0.16b,v0.16b
270289848Sjkim	aesimc	v1.16b,v1.16b
271289848Sjkim	vst1.32	{v0.16b},[$inp],x4
272289848Sjkim	vst1.32	{v1.16b},[$out],#16
273289848Sjkim	cmp	$inp,$out
274289848Sjkim	b.hi	.Loop_imc
275289848Sjkim
276289848Sjkim	vld1.32	{v0.16b},[$out]
277289848Sjkim	aesimc	v0.16b,v0.16b
278289848Sjkim	vst1.32	{v0.16b},[$inp]
279289848Sjkim
280289848Sjkim	eor	x0,x0,x0		// return value
281289848Sjkim.Ldec_key_abort:
282289848Sjkim___
283289848Sjkim$code.=<<___	if ($flavour !~ /64/);
284289848Sjkim	ldmia	sp!,{r4,pc}
285289848Sjkim___
286289848Sjkim$code.=<<___	if ($flavour =~ /64/);
287289848Sjkim	ldp	x29,x30,[sp],#16
288289848Sjkim	ret
289289848Sjkim___
290289848Sjkim$code.=<<___;
291289848Sjkim.size	${prefix}_set_decrypt_key,.-${prefix}_set_decrypt_key
292289848Sjkim___
293289848Sjkim}}}
294289848Sjkim{{{
295289848Sjkimsub gen_block () {
296289848Sjkimmy $dir = shift;
297289848Sjkimmy ($e,$mc) = $dir eq "en" ? ("e","mc") : ("d","imc");
298289848Sjkimmy ($inp,$out,$key)=map("x$_",(0..2));
299289848Sjkimmy $rounds="w3";
300289848Sjkimmy ($rndkey0,$rndkey1,$inout)=map("q$_",(0..3));
301289848Sjkim
302289848Sjkim$code.=<<___;
303289848Sjkim.globl	${prefix}_${dir}crypt
304289848Sjkim.type	${prefix}_${dir}crypt,%function
305289848Sjkim.align	5
306289848Sjkim${prefix}_${dir}crypt:
307289848Sjkim	ldr	$rounds,[$key,#240]
308289848Sjkim	vld1.32	{$rndkey0},[$key],#16
309289848Sjkim	vld1.8	{$inout},[$inp]
310289848Sjkim	sub	$rounds,$rounds,#2
311289848Sjkim	vld1.32	{$rndkey1},[$key],#16
312289848Sjkim
313289848Sjkim.Loop_${dir}c:
314289848Sjkim	aes$e	$inout,$rndkey0
315289848Sjkim	aes$mc	$inout,$inout
316289848Sjkim	vld1.32	{$rndkey0},[$key],#16
317289848Sjkim	subs	$rounds,$rounds,#2
318289848Sjkim	aes$e	$inout,$rndkey1
319289848Sjkim	aes$mc	$inout,$inout
320289848Sjkim	vld1.32	{$rndkey1},[$key],#16
321289848Sjkim	b.gt	.Loop_${dir}c
322289848Sjkim
323289848Sjkim	aes$e	$inout,$rndkey0
324289848Sjkim	aes$mc	$inout,$inout
325289848Sjkim	vld1.32	{$rndkey0},[$key]
326289848Sjkim	aes$e	$inout,$rndkey1
327289848Sjkim	veor	$inout,$inout,$rndkey0
328289848Sjkim
329289848Sjkim	vst1.8	{$inout},[$out]
330289848Sjkim	ret
331289848Sjkim.size	${prefix}_${dir}crypt,.-${prefix}_${dir}crypt
332289848Sjkim___
333289848Sjkim}
334289848Sjkim&gen_block("en");
335289848Sjkim&gen_block("de");
336289848Sjkim}}}
337289848Sjkim{{{
338289848Sjkimmy ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4)); my $enc="w5";
339289848Sjkimmy ($rounds,$cnt,$key_,$step,$step1)=($enc,"w6","x7","x8","x12");
340289848Sjkimmy ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7));
341289848Sjkim
342289848Sjkimmy ($dat,$tmp,$rndzero_n_last)=($dat0,$tmp0,$tmp1);
343289848Sjkimmy ($key4,$key5,$key6,$key7)=("x6","x12","x14",$key);
344289848Sjkim
345289848Sjkim### q8-q15	preloaded key schedule
346289848Sjkim
347289848Sjkim$code.=<<___;
348289848Sjkim.globl	${prefix}_cbc_encrypt
349289848Sjkim.type	${prefix}_cbc_encrypt,%function
350289848Sjkim.align	5
351289848Sjkim${prefix}_cbc_encrypt:
352289848Sjkim___
353289848Sjkim$code.=<<___	if ($flavour =~ /64/);
354289848Sjkim	stp	x29,x30,[sp,#-16]!
355289848Sjkim	add	x29,sp,#0
356289848Sjkim___
357289848Sjkim$code.=<<___	if ($flavour !~ /64/);
358289848Sjkim	mov	ip,sp
359289848Sjkim	stmdb	sp!,{r4-r8,lr}
360289848Sjkim	vstmdb	sp!,{d8-d15}            @ ABI specification says so
361289848Sjkim	ldmia	ip,{r4-r5}		@ load remaining args
362289848Sjkim___
363289848Sjkim$code.=<<___;
364289848Sjkim	subs	$len,$len,#16
365289848Sjkim	mov	$step,#16
366289848Sjkim	b.lo	.Lcbc_abort
367289848Sjkim	cclr	$step,eq
368289848Sjkim
369289848Sjkim	cmp	$enc,#0			// en- or decrypting?
370289848Sjkim	ldr	$rounds,[$key,#240]
371289848Sjkim	and	$len,$len,#-16
372289848Sjkim	vld1.8	{$ivec},[$ivp]
373289848Sjkim	vld1.8	{$dat},[$inp],$step
374289848Sjkim
375289848Sjkim	vld1.32	{q8-q9},[$key]		// load key schedule...
376289848Sjkim	sub	$rounds,$rounds,#6
377289848Sjkim	add	$key_,$key,x5,lsl#4	// pointer to last 7 round keys
378289848Sjkim	sub	$rounds,$rounds,#2
379289848Sjkim	vld1.32	{q10-q11},[$key_],#32
380289848Sjkim	vld1.32	{q12-q13},[$key_],#32
381289848Sjkim	vld1.32	{q14-q15},[$key_],#32
382289848Sjkim	vld1.32	{$rndlast},[$key_]
383289848Sjkim
384289848Sjkim	add	$key_,$key,#32
385289848Sjkim	mov	$cnt,$rounds
386289848Sjkim	b.eq	.Lcbc_dec
387289848Sjkim
388289848Sjkim	cmp	$rounds,#2
389289848Sjkim	veor	$dat,$dat,$ivec
390289848Sjkim	veor	$rndzero_n_last,q8,$rndlast
391289848Sjkim	b.eq	.Lcbc_enc128
392289848Sjkim
393289848Sjkim	vld1.32	{$in0-$in1},[$key_]
394289848Sjkim	add	$key_,$key,#16
395289848Sjkim	add	$key4,$key,#16*4
396289848Sjkim	add	$key5,$key,#16*5
397289848Sjkim	aese	$dat,q8
398289848Sjkim	aesmc	$dat,$dat
399289848Sjkim	add	$key6,$key,#16*6
400289848Sjkim	add	$key7,$key,#16*7
401289848Sjkim	b	.Lenter_cbc_enc
402289848Sjkim
403289848Sjkim.align	4
404289848Sjkim.Loop_cbc_enc:
405289848Sjkim	aese	$dat,q8
406289848Sjkim	aesmc	$dat,$dat
407289848Sjkim	 vst1.8	{$ivec},[$out],#16
408289848Sjkim.Lenter_cbc_enc:
409289848Sjkim	aese	$dat,q9
410289848Sjkim	aesmc	$dat,$dat
411289848Sjkim	aese	$dat,$in0
412289848Sjkim	aesmc	$dat,$dat
413289848Sjkim	vld1.32	{q8},[$key4]
414289848Sjkim	cmp	$rounds,#4
415289848Sjkim	aese	$dat,$in1
416289848Sjkim	aesmc	$dat,$dat
417289848Sjkim	vld1.32	{q9},[$key5]
418289848Sjkim	b.eq	.Lcbc_enc192
419289848Sjkim
420289848Sjkim	aese	$dat,q8
421289848Sjkim	aesmc	$dat,$dat
422289848Sjkim	vld1.32	{q8},[$key6]
423289848Sjkim	aese	$dat,q9
424289848Sjkim	aesmc	$dat,$dat
425289848Sjkim	vld1.32	{q9},[$key7]
426289848Sjkim	nop
427289848Sjkim
428289848Sjkim.Lcbc_enc192:
429289848Sjkim	aese	$dat,q8
430289848Sjkim	aesmc	$dat,$dat
431289848Sjkim	 subs	$len,$len,#16
432289848Sjkim	aese	$dat,q9
433289848Sjkim	aesmc	$dat,$dat
434289848Sjkim	 cclr	$step,eq
435289848Sjkim	aese	$dat,q10
436289848Sjkim	aesmc	$dat,$dat
437289848Sjkim	aese	$dat,q11
438289848Sjkim	aesmc	$dat,$dat
439289848Sjkim	 vld1.8	{q8},[$inp],$step
440289848Sjkim	aese	$dat,q12
441289848Sjkim	aesmc	$dat,$dat
442289848Sjkim	 veor	q8,q8,$rndzero_n_last
443289848Sjkim	aese	$dat,q13
444289848Sjkim	aesmc	$dat,$dat
445289848Sjkim	 vld1.32 {q9},[$key_]		// re-pre-load rndkey[1]
446289848Sjkim	aese	$dat,q14
447289848Sjkim	aesmc	$dat,$dat
448289848Sjkim	aese	$dat,q15
449289848Sjkim	veor	$ivec,$dat,$rndlast
450289848Sjkim	b.hs	.Loop_cbc_enc
451289848Sjkim
452289848Sjkim	vst1.8	{$ivec},[$out],#16
453289848Sjkim	b	.Lcbc_done
454289848Sjkim
455289848Sjkim.align	5
456289848Sjkim.Lcbc_enc128:
457289848Sjkim	vld1.32	{$in0-$in1},[$key_]
458289848Sjkim	aese	$dat,q8
459289848Sjkim	aesmc	$dat,$dat
460289848Sjkim	b	.Lenter_cbc_enc128
461289848Sjkim.Loop_cbc_enc128:
462289848Sjkim	aese	$dat,q8
463289848Sjkim	aesmc	$dat,$dat
464289848Sjkim	 vst1.8	{$ivec},[$out],#16
465289848Sjkim.Lenter_cbc_enc128:
466289848Sjkim	aese	$dat,q9
467289848Sjkim	aesmc	$dat,$dat
468289848Sjkim	 subs	$len,$len,#16
469289848Sjkim	aese	$dat,$in0
470289848Sjkim	aesmc	$dat,$dat
471289848Sjkim	 cclr	$step,eq
472289848Sjkim	aese	$dat,$in1
473289848Sjkim	aesmc	$dat,$dat
474289848Sjkim	aese	$dat,q10
475289848Sjkim	aesmc	$dat,$dat
476289848Sjkim	aese	$dat,q11
477289848Sjkim	aesmc	$dat,$dat
478289848Sjkim	 vld1.8	{q8},[$inp],$step
479289848Sjkim	aese	$dat,q12
480289848Sjkim	aesmc	$dat,$dat
481289848Sjkim	aese	$dat,q13
482289848Sjkim	aesmc	$dat,$dat
483289848Sjkim	aese	$dat,q14
484289848Sjkim	aesmc	$dat,$dat
485289848Sjkim	 veor	q8,q8,$rndzero_n_last
486289848Sjkim	aese	$dat,q15
487289848Sjkim	veor	$ivec,$dat,$rndlast
488289848Sjkim	b.hs	.Loop_cbc_enc128
489289848Sjkim
490289848Sjkim	vst1.8	{$ivec},[$out],#16
491289848Sjkim	b	.Lcbc_done
492289848Sjkim___
493289848Sjkim{
494289848Sjkimmy ($dat2,$in2,$tmp2)=map("q$_",(10,11,9));
495289848Sjkim$code.=<<___;
496289848Sjkim.align	5
497289848Sjkim.Lcbc_dec:
498289848Sjkim	vld1.8	{$dat2},[$inp],#16
499289848Sjkim	subs	$len,$len,#32		// bias
500289848Sjkim	add	$cnt,$rounds,#2
501289848Sjkim	vorr	$in1,$dat,$dat
502289848Sjkim	vorr	$dat1,$dat,$dat
503289848Sjkim	vorr	$in2,$dat2,$dat2
504289848Sjkim	b.lo	.Lcbc_dec_tail
505289848Sjkim
506289848Sjkim	vorr	$dat1,$dat2,$dat2
507289848Sjkim	vld1.8	{$dat2},[$inp],#16
508289848Sjkim	vorr	$in0,$dat,$dat
509289848Sjkim	vorr	$in1,$dat1,$dat1
510289848Sjkim	vorr	$in2,$dat2,$dat2
511289848Sjkim
512289848Sjkim.Loop3x_cbc_dec:
513289848Sjkim	aesd	$dat0,q8
514289848Sjkim	aesimc	$dat0,$dat0
515289848Sjkim	aesd	$dat1,q8
516289848Sjkim	aesimc	$dat1,$dat1
517289848Sjkim	aesd	$dat2,q8
518289848Sjkim	aesimc	$dat2,$dat2
519289848Sjkim	vld1.32	{q8},[$key_],#16
520289848Sjkim	subs	$cnt,$cnt,#2
521289848Sjkim	aesd	$dat0,q9
522289848Sjkim	aesimc	$dat0,$dat0
523289848Sjkim	aesd	$dat1,q9
524289848Sjkim	aesimc	$dat1,$dat1
525289848Sjkim	aesd	$dat2,q9
526289848Sjkim	aesimc	$dat2,$dat2
527289848Sjkim	vld1.32	{q9},[$key_],#16
528289848Sjkim	b.gt	.Loop3x_cbc_dec
529289848Sjkim
530289848Sjkim	aesd	$dat0,q8
531289848Sjkim	aesimc	$dat0,$dat0
532289848Sjkim	aesd	$dat1,q8
533289848Sjkim	aesimc	$dat1,$dat1
534289848Sjkim	aesd	$dat2,q8
535289848Sjkim	aesimc	$dat2,$dat2
536289848Sjkim	 veor	$tmp0,$ivec,$rndlast
537289848Sjkim	 subs	$len,$len,#0x30
538289848Sjkim	 veor	$tmp1,$in0,$rndlast
539289848Sjkim	 mov.lo	x6,$len			// x6, $cnt, is zero at this point
540289848Sjkim	aesd	$dat0,q9
541289848Sjkim	aesimc	$dat0,$dat0
542289848Sjkim	aesd	$dat1,q9
543289848Sjkim	aesimc	$dat1,$dat1
544289848Sjkim	aesd	$dat2,q9
545289848Sjkim	aesimc	$dat2,$dat2
546289848Sjkim	 veor	$tmp2,$in1,$rndlast
547289848Sjkim	 add	$inp,$inp,x6		// $inp is adjusted in such way that
548289848Sjkim					// at exit from the loop $dat1-$dat2
549289848Sjkim					// are loaded with last "words"
550289848Sjkim	 vorr	$ivec,$in2,$in2
551289848Sjkim	 mov	$key_,$key
552289848Sjkim	aesd	$dat0,q12
553289848Sjkim	aesimc	$dat0,$dat0
554289848Sjkim	aesd	$dat1,q12
555289848Sjkim	aesimc	$dat1,$dat1
556289848Sjkim	aesd	$dat2,q12
557289848Sjkim	aesimc	$dat2,$dat2
558289848Sjkim	 vld1.8	{$in0},[$inp],#16
559289848Sjkim	aesd	$dat0,q13
560289848Sjkim	aesimc	$dat0,$dat0
561289848Sjkim	aesd	$dat1,q13
562289848Sjkim	aesimc	$dat1,$dat1
563289848Sjkim	aesd	$dat2,q13
564289848Sjkim	aesimc	$dat2,$dat2
565289848Sjkim	 vld1.8	{$in1},[$inp],#16
566289848Sjkim	aesd	$dat0,q14
567289848Sjkim	aesimc	$dat0,$dat0
568289848Sjkim	aesd	$dat1,q14
569289848Sjkim	aesimc	$dat1,$dat1
570289848Sjkim	aesd	$dat2,q14
571289848Sjkim	aesimc	$dat2,$dat2
572289848Sjkim	 vld1.8	{$in2},[$inp],#16
573289848Sjkim	aesd	$dat0,q15
574289848Sjkim	aesd	$dat1,q15
575289848Sjkim	aesd	$dat2,q15
576289848Sjkim	 vld1.32 {q8},[$key_],#16	// re-pre-load rndkey[0]
577289848Sjkim	 add	$cnt,$rounds,#2
578289848Sjkim	veor	$tmp0,$tmp0,$dat0
579289848Sjkim	veor	$tmp1,$tmp1,$dat1
580289848Sjkim	veor	$dat2,$dat2,$tmp2
581289848Sjkim	 vld1.32 {q9},[$key_],#16	// re-pre-load rndkey[1]
582289848Sjkim	vst1.8	{$tmp0},[$out],#16
583289848Sjkim	 vorr	$dat0,$in0,$in0
584289848Sjkim	vst1.8	{$tmp1},[$out],#16
585289848Sjkim	 vorr	$dat1,$in1,$in1
586289848Sjkim	vst1.8	{$dat2},[$out],#16
587289848Sjkim	 vorr	$dat2,$in2,$in2
588289848Sjkim	b.hs	.Loop3x_cbc_dec
589289848Sjkim
590289848Sjkim	cmn	$len,#0x30
591289848Sjkim	b.eq	.Lcbc_done
592289848Sjkim	nop
593289848Sjkim
594289848Sjkim.Lcbc_dec_tail:
595289848Sjkim	aesd	$dat1,q8
596289848Sjkim	aesimc	$dat1,$dat1
597289848Sjkim	aesd	$dat2,q8
598289848Sjkim	aesimc	$dat2,$dat2
599289848Sjkim	vld1.32	{q8},[$key_],#16
600289848Sjkim	subs	$cnt,$cnt,#2
601289848Sjkim	aesd	$dat1,q9
602289848Sjkim	aesimc	$dat1,$dat1
603289848Sjkim	aesd	$dat2,q9
604289848Sjkim	aesimc	$dat2,$dat2
605289848Sjkim	vld1.32	{q9},[$key_],#16
606289848Sjkim	b.gt	.Lcbc_dec_tail
607289848Sjkim
608289848Sjkim	aesd	$dat1,q8
609289848Sjkim	aesimc	$dat1,$dat1
610289848Sjkim	aesd	$dat2,q8
611289848Sjkim	aesimc	$dat2,$dat2
612289848Sjkim	aesd	$dat1,q9
613289848Sjkim	aesimc	$dat1,$dat1
614289848Sjkim	aesd	$dat2,q9
615289848Sjkim	aesimc	$dat2,$dat2
616289848Sjkim	aesd	$dat1,q12
617289848Sjkim	aesimc	$dat1,$dat1
618289848Sjkim	aesd	$dat2,q12
619289848Sjkim	aesimc	$dat2,$dat2
620289848Sjkim	 cmn	$len,#0x20
621289848Sjkim	aesd	$dat1,q13
622289848Sjkim	aesimc	$dat1,$dat1
623289848Sjkim	aesd	$dat2,q13
624289848Sjkim	aesimc	$dat2,$dat2
625289848Sjkim	 veor	$tmp1,$ivec,$rndlast
626289848Sjkim	aesd	$dat1,q14
627289848Sjkim	aesimc	$dat1,$dat1
628289848Sjkim	aesd	$dat2,q14
629289848Sjkim	aesimc	$dat2,$dat2
630289848Sjkim	 veor	$tmp2,$in1,$rndlast
631289848Sjkim	aesd	$dat1,q15
632289848Sjkim	aesd	$dat2,q15
633289848Sjkim	b.eq	.Lcbc_dec_one
634289848Sjkim	veor	$tmp1,$tmp1,$dat1
635289848Sjkim	veor	$tmp2,$tmp2,$dat2
636289848Sjkim	 vorr	$ivec,$in2,$in2
637289848Sjkim	vst1.8	{$tmp1},[$out],#16
638289848Sjkim	vst1.8	{$tmp2},[$out],#16
639289848Sjkim	b	.Lcbc_done
640289848Sjkim
641289848Sjkim.Lcbc_dec_one:
642289848Sjkim	veor	$tmp1,$tmp1,$dat2
643289848Sjkim	 vorr	$ivec,$in2,$in2
644289848Sjkim	vst1.8	{$tmp1},[$out],#16
645289848Sjkim
646289848Sjkim.Lcbc_done:
647289848Sjkim	vst1.8	{$ivec},[$ivp]
648289848Sjkim.Lcbc_abort:
649289848Sjkim___
650289848Sjkim}
651289848Sjkim$code.=<<___	if ($flavour !~ /64/);
652289848Sjkim	vldmia	sp!,{d8-d15}
653289848Sjkim	ldmia	sp!,{r4-r8,pc}
654289848Sjkim___
655289848Sjkim$code.=<<___	if ($flavour =~ /64/);
656289848Sjkim	ldr	x29,[sp],#16
657289848Sjkim	ret
658289848Sjkim___
659289848Sjkim$code.=<<___;
660289848Sjkim.size	${prefix}_cbc_encrypt,.-${prefix}_cbc_encrypt
661289848Sjkim___
662289848Sjkim}}}
663289848Sjkim{{{
664289848Sjkimmy ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4));
665289848Sjkimmy ($rounds,$cnt,$key_)=("w5","w6","x7");
666289848Sjkimmy ($ctr,$tctr0,$tctr1,$tctr2)=map("w$_",(8..10,12));
667289848Sjkimmy $step="x12";		# aliases with $tctr2
668289848Sjkim
669289848Sjkimmy ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7));
670289848Sjkimmy ($dat2,$in2,$tmp2)=map("q$_",(10,11,9));
671289848Sjkim
672289848Sjkimmy ($dat,$tmp)=($dat0,$tmp0);
673289848Sjkim
674289848Sjkim### q8-q15	preloaded key schedule
675289848Sjkim
676289848Sjkim$code.=<<___;
677289848Sjkim.globl	${prefix}_ctr32_encrypt_blocks
678289848Sjkim.type	${prefix}_ctr32_encrypt_blocks,%function
679289848Sjkim.align	5
680289848Sjkim${prefix}_ctr32_encrypt_blocks:
681289848Sjkim___
682289848Sjkim$code.=<<___	if ($flavour =~ /64/);
683289848Sjkim	stp		x29,x30,[sp,#-16]!
684289848Sjkim	add		x29,sp,#0
685289848Sjkim___
686289848Sjkim$code.=<<___	if ($flavour !~ /64/);
687289848Sjkim	mov		ip,sp
688289848Sjkim	stmdb		sp!,{r4-r10,lr}
689289848Sjkim	vstmdb		sp!,{d8-d15}            @ ABI specification says so
690289848Sjkim	ldr		r4, [ip]		@ load remaining arg
691289848Sjkim___
692289848Sjkim$code.=<<___;
693289848Sjkim	ldr		$rounds,[$key,#240]
694289848Sjkim
695289848Sjkim	ldr		$ctr, [$ivp, #12]
696289848Sjkim	vld1.32		{$dat0},[$ivp]
697289848Sjkim
698289848Sjkim	vld1.32		{q8-q9},[$key]		// load key schedule...
699289848Sjkim	sub		$rounds,$rounds,#4
700289848Sjkim	mov		$step,#16
701289848Sjkim	cmp		$len,#2
702289848Sjkim	add		$key_,$key,x5,lsl#4	// pointer to last 5 round keys
703289848Sjkim	sub		$rounds,$rounds,#2
704289848Sjkim	vld1.32		{q12-q13},[$key_],#32
705289848Sjkim	vld1.32		{q14-q15},[$key_],#32
706289848Sjkim	vld1.32		{$rndlast},[$key_]
707289848Sjkim	add		$key_,$key,#32
708289848Sjkim	mov		$cnt,$rounds
709289848Sjkim	cclr		$step,lo
710289848Sjkim#ifndef __ARMEB__
711289848Sjkim	rev		$ctr, $ctr
712289848Sjkim#endif
713289848Sjkim	vorr		$dat1,$dat0,$dat0
714289848Sjkim	add		$tctr1, $ctr, #1
715289848Sjkim	vorr		$dat2,$dat0,$dat0
716289848Sjkim	add		$ctr, $ctr, #2
717289848Sjkim	vorr		$ivec,$dat0,$dat0
718289848Sjkim	rev		$tctr1, $tctr1
719289848Sjkim	vmov.32		${dat1}[3],$tctr1
720289848Sjkim	b.ls		.Lctr32_tail
721289848Sjkim	rev		$tctr2, $ctr
722289848Sjkim	sub		$len,$len,#3		// bias
723289848Sjkim	vmov.32		${dat2}[3],$tctr2
724289848Sjkim	b		.Loop3x_ctr32
725289848Sjkim
726289848Sjkim.align	4
727289848Sjkim.Loop3x_ctr32:
728289848Sjkim	aese		$dat0,q8
729289848Sjkim	aesmc		$dat0,$dat0
730289848Sjkim	aese		$dat1,q8
731289848Sjkim	aesmc		$dat1,$dat1
732289848Sjkim	aese		$dat2,q8
733289848Sjkim	aesmc		$dat2,$dat2
734289848Sjkim	vld1.32		{q8},[$key_],#16
735289848Sjkim	subs		$cnt,$cnt,#2
736289848Sjkim	aese		$dat0,q9
737289848Sjkim	aesmc		$dat0,$dat0
738289848Sjkim	aese		$dat1,q9
739289848Sjkim	aesmc		$dat1,$dat1
740289848Sjkim	aese		$dat2,q9
741289848Sjkim	aesmc		$dat2,$dat2
742289848Sjkim	vld1.32		{q9},[$key_],#16
743289848Sjkim	b.gt		.Loop3x_ctr32
744289848Sjkim
745289848Sjkim	aese		$dat0,q8
746289848Sjkim	aesmc		$tmp0,$dat0
747289848Sjkim	aese		$dat1,q8
748289848Sjkim	aesmc		$tmp1,$dat1
749289848Sjkim	 vld1.8		{$in0},[$inp],#16
750289848Sjkim	 vorr		$dat0,$ivec,$ivec
751289848Sjkim	aese		$dat2,q8
752289848Sjkim	aesmc		$dat2,$dat2
753289848Sjkim	 vld1.8		{$in1},[$inp],#16
754289848Sjkim	 vorr		$dat1,$ivec,$ivec
755289848Sjkim	aese		$tmp0,q9
756289848Sjkim	aesmc		$tmp0,$tmp0
757289848Sjkim	aese		$tmp1,q9
758289848Sjkim	aesmc		$tmp1,$tmp1
759289848Sjkim	 vld1.8		{$in2},[$inp],#16
760289848Sjkim	 mov		$key_,$key
761289848Sjkim	aese		$dat2,q9
762289848Sjkim	aesmc		$tmp2,$dat2
763289848Sjkim	 vorr		$dat2,$ivec,$ivec
764289848Sjkim	 add		$tctr0,$ctr,#1
765289848Sjkim	aese		$tmp0,q12
766289848Sjkim	aesmc		$tmp0,$tmp0
767289848Sjkim	aese		$tmp1,q12
768289848Sjkim	aesmc		$tmp1,$tmp1
769289848Sjkim	 veor		$in0,$in0,$rndlast
770289848Sjkim	 add		$tctr1,$ctr,#2
771289848Sjkim	aese		$tmp2,q12
772289848Sjkim	aesmc		$tmp2,$tmp2
773289848Sjkim	 veor		$in1,$in1,$rndlast
774289848Sjkim	 add		$ctr,$ctr,#3
775289848Sjkim	aese		$tmp0,q13
776289848Sjkim	aesmc		$tmp0,$tmp0
777289848Sjkim	aese		$tmp1,q13
778289848Sjkim	aesmc		$tmp1,$tmp1
779289848Sjkim	 veor		$in2,$in2,$rndlast
780289848Sjkim	 rev		$tctr0,$tctr0
781289848Sjkim	aese		$tmp2,q13
782289848Sjkim	aesmc		$tmp2,$tmp2
783289848Sjkim	 vmov.32	${dat0}[3], $tctr0
784289848Sjkim	 rev		$tctr1,$tctr1
785289848Sjkim	aese		$tmp0,q14
786289848Sjkim	aesmc		$tmp0,$tmp0
787289848Sjkim	aese		$tmp1,q14
788289848Sjkim	aesmc		$tmp1,$tmp1
789289848Sjkim	 vmov.32	${dat1}[3], $tctr1
790289848Sjkim	 rev		$tctr2,$ctr
791289848Sjkim	aese		$tmp2,q14
792289848Sjkim	aesmc		$tmp2,$tmp2
793289848Sjkim	 vmov.32	${dat2}[3], $tctr2
794289848Sjkim	 subs		$len,$len,#3
795289848Sjkim	aese		$tmp0,q15
796289848Sjkim	aese		$tmp1,q15
797289848Sjkim	aese		$tmp2,q15
798289848Sjkim
799289848Sjkim	veor		$in0,$in0,$tmp0
800289848Sjkim	 vld1.32	 {q8},[$key_],#16	// re-pre-load rndkey[0]
801289848Sjkim	vst1.8		{$in0},[$out],#16
802289848Sjkim	veor		$in1,$in1,$tmp1
803289848Sjkim	 mov		$cnt,$rounds
804289848Sjkim	vst1.8		{$in1},[$out],#16
805289848Sjkim	veor		$in2,$in2,$tmp2
806289848Sjkim	 vld1.32	 {q9},[$key_],#16	// re-pre-load rndkey[1]
807289848Sjkim	vst1.8		{$in2},[$out],#16
808289848Sjkim	b.hs		.Loop3x_ctr32
809289848Sjkim
810289848Sjkim	adds		$len,$len,#3
811289848Sjkim	b.eq		.Lctr32_done
812289848Sjkim	cmp		$len,#1
813289848Sjkim	mov		$step,#16
814289848Sjkim	cclr		$step,eq
815289848Sjkim
816289848Sjkim.Lctr32_tail:
817289848Sjkim	aese		$dat0,q8
818289848Sjkim	aesmc		$dat0,$dat0
819289848Sjkim	aese		$dat1,q8
820289848Sjkim	aesmc		$dat1,$dat1
821289848Sjkim	vld1.32		{q8},[$key_],#16
822289848Sjkim	subs		$cnt,$cnt,#2
823289848Sjkim	aese		$dat0,q9
824289848Sjkim	aesmc		$dat0,$dat0
825289848Sjkim	aese		$dat1,q9
826289848Sjkim	aesmc		$dat1,$dat1
827289848Sjkim	vld1.32		{q9},[$key_],#16
828289848Sjkim	b.gt		.Lctr32_tail
829289848Sjkim
830289848Sjkim	aese		$dat0,q8
831289848Sjkim	aesmc		$dat0,$dat0
832289848Sjkim	aese		$dat1,q8
833289848Sjkim	aesmc		$dat1,$dat1
834289848Sjkim	aese		$dat0,q9
835289848Sjkim	aesmc		$dat0,$dat0
836289848Sjkim	aese		$dat1,q9
837289848Sjkim	aesmc		$dat1,$dat1
838289848Sjkim	 vld1.8		{$in0},[$inp],$step
839289848Sjkim	aese		$dat0,q12
840289848Sjkim	aesmc		$dat0,$dat0
841289848Sjkim	aese		$dat1,q12
842289848Sjkim	aesmc		$dat1,$dat1
843289848Sjkim	 vld1.8		{$in1},[$inp]
844289848Sjkim	aese		$dat0,q13
845289848Sjkim	aesmc		$dat0,$dat0
846289848Sjkim	aese		$dat1,q13
847289848Sjkim	aesmc		$dat1,$dat1
848289848Sjkim	 veor		$in0,$in0,$rndlast
849289848Sjkim	aese		$dat0,q14
850289848Sjkim	aesmc		$dat0,$dat0
851289848Sjkim	aese		$dat1,q14
852289848Sjkim	aesmc		$dat1,$dat1
853289848Sjkim	 veor		$in1,$in1,$rndlast
854289848Sjkim	aese		$dat0,q15
855289848Sjkim	aese		$dat1,q15
856289848Sjkim
857289848Sjkim	cmp		$len,#1
858289848Sjkim	veor		$in0,$in0,$dat0
859289848Sjkim	veor		$in1,$in1,$dat1
860289848Sjkim	vst1.8		{$in0},[$out],#16
861289848Sjkim	b.eq		.Lctr32_done
862289848Sjkim	vst1.8		{$in1},[$out]
863289848Sjkim
864289848Sjkim.Lctr32_done:
865289848Sjkim___
866289848Sjkim$code.=<<___	if ($flavour !~ /64/);
867289848Sjkim	vldmia		sp!,{d8-d15}
868289848Sjkim	ldmia		sp!,{r4-r10,pc}
869289848Sjkim___
870289848Sjkim$code.=<<___	if ($flavour =~ /64/);
871289848Sjkim	ldr		x29,[sp],#16
872289848Sjkim	ret
873289848Sjkim___
874289848Sjkim$code.=<<___;
875289848Sjkim.size	${prefix}_ctr32_encrypt_blocks,.-${prefix}_ctr32_encrypt_blocks
876289848Sjkim___
877289848Sjkim}}}
878289848Sjkim$code.=<<___;
879289848Sjkim#endif
880289848Sjkim___
881289848Sjkim########################################
882289848Sjkimif ($flavour =~ /64/) {			######## 64-bit code
883289848Sjkim    my %opcode = (
884289848Sjkim	"aesd"	=>	0x4e285800,	"aese"	=>	0x4e284800,
885289848Sjkim	"aesimc"=>	0x4e287800,	"aesmc"	=>	0x4e286800	);
886289848Sjkim
887289848Sjkim    local *unaes = sub {
888289848Sjkim	my ($mnemonic,$arg)=@_;
889289848Sjkim
890289848Sjkim	$arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o	&&
891289848Sjkim	sprintf ".inst\t0x%08x\t//%s %s",
892289848Sjkim			$opcode{$mnemonic}|$1|($2<<5),
893289848Sjkim			$mnemonic,$arg;
894289848Sjkim    };
895289848Sjkim
896289848Sjkim    foreach(split("\n",$code)) {
897289848Sjkim	s/\`([^\`]*)\`/eval($1)/geo;
898289848Sjkim
899289848Sjkim	s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo;	# old->new registers
900289848Sjkim	s/@\s/\/\//o;			# old->new style commentary
901289848Sjkim
902289848Sjkim	#s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo	or
903289848Sjkim	s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel	$1$2,$1zr,$1$2,$3/o	or
904289848Sjkim	s/mov\.([a-z]+)\s+([wx][0-9]+),\s*([wx][0-9]+)/csel	$2,$3,$2,$1/o	or
905289848Sjkim	s/vmov\.i8/movi/o	or	# fix up legacy mnemonics
906289848Sjkim	s/vext\.8/ext/o		or
907289848Sjkim	s/vrev32\.8/rev32/o	or
908289848Sjkim	s/vtst\.8/cmtst/o	or
909289848Sjkim	s/vshr/ushr/o		or
910289848Sjkim	s/^(\s+)v/$1/o		or	# strip off v prefix
911289848Sjkim	s/\bbx\s+lr\b/ret/o;
912289848Sjkim
913289848Sjkim	# fix up remainig legacy suffixes
914289848Sjkim	s/\.[ui]?8//o;
915289848Sjkim	m/\],#8/o and s/\.16b/\.8b/go;
916289848Sjkim	s/\.[ui]?32//o and s/\.16b/\.4s/go;
917289848Sjkim	s/\.[ui]?64//o and s/\.16b/\.2d/go;
918289848Sjkim	s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o;
919289848Sjkim
920289848Sjkim	print $_,"\n";
921289848Sjkim    }
922289848Sjkim} else {				######## 32-bit code
923289848Sjkim    my %opcode = (
924289848Sjkim	"aesd"	=>	0xf3b00340,	"aese"	=>	0xf3b00300,
925289848Sjkim	"aesimc"=>	0xf3b003c0,	"aesmc"	=>	0xf3b00380	);
926289848Sjkim
927289848Sjkim    local *unaes = sub {
928289848Sjkim	my ($mnemonic,$arg)=@_;
929289848Sjkim
930289848Sjkim	if ($arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o) {
931289848Sjkim	    my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
932289848Sjkim					 |(($2&7)<<1) |(($2&8)<<2);
933289848Sjkim	    # since ARMv7 instructions are always encoded little-endian.
934289848Sjkim	    # correct solution is to use .inst directive, but older
935289848Sjkim	    # assemblers don't implement it:-(
936289848Sjkim	    sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s",
937289848Sjkim			$word&0xff,($word>>8)&0xff,
938289848Sjkim			($word>>16)&0xff,($word>>24)&0xff,
939289848Sjkim			$mnemonic,$arg;
940289848Sjkim	}
941289848Sjkim    };
942289848Sjkim
943289848Sjkim    sub unvtbl {
944289848Sjkim	my $arg=shift;
945289848Sjkim
946289848Sjkim	$arg =~ m/q([0-9]+),\s*\{q([0-9]+)\},\s*q([0-9]+)/o &&
947289848Sjkim	sprintf	"vtbl.8	d%d,{q%d},d%d\n\t".
948289848Sjkim		"vtbl.8	d%d,{q%d},d%d", 2*$1,$2,2*$3, 2*$1+1,$2,2*$3+1;
949289848Sjkim    }
950289848Sjkim
951289848Sjkim    sub unvdup32 {
952289848Sjkim	my $arg=shift;
953289848Sjkim
954289848Sjkim	$arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o &&
955289848Sjkim	sprintf	"vdup.32	q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1;
956289848Sjkim    }
957289848Sjkim
958289848Sjkim    sub unvmov32 {
959289848Sjkim	my $arg=shift;
960289848Sjkim
961289848Sjkim	$arg =~ m/q([0-9]+)\[([0-3])\],(.*)/o &&
962289848Sjkim	sprintf	"vmov.32	d%d[%d],%s",2*$1+($2>>1),$2&1,$3;
963289848Sjkim    }
964289848Sjkim
965289848Sjkim    foreach(split("\n",$code)) {
966289848Sjkim	s/\`([^\`]*)\`/eval($1)/geo;
967289848Sjkim
968289848Sjkim	s/\b[wx]([0-9]+)\b/r$1/go;		# new->old registers
969289848Sjkim	s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go;	# new->old registers
970289848Sjkim	s/\/\/\s?/@ /o;				# new->old style commentary
971289848Sjkim
972289848Sjkim	# fix up remainig new-style suffixes
973289848Sjkim	s/\{q([0-9]+)\},\s*\[(.+)\],#8/sprintf "{d%d},[$2]!",2*$1/eo	or
974289848Sjkim	s/\],#[0-9]+/]!/o;
975289848Sjkim
976289848Sjkim	s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo	or
977289848Sjkim	s/cclr\s+([^,]+),\s*([a-z]+)/mov$2	$1,#0/o	or
978289848Sjkim	s/vtbl\.8\s+(.*)/unvtbl($1)/geo			or
979289848Sjkim	s/vdup\.32\s+(.*)/unvdup32($1)/geo		or
980289848Sjkim	s/vmov\.32\s+(.*)/unvmov32($1)/geo		or
981289848Sjkim	s/^(\s+)b\./$1b/o				or
982289848Sjkim	s/^(\s+)mov\./$1mov/o				or
983289848Sjkim	s/^(\s+)ret/$1bx\tlr/o;
984289848Sjkim
985289848Sjkim	print $_,"\n";
986289848Sjkim    }
987289848Sjkim}
988289848Sjkim
989289848Sjkimclose STDOUT;
990