]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/aes/asm/bsaes-armv7.pl
bsaes-armv7.pl: minor performance squeeze on Snapdragon S4.
[thirdparty/openssl.git] / crypto / aes / asm / bsaes-armv7.pl
CommitLineData
c4a52a6d
AP
1#!/usr/bin/env perl
2
3# ====================================================================
358c372d 4# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
c4a52a6d
AP
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# Bit-sliced AES for ARM NEON
11#
12# February 2012.
13#
14# This implementation is direct adaptation of bsaes-x86_64 module for
15# ARM NEON. Except that this module is endian-neutral [in sense that
16# it can be compiled for either endianness] by courtesy of vld1.8's
17# neutrality. Initial version doesn't implement interface to OpenSSL,
18# only low-level primitives and unsupported entry points, just enough
19# to collect performance results, which for Cortex-A8 core are:
20#
442c9f13 21# encrypt 20.0 cycles per byte processed with 128-bit key
a903e691 22# decrypt 24.5 cycles per byte processed with 128-bit key
442c9f13 23# key conv. 440 cycles per 128-bit key/0.17 of 8x block
c4a52a6d 24#
a903e691
AP
25# Snapdragon S4 encrypts byte in 18.3 cycles and decrypts in 23.3.
26#
c4a52a6d 27# When comparing to x86_64 results keep in mind that NEON unit is
a903e691
AP
28# [mostly] single-issue and thus can't [fully] benefit from
29# instruction-level parallelism. And when comparing to aes-armv4
30# results keep in mind key schedule conversion overhead (see
31# bsaes-x86_64.pl for further details)...
c4a52a6d
AP
32#
33# <appro@openssl.org>
34
35while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
36open STDOUT,">$output";
37
38my ($inp,$out,$len,$key)=("r0","r1","r2","r3");
39my @XMM=map("q$_",(0..15));
40
41{
42my ($key,$rounds,$const)=("r4","r5","r6");
43
44sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; }
45sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; }
46
47sub Sbox {
48# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
49# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb
50my @b=@_[0..7];
51my @t=@_[8..11];
52my @s=@_[12..15];
53 &InBasisChange (@b);
54 &Inv_GF256 (@b[6,5,0,3,7,1,4,2],@t,@s);
55 &OutBasisChange (@b[7,1,4,2,6,5,0,3]);
56}
57
58sub InBasisChange {
59# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
60# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb
61my @b=@_[0..7];
62$code.=<<___;
c4a52a6d 63 veor @b[2], @b[2], @b[1]
a903e691 64 veor @b[5], @b[5], @b[6]
c4a52a6d
AP
65 veor @b[3], @b[3], @b[0]
66 veor @b[6], @b[6], @b[2]
67 veor @b[5], @b[5], @b[0]
68
69 veor @b[6], @b[6], @b[3]
70 veor @b[3], @b[3], @b[7]
71 veor @b[7], @b[7], @b[5]
72 veor @b[3], @b[3], @b[4]
73 veor @b[4], @b[4], @b[5]
c4a52a6d
AP
74
75 veor @b[2], @b[2], @b[7]
a903e691 76 veor @b[3], @b[3], @b[1]
c4a52a6d
AP
77 veor @b[1], @b[1], @b[5]
78___
79}
80
81sub OutBasisChange {
82# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
83# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb
84my @b=@_[0..7];
85$code.=<<___;
86 veor @b[0], @b[0], @b[6]
87 veor @b[1], @b[1], @b[4]
c4a52a6d 88 veor @b[4], @b[4], @b[6]
a903e691 89 veor @b[2], @b[2], @b[0]
c4a52a6d
AP
90 veor @b[6], @b[6], @b[1]
91
92 veor @b[1], @b[1], @b[5]
93 veor @b[5], @b[5], @b[3]
94 veor @b[3], @b[3], @b[7]
95 veor @b[7], @b[7], @b[5]
96 veor @b[2], @b[2], @b[5]
97
98 veor @b[4], @b[4], @b[7]
99___
100}
101
102sub InvSbox {
103# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb
104# output in lsb > [b0, b1, b6, b4, b2, b7, b3, b5] < msb
105my @b=@_[0..7];
106my @t=@_[8..11];
107my @s=@_[12..15];
108 &InvInBasisChange (@b);
109 &Inv_GF256 (@b[5,1,2,6,3,7,0,4],@t,@s);
110 &InvOutBasisChange (@b[3,7,0,4,5,1,2,6]);
111}
112
a903e691 113sub InvInBasisChange { # OutBasisChange in reverse (with twist)
c4a52a6d
AP
114my @b=@_[5,1,2,6,3,7,0,4];
115$code.=<<___
a903e691 116 veor @b[1], @b[1], @b[7]
c4a52a6d
AP
117 veor @b[4], @b[4], @b[7]
118
119 veor @b[7], @b[7], @b[5]
a903e691 120 veor @b[1], @b[1], @b[3]
c4a52a6d
AP
121 veor @b[2], @b[2], @b[5]
122 veor @b[3], @b[3], @b[7]
c4a52a6d
AP
123
124 veor @b[6], @b[6], @b[1]
125 veor @b[2], @b[2], @b[0]
a903e691 126 veor @b[5], @b[5], @b[3]
c4a52a6d
AP
127 veor @b[4], @b[4], @b[6]
128 veor @b[0], @b[0], @b[6]
129 veor @b[1], @b[1], @b[4]
130___
131}
132
133sub InvOutBasisChange { # InBasisChange in reverse
134my @b=@_[2,5,7,3,6,1,0,4];
135$code.=<<___;
136 veor @b[1], @b[1], @b[5]
137 veor @b[2], @b[2], @b[7]
138
139 veor @b[3], @b[3], @b[1]
140 veor @b[4], @b[4], @b[5]
141 veor @b[7], @b[7], @b[5]
142 veor @b[3], @b[3], @b[4]
143 veor @b[5], @b[5], @b[0]
144 veor @b[3], @b[3], @b[7]
145 veor @b[6], @b[6], @b[2]
146 veor @b[2], @b[2], @b[1]
147 veor @b[6], @b[6], @b[3]
148
149 veor @b[3], @b[3], @b[0]
150 veor @b[5], @b[5], @b[6]
151___
152}
153
154sub Mul_GF4 {
155#;*************************************************************
156#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) *
157#;*************************************************************
a903e691 158my ($x0,$x1,$y0,$y1,$t0,$t1)=@_;
c4a52a6d
AP
159$code.=<<___;
160 veor $t0, $y0, $y1
161 vand $t0, $t0, $x0
162 veor $x0, $x0, $x1
a903e691 163 vand $t1, $x1, $y0
c4a52a6d 164 vand $x0, $x0, $y1
a903e691
AP
165 veor $x1, $t1, $t0
166 veor $x0, $x0, $t1
c4a52a6d
AP
167___
168}
169
170sub Mul_GF4_N { # not used, see next subroutine
171# multiply and scale by N
172my ($x0,$x1,$y0,$y1,$t0)=@_;
173$code.=<<___;
174 veor $t0, $y0, $y1
175 vand $t0, $t0, $x0
176 veor $x0, $x0, $x1
177 vand $x1, $x1, $y0
178 vand $x0, $x0, $y1
179 veor $x1, $x1, $x0
180 veor $x0, $x0, $t0
181___
182}
183
184sub Mul_GF4_N_GF4 {
185# interleaved Mul_GF4_N and Mul_GF4
186my ($x0,$x1,$y0,$y1,$t0,
187 $x2,$x3,$y2,$y3,$t1)=@_;
188$code.=<<___;
189 veor $t0, $y0, $y1
190 veor $t1, $y2, $y3
191 vand $t0, $t0, $x0
192 vand $t1, $t1, $x2
193 veor $x0, $x0, $x1
194 veor $x2, $x2, $x3
195 vand $x1, $x1, $y0
196 vand $x3, $x3, $y2
197 vand $x0, $x0, $y1
198 vand $x2, $x2, $y3
199 veor $x1, $x1, $x0
200 veor $x2, $x2, $x3
201 veor $x0, $x0, $t0
202 veor $x3, $x3, $t1
203___
204}
205sub Mul_GF16_2 {
206my @x=@_[0..7];
207my @y=@_[8..11];
208my @t=@_[12..15];
209$code.=<<___;
a903e691
AP
210 veor @t[0], @x[0], @x[2]
211 veor @t[1], @x[1], @x[3]
c4a52a6d 212___
a903e691 213 &Mul_GF4 (@x[0], @x[1], @y[0], @y[1], @t[2..3]);
c4a52a6d 214$code.=<<___;
c4a52a6d
AP
215 veor @y[0], @y[0], @y[2]
216 veor @y[1], @y[1], @y[3]
217___
218 Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3],
219 @x[2], @x[3], @y[2], @y[3], @t[2]);
220$code.=<<___;
221 veor @x[0], @x[0], @t[0]
222 veor @x[2], @x[2], @t[0]
223 veor @x[1], @x[1], @t[1]
224 veor @x[3], @x[3], @t[1]
225
226 veor @t[0], @x[4], @x[6]
227 veor @t[1], @x[5], @x[7]
228___
229 &Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3],
230 @x[6], @x[7], @y[2], @y[3], @t[2]);
231$code.=<<___;
232 veor @y[0], @y[0], @y[2]
233 veor @y[1], @y[1], @y[3]
234___
a903e691 235 &Mul_GF4 (@x[4], @x[5], @y[0], @y[1], @t[2..3]);
c4a52a6d
AP
236$code.=<<___;
237 veor @x[4], @x[4], @t[0]
238 veor @x[6], @x[6], @t[0]
239 veor @x[5], @x[5], @t[1]
240 veor @x[7], @x[7], @t[1]
241___
242}
243sub Inv_GF256 {
244#;********************************************************************
245#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144) *
246#;********************************************************************
247my @x=@_[0..7];
248my @t=@_[8..11];
249my @s=@_[12..15];
250# direct optimizations from hardware
251$code.=<<___;
252 veor @t[3], @x[4], @x[6]
253 veor @t[2], @x[5], @x[7]
254 veor @t[1], @x[1], @x[3]
255 veor @s[1], @x[7], @x[6]
256 vmov @t[0], @t[2]
257 veor @s[0], @x[0], @x[2]
258
259 vorr @t[2], @t[2], @t[1]
260 veor @s[3], @t[3], @t[0]
261 vand @s[2], @t[3], @s[0]
262 vorr @t[3], @t[3], @s[0]
263 veor @s[0], @s[0], @t[1]
264 vand @t[0], @t[0], @t[1]
265 vand @s[3], @s[3], @s[0]
266 veor @s[0], @x[3], @x[2]
267 vand @s[1], @s[1], @s[0]
268 veor @t[3], @t[3], @s[1]
269 veor @t[2], @t[2], @s[1]
270 veor @s[1], @x[4], @x[5]
271 veor @s[0], @x[1], @x[0]
272 vorr @t[1], @s[1], @s[0]
273 vand @s[1], @s[1], @s[0]
274 veor @t[0], @t[0], @s[1]
275 veor @t[3], @t[3], @s[3]
276 veor @t[2], @t[2], @s[2]
277 veor @t[1], @t[1], @s[3]
278 veor @t[0], @t[0], @s[2]
279 veor @t[1], @t[1], @s[2]
280 vand @s[0], @x[7], @x[3]
281 vand @s[1], @x[6], @x[2]
282 vand @s[2], @x[5], @x[1]
283 vorr @s[3], @x[4], @x[0]
284 veor @t[3], @t[3], @s[0]
285 veor @t[2], @t[2], @s[1]
286 veor @t[1], @t[1], @s[2]
287 veor @t[0], @t[0], @s[3]
288
289 @ Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3
290
291 @ new smaller inversion
292
293 veor @s[0], @t[3], @t[2]
294 vand @t[3], @t[3], @t[1]
295
296 veor @s[2], @t[0], @t[3]
442c9f13
AP
297 veor @s[1], @t[2], @t[3]
298
c4a52a6d 299 vand @s[3], @s[0], @s[2]
442c9f13 300 vbsl @s[1], @t[1], @t[0]
c4a52a6d
AP
301
302 veor @s[3], @s[3], @t[2]
c4a52a6d 303 veor @t[2], @s[2], @s[1]
c4a52a6d
AP
304
305 vand @t[2], @t[2], @t[0]
442c9f13 306 vbsl @t[0], @s[2], @s[1]
c4a52a6d
AP
307
308 veor @s[2], @s[2], @t[2]
442c9f13 309 veor @t[1], @t[1], @t[0]
c4a52a6d
AP
310
311 vand @s[2], @s[2], @s[3]
312
313 veor @s[2], @s[2], @s[0]
314___
315# output in s3, s2, s1, t1
316
317# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3
318
319# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3
320 &Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]);
321
322### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb
323}
324
325# AES linear components
326
327sub ShiftRows {
328my @x=@_[0..7];
329my @t=@_[8..11];
330my $mask=pop;
331$code.=<<___;
332 vldmia $key!, {@t[0]-@t[3]}
333 veor @t[0], @t[0], @x[0]
334 veor @t[1], @t[1], @x[1]
335 vtbl.8 `&Dlo(@x[0])`, {@t[0]}, `&Dlo($mask)`
336 vtbl.8 `&Dhi(@x[0])`, {@t[0]}, `&Dhi($mask)`
337 vldmia $key!, {@t[0]}
338 veor @t[2], @t[2], @x[2]
339 vtbl.8 `&Dlo(@x[1])`, {@t[1]}, `&Dlo($mask)`
340 vtbl.8 `&Dhi(@x[1])`, {@t[1]}, `&Dhi($mask)`
341 vldmia $key!, {@t[1]}
342 veor @t[3], @t[3], @x[3]
343 vtbl.8 `&Dlo(@x[2])`, {@t[2]}, `&Dlo($mask)`
344 vtbl.8 `&Dhi(@x[2])`, {@t[2]}, `&Dhi($mask)`
345 vldmia $key!, {@t[2]}
346 vtbl.8 `&Dlo(@x[3])`, {@t[3]}, `&Dlo($mask)`
347 vtbl.8 `&Dhi(@x[3])`, {@t[3]}, `&Dhi($mask)`
348 vldmia $key!, {@t[3]}
349 veor @t[0], @t[0], @x[4]
350 veor @t[1], @t[1], @x[5]
351 vtbl.8 `&Dlo(@x[4])`, {@t[0]}, `&Dlo($mask)`
352 vtbl.8 `&Dhi(@x[4])`, {@t[0]}, `&Dhi($mask)`
353 veor @t[2], @t[2], @x[6]
354 vtbl.8 `&Dlo(@x[5])`, {@t[1]}, `&Dlo($mask)`
355 vtbl.8 `&Dhi(@x[5])`, {@t[1]}, `&Dhi($mask)`
356 veor @t[3], @t[3], @x[7]
357 vtbl.8 `&Dlo(@x[6])`, {@t[2]}, `&Dlo($mask)`
358 vtbl.8 `&Dhi(@x[6])`, {@t[2]}, `&Dhi($mask)`
359 vtbl.8 `&Dlo(@x[7])`, {@t[3]}, `&Dlo($mask)`
360 vtbl.8 `&Dhi(@x[7])`, {@t[3]}, `&Dhi($mask)`
361___
362}
363
364sub MixColumns {
365# modified to emit output in order suitable for feeding back to aesenc[last]
366my @x=@_[0..7];
367my @t=@_[8..15];
368$code.=<<___;
369 vext.8 @t[0], @x[0], @x[0], #12 @ x0 <<< 32
370 vext.8 @t[1], @x[1], @x[1], #12
371 veor @x[0], @x[0], @t[0] @ x0 ^ (x0 <<< 32)
372 vext.8 @t[2], @x[2], @x[2], #12
373 veor @x[1], @x[1], @t[1]
374 vext.8 @t[3], @x[3], @x[3], #12
375 veor @x[2], @x[2], @t[2]
376 vext.8 @t[4], @x[4], @x[4], #12
377 veor @x[3], @x[3], @t[3]
378 vext.8 @t[5], @x[5], @x[5], #12
379 veor @x[4], @x[4], @t[4]
380 vext.8 @t[6], @x[6], @x[6], #12
381 veor @x[5], @x[5], @t[5]
382 vext.8 @t[7], @x[7], @x[7], #12
383 veor @x[6], @x[6], @t[6]
384 veor @x[7], @x[7], @t[7]
385
386 veor @t[1], @t[1], @x[0]
387 vext.8 @x[0], @x[0], @x[0], #8 @ (x0 ^ (x0 <<< 32)) <<< 64)
388 veor @t[0], @t[0], @x[7]
389 veor @t[1], @t[1], @x[7]
390 veor @t[2], @t[2], @x[1]
391 vext.8 @x[1], @x[1], @x[1], #8
392 veor @t[5], @t[5], @x[4]
393 veor @x[0], @x[0], @t[0]
394 veor @t[6], @t[6], @x[5]
395 veor @x[1], @x[1], @t[1]
396 vext.8 @t[0], @x[4], @x[4], #8
397 veor @t[4], @t[4], @x[3]
398 vext.8 @t[1], @x[5], @x[5], #8
399 veor @t[7], @t[7], @x[6]
400 vext.8 @x[4], @x[3], @x[3], #8
401 veor @t[3], @t[3], @x[2]
402 vext.8 @x[5], @x[7], @x[7], #8
403 veor @t[3], @t[3], @x[7]
404 vext.8 @x[3], @x[6], @x[6], #8
405 veor @t[4], @t[4], @x[7]
406 vext.8 @x[6], @x[2], @x[2], #8
c4a52a6d 407 veor @x[7], @t[1], @t[5]
a903e691 408 veor @x[2], @t[0], @t[4]
c4a52a6d
AP
409
410 veor @x[4], @x[4], @t[3]
411 veor @x[5], @x[5], @t[7]
412 veor @x[3], @x[3], @t[6]
413 @ vmov @x[2], @t[0]
414 veor @x[6], @x[6], @t[2]
415 @ vmov @x[7], @t[1]
416___
417}
418
419sub InvMixColumns {
420my @x=@_[0..7];
421my @t=@_[8..15];
422
423$code.=<<___;
424 @ multiplication by 0x0e
425 vext.8 @t[7], @x[7], @x[7], #12
426 vmov @t[2], @x[2]
c4a52a6d 427 veor @x[2], @x[2], @x[5] @ 2 5
a903e691 428 veor @x[7], @x[7], @x[5] @ 7 5
c4a52a6d
AP
429 vext.8 @t[0], @x[0], @x[0], #12
430 vmov @t[5], @x[5]
431 veor @x[5], @x[5], @x[0] @ 5 0 [1]
432 veor @x[0], @x[0], @x[1] @ 0 1
433 vext.8 @t[1], @x[1], @x[1], #12
434 veor @x[1], @x[1], @x[2] @ 1 25
435 veor @x[0], @x[0], @x[6] @ 01 6 [2]
c4a52a6d 436 vext.8 @t[3], @x[3], @x[3], #12
a903e691 437 veor @x[1], @x[1], @x[3] @ 125 3 [4]
c4a52a6d
AP
438 veor @x[2], @x[2], @x[0] @ 25 016 [3]
439 veor @x[3], @x[3], @x[7] @ 3 75
440 veor @x[7], @x[7], @x[6] @ 75 6 [0]
441 vext.8 @t[6], @x[6], @x[6], #12
442 vmov @t[4], @x[4]
443 veor @x[6], @x[6], @x[4] @ 6 4
444 veor @x[4], @x[4], @x[3] @ 4 375 [6]
445 veor @x[3], @x[3], @x[7] @ 375 756=36
446 veor @x[6], @x[6], @t[5] @ 64 5 [7]
447 veor @x[3], @x[3], @t[2] @ 36 2
448 vext.8 @t[5], @t[5], @t[5], #12
449 veor @x[3], @x[3], @t[4] @ 362 4 [5]
450___
451 my @y = @x[7,5,0,2,1,3,4,6];
452$code.=<<___;
453 @ multiplication by 0x0b
454 veor @y[1], @y[1], @y[0]
455 veor @y[0], @y[0], @t[0]
c4a52a6d 456 vext.8 @t[2], @t[2], @t[2], #12
a903e691 457 veor @y[1], @y[1], @t[1]
c4a52a6d 458 veor @y[0], @y[0], @t[5]
a903e691 459 vext.8 @t[4], @t[4], @t[4], #12
c4a52a6d
AP
460 veor @y[1], @y[1], @t[6]
461 veor @y[0], @y[0], @t[7]
c4a52a6d 462 veor @t[7], @t[7], @t[6] @ clobber t[7]
c4a52a6d
AP
463
464 veor @y[3], @y[3], @t[0]
a903e691 465 veor @y[1], @y[1], @y[0]
c4a52a6d
AP
466 vext.8 @t[0], @t[0], @t[0], #12
467 veor @y[2], @y[2], @t[1]
468 veor @y[4], @y[4], @t[1]
c4a52a6d 469 vext.8 @t[1], @t[1], @t[1], #12
a903e691 470 veor @y[2], @y[2], @t[2]
c4a52a6d
AP
471 veor @y[3], @y[3], @t[2]
472 veor @y[5], @y[5], @t[2]
473 veor @y[2], @y[2], @t[7]
474 vext.8 @t[2], @t[2], @t[2], #12
475 veor @y[3], @y[3], @t[3]
476 veor @y[6], @y[6], @t[3]
477 veor @y[4], @y[4], @t[3]
c4a52a6d 478 veor @y[7], @y[7], @t[4]
a903e691 479 vext.8 @t[3], @t[3], @t[3], #12
c4a52a6d
AP
480 veor @y[5], @y[5], @t[4]
481 veor @y[7], @y[7], @t[7]
482 veor @y[3], @y[3], @t[5]
483 veor @y[4], @y[4], @t[4]
484 veor @t[7], @t[7], @t[5] @ clobber t[7] even more
485
486 veor @y[5], @y[5], @t[7]
487 vext.8 @t[4], @t[4], @t[4], #12
488 veor @y[6], @y[6], @t[7]
489 veor @y[4], @y[4], @t[7]
490
491 veor @t[7], @t[7], @t[5]
492 vext.8 @t[5], @t[5], @t[5], #12
c4a52a6d
AP
493
494 @ multiplication by 0x0d
495 veor @y[4], @y[4], @y[7]
a903e691 496 veor @t[7], @t[7], @t[6] @ restore t[7]
c4a52a6d
AP
497 veor @y[7], @y[7], @t[4]
498 vext.8 @t[6], @t[6], @t[6], #12
499 veor @y[2], @y[2], @t[0]
500 veor @y[7], @y[7], @t[5]
c4a52a6d 501 vext.8 @t[7], @t[7], @t[7], #12
a903e691 502 veor @y[2], @y[2], @t[2]
c4a52a6d
AP
503
504 veor @y[3], @y[3], @y[1]
505 veor @y[1], @y[1], @t[1]
506 veor @y[0], @y[0], @t[0]
507 veor @y[3], @y[3], @t[0]
508 veor @y[1], @y[1], @t[5]
509 veor @y[0], @y[0], @t[5]
c4a52a6d 510 vext.8 @t[0], @t[0], @t[0], #12
a903e691 511 veor @y[1], @y[1], @t[7]
c4a52a6d
AP
512 veor @y[0], @y[0], @t[6]
513 veor @y[3], @y[3], @y[1]
514 veor @y[4], @y[4], @t[1]
515 vext.8 @t[1], @t[1], @t[1], #12
516
517 veor @y[7], @y[7], @t[7]
518 veor @y[4], @y[4], @t[2]
519 veor @y[5], @y[5], @t[2]
c4a52a6d
AP
520 veor @y[2], @y[2], @t[6]
521 veor @t[6], @t[6], @t[3] @ clobber t[6]
a903e691 522 vext.8 @t[2], @t[2], @t[2], #12
c4a52a6d
AP
523 veor @y[4], @y[4], @y[7]
524 veor @y[3], @y[3], @t[6]
525
526 veor @y[6], @y[6], @t[6]
527 veor @y[5], @y[5], @t[5]
528 vext.8 @t[5], @t[5], @t[5], #12
529 veor @y[6], @y[6], @t[4]
530 vext.8 @t[4], @t[4], @t[4], #12
531 veor @y[5], @y[5], @t[6]
532 veor @y[6], @y[6], @t[7]
533 vext.8 @t[7], @t[7], @t[7], #12
534 veor @t[6], @t[6], @t[3] @ restore t[6]
535 vext.8 @t[3], @t[3], @t[3], #12
536
537 @ multiplication by 0x09
538 veor @y[4], @y[4], @y[1]
539 veor @t[1], @t[1], @y[1] @ t[1]=y[1]
540 veor @t[0], @t[0], @t[5] @ clobber t[0]
541 vext.8 @t[6], @t[6], @t[6], #12
542 veor @t[1], @t[1], @t[5]
543 veor @y[3], @y[3], @t[0]
544 veor @t[0], @t[0], @y[0] @ t[0]=y[0]
545 veor @t[1], @t[1], @t[6]
546 veor @t[6], @t[6], @t[7] @ clobber t[6]
547 veor @y[4], @y[4], @t[1]
548 veor @y[7], @y[7], @t[4]
c4a52a6d 549 veor @y[6], @y[6], @t[3]
c4a52a6d 550 veor @y[5], @y[5], @t[2]
a903e691
AP
551 veor @t[4], @t[4], @y[4] @ t[4]=y[4]
552 veor @t[3], @t[3], @y[3] @ t[3]=y[3]
553 veor @t[5], @t[5], @y[5] @ t[5]=y[5]
c4a52a6d
AP
554 veor @t[2], @t[2], @y[2] @ t[2]=y[2]
555 veor @t[3], @t[3], @t[7]
c4a52a6d
AP
556 veor @XMM[5], @t[5], @t[6]
557 veor @XMM[6], @t[6], @y[6] @ t[6]=y[6]
558 veor @XMM[2], @t[2], @t[6]
559 veor @XMM[7], @t[7], @y[7] @ t[7]=y[7]
560
561 vmov @XMM[0], @t[0]
562 vmov @XMM[1], @t[1]
563 @ vmov @XMM[2], @t[2]
564 vmov @XMM[3], @t[3]
565 vmov @XMM[4], @t[4]
566 @ vmov @XMM[5], @t[5]
567 @ vmov @XMM[6], @t[6]
568 @ vmov @XMM[7], @t[7]
569___
570}
571
572sub swapmove {
573my ($a,$b,$n,$mask,$t)=@_;
574$code.=<<___;
575 vshr.u64 $t, $b, #$n
576 veor $t, $t, $a
577 vand $t, $t, $mask
578 veor $a, $a, $t
579 vshl.u64 $t, $t, #$n
580 veor $b, $b, $t
581___
582}
583sub swapmove2x {
584my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_;
585$code.=<<___;
586 vshr.u64 $t0, $b0, #$n
587 vshr.u64 $t1, $b1, #$n
588 veor $t0, $t0, $a0
589 veor $t1, $t1, $a1
590 vand $t0, $t0, $mask
591 vand $t1, $t1, $mask
592 veor $a0, $a0, $t0
593 vshl.u64 $t0, $t0, #$n
594 veor $a1, $a1, $t1
595 vshl.u64 $t1, $t1, #$n
596 veor $b0, $b0, $t0
597 veor $b1, $b1, $t1
598___
599}
600
601sub bitslice {
602my @x=reverse(@_[0..7]);
603my ($t0,$t1,$t2,$t3)=@_[8..11];
604$code.=<<___;
605 vmov.i8 $t0,#0x55 @ compose .LBS0
606 vmov.i8 $t1,#0x33 @ compose .LBS1
607___
608 &swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3);
609 &swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
610$code.=<<___;
611 vmov.i8 $t0,#0x0f @ compose .LBS2
612___
613 &swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3);
614 &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
615
616 &swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3);
617 &swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3);
618}
619
620$code.=<<___;
621.text
622.code 32
623.fpu neon
624
625.type _bsaes_decrypt8,%function
626.align 4
627_bsaes_decrypt8:
628 sub $const,pc,#8 @ _bsaes_decrypt8
629 vldmia $key!, {@XMM[9]} @ round 0 key
630 add $const,$const,#.LM0ISR-_bsaes_decrypt8
631
632 vldmia $const!, {@XMM[8]} @ .LM0ISR
633 veor @XMM[10], @XMM[0], @XMM[9] @ xor with round0 key
634 veor @XMM[11], @XMM[1], @XMM[9]
635 vtbl.8 `&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])`
636 vtbl.8 `&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])`
637 veor @XMM[12], @XMM[2], @XMM[9]
638 vtbl.8 `&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])`
639 vtbl.8 `&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])`
640 veor @XMM[13], @XMM[3], @XMM[9]
641 vtbl.8 `&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])`
642 vtbl.8 `&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])`
643 veor @XMM[14], @XMM[4], @XMM[9]
644 vtbl.8 `&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])`
645 vtbl.8 `&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])`
646 veor @XMM[15], @XMM[5], @XMM[9]
647 vtbl.8 `&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])`
648 vtbl.8 `&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])`
649 veor @XMM[10], @XMM[6], @XMM[9]
650 vtbl.8 `&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])`
651 vtbl.8 `&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])`
652 veor @XMM[11], @XMM[7], @XMM[9]
653 vtbl.8 `&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])`
654 vtbl.8 `&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])`
655 vtbl.8 `&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])`
656 vtbl.8 `&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])`
657___
658 &bitslice (@XMM[0..7, 8..11]);
659$code.=<<___;
660 sub $rounds,$rounds,#1
661 b .Ldec_sbox
662.align 4
663.Ldec_loop:
664___
665 &ShiftRows (@XMM[0..7, 8..12]);
666$code.=".Ldec_sbox:\n";
667 &InvSbox (@XMM[0..7, 8..15]);
668$code.=<<___;
669 subs $rounds,$rounds,#1
670 bcc .Ldec_done
671___
672 &InvMixColumns (@XMM[0,1,6,4,2,7,3,5, 8..15]);
673$code.=<<___;
674 vldmia $const, {@XMM[12]} @ .LISR
675 addeq $const,$const,#0x10
676 bne .Ldec_loop
677 vldmia $const, {@XMM[12]} @ .LISRM0
678 b .Ldec_loop
679.align 4
680.Ldec_done:
681___
682 &bitslice (@XMM[0,1,6,4,2,7,3,5, 8..11]);
683$code.=<<___;
684 vldmia $key, {@XMM[8]} @ last round key
685 veor @XMM[6], @XMM[6], @XMM[8]
686 veor @XMM[4], @XMM[4], @XMM[8]
687 veor @XMM[2], @XMM[2], @XMM[8]
688 veor @XMM[7], @XMM[7], @XMM[8]
689 veor @XMM[3], @XMM[3], @XMM[8]
690 veor @XMM[5], @XMM[5], @XMM[8]
691 veor @XMM[0], @XMM[0], @XMM[8]
692 veor @XMM[1], @XMM[1], @XMM[8]
693 bx lr
694.size _bsaes_decrypt8,.-_bsaes_decrypt8
695
696.type _bsaes_const,%object
697.align 6
698_bsaes_const:
699.LM0ISR: @ InvShiftRows constants
700 .quad 0x0a0e0206070b0f03, 0x0004080c0d010509
701.LISR:
702 .quad 0x0504070602010003, 0x0f0e0d0c080b0a09
703.LISRM0:
704 .quad 0x01040b0e0205080f, 0x0306090c00070a0d
705.LM0SR: @ ShiftRows constants
706 .quad 0x0a0e02060f03070b, 0x0004080c05090d01
707.LSR:
708 .quad 0x0504070600030201, 0x0f0e0d0c0a09080b
709.LSRM0:
710 .quad 0x0304090e00050a0f, 0x01060b0c0207080d
711.LM0:
712 .quad 0x02060a0e03070b0f, 0x0004080c0105090d
713.asciz "Bit-sliced AES for NEON, CRYPTOGAMS by <appro\@openssl.org>"
714.align 6
715.size _bsaes_const,.-_bsaes_const
716
717.type _bsaes_encrypt8,%function
718.align 4
719_bsaes_encrypt8:
720 sub $const,pc,#8 @ _bsaes_encrypt8
721 vldmia $key!, {@XMM[9]} @ round 0 key
722 sub $const,$const,#_bsaes_encrypt8-.LM0SR
723
724 vldmia $const!, {@XMM[8]} @ .LM0SR
725 veor @XMM[10], @XMM[0], @XMM[9] @ xor with round0 key
726 veor @XMM[11], @XMM[1], @XMM[9]
727 vtbl.8 `&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])`
728 vtbl.8 `&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])`
729 veor @XMM[12], @XMM[2], @XMM[9]
730 vtbl.8 `&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])`
731 vtbl.8 `&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])`
732 veor @XMM[13], @XMM[3], @XMM[9]
733 vtbl.8 `&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])`
734 vtbl.8 `&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])`
735 veor @XMM[14], @XMM[4], @XMM[9]
736 vtbl.8 `&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])`
737 vtbl.8 `&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])`
738 veor @XMM[15], @XMM[5], @XMM[9]
739 vtbl.8 `&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])`
740 vtbl.8 `&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])`
741 veor @XMM[10], @XMM[6], @XMM[9]
742 vtbl.8 `&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])`
743 vtbl.8 `&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])`
744 veor @XMM[11], @XMM[7], @XMM[9]
745 vtbl.8 `&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])`
746 vtbl.8 `&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])`
747 vtbl.8 `&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])`
748 vtbl.8 `&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])`
749_bsaes_encrypt8_bitslice:
750___
751 &bitslice (@XMM[0..7, 8..11]);
752$code.=<<___;
753 sub $rounds,$rounds,#1
754 b .Lenc_sbox
755.align 4
756.Lenc_loop:
757___
758 &ShiftRows (@XMM[0..7, 8..12]);
759$code.=".Lenc_sbox:\n";
760 &Sbox (@XMM[0..7, 8..15]);
761$code.=<<___;
762 subs $rounds,$rounds,#1
763 bcc .Lenc_done
764___
765 &MixColumns (@XMM[0,1,4,6,3,7,2,5, 8..15]);
766$code.=<<___;
767 vldmia $const, {@XMM[12]} @ .LSR
768 addeq $const,$const,#0x10
769 bne .Lenc_loop
770 vldmia $const, {@XMM[12]} @ .LSRM0
771 b .Lenc_loop
772.align 4
773.Lenc_done:
774___
775 # output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb
776 &bitslice (@XMM[0,1,4,6,3,7,2,5, 8..11]);
777$code.=<<___;
778 vldmia $key, {@XMM[8]} @ last round key
779 veor @XMM[4], @XMM[4], @XMM[8]
780 veor @XMM[6], @XMM[6], @XMM[8]
781 veor @XMM[3], @XMM[3], @XMM[8]
782 veor @XMM[7], @XMM[7], @XMM[8]
783 veor @XMM[2], @XMM[2], @XMM[8]
784 veor @XMM[5], @XMM[5], @XMM[8]
785 veor @XMM[0], @XMM[0], @XMM[8]
786 veor @XMM[1], @XMM[1], @XMM[8]
787 bx lr
788.size _bsaes_encrypt8,.-_bsaes_encrypt8
789___
790}
791{
792my ($out,$inp,$rounds,$const)=("r12","r4","r5","r6");
793
794sub bitslice_key {
795my @x=reverse(@_[0..7]);
796my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12];
797
798 &swapmove (@x[0,1],1,$bs0,$t2,$t3);
799$code.=<<___;
800 @ &swapmove(@x[2,3],1,$t0,$t2,$t3);
801 vmov @x[2], @x[0]
802 vmov @x[3], @x[1]
803___
804 #&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3);
805
806 &swapmove2x (@x[0,2,1,3],2,$bs1,$t2,$t3);
807$code.=<<___;
808 @ &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3);
809 vmov @x[4], @x[0]
810 vmov @x[6], @x[2]
811 vmov @x[5], @x[1]
812 vmov @x[7], @x[3]
813___
814 &swapmove2x (@x[0,4,1,5],4,$bs2,$t2,$t3);
815 &swapmove2x (@x[2,6,3,7],4,$bs2,$t2,$t3);
816}
817
818$code.=<<___;
819.type _bsaes_key_convert,%function
820.align 4
821_bsaes_key_convert:
822 sub $const,pc,#8 @ _bsaes_key_convert
823 vld1.8 {@XMM[7]}, [$inp]! @ load round 0 key
824 sub $const,$const,#_bsaes_key_convert-.LM0
825 vld1.8 {@XMM[15]}, [$inp]! @ load round 1 key
826
442c9f13
AP
827 vmov.i8 @XMM[8], #0x01 @ bit masks
828 vmov.i8 @XMM[9], #0x02
829 vmov.i8 @XMM[10], #0x04
830 vmov.i8 @XMM[11], #0x08
831 vmov.i8 @XMM[12], #0x10
832 vmov.i8 @XMM[13], #0x20
833 vldmia $const, {@XMM[14]} @ .LM0
c4a52a6d
AP
834
835#ifdef __ARMEL__
836 vrev32.8 @XMM[7], @XMM[7]
837 vrev32.8 @XMM[15], @XMM[15]
838#endif
839 sub $rounds,$rounds,#1
840 vstmia $out!, {@XMM[7]} @ save round 0 key
841 b .Lkey_loop
842
843.align 4
844.Lkey_loop:
442c9f13
AP
845 vtbl.8 `&Dlo(@XMM[7])`,{@XMM[15]},`&Dlo(@XMM[14])`
846 vtbl.8 `&Dhi(@XMM[7])`,{@XMM[15]},`&Dhi(@XMM[14])`
847 vmov.i8 @XMM[6], #0x40
848 vmov.i8 @XMM[15], #0x80
849
850 vtst.8 @XMM[0], @XMM[7], @XMM[8]
851 vtst.8 @XMM[1], @XMM[7], @XMM[9]
852 vtst.8 @XMM[2], @XMM[7], @XMM[10]
853 vtst.8 @XMM[3], @XMM[7], @XMM[11]
854 vtst.8 @XMM[4], @XMM[7], @XMM[12]
855 vtst.8 @XMM[5], @XMM[7], @XMM[13]
856 vtst.8 @XMM[6], @XMM[7], @XMM[6]
857 vtst.8 @XMM[7], @XMM[7], @XMM[15]
c4a52a6d 858 vld1.8 {@XMM[15]}, [$inp]! @ load next round key
442c9f13 859 vmvn @XMM[0], @XMM[0] @ "pnot"
c4a52a6d 860 vmvn @XMM[1], @XMM[1]
442c9f13
AP
861 vmvn @XMM[5], @XMM[5]
862 vmvn @XMM[6], @XMM[6]
c4a52a6d
AP
863#ifdef __ARMEL__
864 vrev32.8 @XMM[15], @XMM[15]
865#endif
866 subs $rounds,$rounds,#1
867 vstmia $out!,{@XMM[0]-@XMM[7]} @ write bit-sliced round key
868 bne .Lkey_loop
869
870 vmov.i8 @XMM[7],#0x63 @ compose .L63
871 @ don't save last round key
872 bx lr
873.size _bsaes_key_convert,.-_bsaes_key_convert
874___
875}
876
877if (1) { # following four functions are unsupported interface
878 # used for benchmarking...
879$code.=<<___;
880.globl bsaes_enc_key_convert
881.type bsaes_enc_key_convert,%function
882.align 4
883bsaes_enc_key_convert:
884 stmdb sp!,{r4-r6,lr}
885 vstmdb sp!,{d8-d15} @ ABI specification says so
886
887 ldr r5,[$inp,#240] @ pass rounds
888 mov r4,$inp @ pass key
889 mov r12,$out @ pass key schedule
890 bl _bsaes_key_convert
891 veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key
892 vstmia r12, {@XMM[7]} @ save last round key
893
894 vldmia sp!,{d8-d15}
895 ldmia sp!,{r4-r6,pc}
896.size bsaes_enc_key_convert,.-bsaes_enc_key_convert
897
898.globl bsaes_encrypt_128
899.type bsaes_encrypt_128,%function
900.align 4
901bsaes_encrypt_128:
902 stmdb sp!,{r4-r6,lr}
903 vstmdb sp!,{d8-d15} @ ABI specification says so
904.Lenc128_loop:
442c9f13
AP
905 vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input
906 vld1.8 {@XMM[2]-@XMM[3]}, [$inp]!
c4a52a6d 907 mov r4,$key @ pass the key
442c9f13 908 vld1.8 {@XMM[4]-@XMM[5]}, [$inp]!
c4a52a6d 909 mov r5,#10 @ pass rounds
442c9f13 910 vld1.8 {@XMM[6]-@XMM[7]}, [$inp]!
c4a52a6d
AP
911
912 bl _bsaes_encrypt8
913
442c9f13 914 vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
c4a52a6d
AP
915 vst1.8 {@XMM[4]}, [$out]!
916 vst1.8 {@XMM[6]}, [$out]!
917 vst1.8 {@XMM[3]}, [$out]!
918 vst1.8 {@XMM[7]}, [$out]!
919 vst1.8 {@XMM[2]}, [$out]!
920 subs $len,$len,#0x80
921 vst1.8 {@XMM[5]}, [$out]!
922 bhi .Lenc128_loop
923
924 vldmia sp!,{d8-d15}
925 ldmia sp!,{r4-r6,pc}
926.size bsaes_encrypt_128,.-bsaes_encrypt_128
927
928.globl bsaes_dec_key_convert
929.type bsaes_dec_key_convert,%function
930.align 4
931bsaes_dec_key_convert:
932 stmdb sp!,{r4-r6,lr}
933 vstmdb sp!,{d8-d15} @ ABI specification says so
934
935 ldr r5,[$inp,#240] @ pass rounds
936 mov r4,$inp @ pass key
937 mov r12,$out @ pass key schedule
938 bl _bsaes_key_convert
939 vldmia $out, {@XMM[6]}
940 vstmia r12, {@XMM[15]} @ save last round key
941 veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key
942 vstmia $out, {@XMM[7]}
943
944 vldmia sp!,{d8-d15}
945 ldmia sp!,{r4-r6,pc}
946.size bsaes_dec_key_convert,.-bsaes_dec_key_convert
947
948.globl bsaes_decrypt_128
949.type bsaes_decrypt_128,%function
950.align 4
951bsaes_decrypt_128:
952 stmdb sp!,{r4-r6,lr}
953 vstmdb sp!,{d8-d15} @ ABI specification says so
954.Ldec128_loop:
442c9f13
AP
955 vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input
956 vld1.8 {@XMM[2]-@XMM[3]}, [$inp]!
c4a52a6d 957 mov r4,$key @ pass the key
442c9f13 958 vld1.8 {@XMM[4]-@XMM[5]}, [$inp]!
c4a52a6d 959 mov r5,#10 @ pass rounds
442c9f13 960 vld1.8 {@XMM[6]-@XMM[7]}, [$inp]!
c4a52a6d
AP
961
962 bl _bsaes_decrypt8
963
442c9f13 964 vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output
c4a52a6d
AP
965 vst1.8 {@XMM[6]}, [$out]!
966 vst1.8 {@XMM[4]}, [$out]!
967 vst1.8 {@XMM[2]}, [$out]!
968 vst1.8 {@XMM[7]}, [$out]!
969 vst1.8 {@XMM[3]}, [$out]!
970 subs $len,$len,#0x80
971 vst1.8 {@XMM[5]}, [$out]!
972 bhi .Ldec128_loop
973
974 vldmia sp!,{d8-d15}
975 ldmia sp!,{r4-r6,pc}
976.size bsaes_decrypt_128,.-bsaes_decrypt_128
977___
978}
979
980$code =~ s/\`([^\`]*)\`/eval($1)/gem;
981
982print $code;
983
984close STDOUT;