SPARCv9 assembly pack: unify build rules and argument handling.
[openssl.git] / crypto / bn / asm / sparcv9-mont.pl
1 #!/usr/bin/env perl
2
3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> 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 # December 2005
11 #
12 # Pure SPARCv9/8+ and IALU-only bn_mul_mont implementation. The reasons
13 # for undertaken effort are multiple. First of all, UltraSPARC is not
14 # the whole SPARCv9 universe and other VIS-free implementations deserve
15 # optimized code as much. Secondly, newly introduced UltraSPARC T1,
16 # a.k.a. Niagara, has shared FPU and concurrent FPU-intensive pathes,
17 # such as sparcv9a-mont, will simply sink it. Yes, T1 is equipped with
18 # several integrated RSA/DSA accelerator circuits accessible through
19 # kernel driver [only(*)], but having decent user-land software
20 # implementation is important too. Finally, reasons like desire to
21 # experiment with dedicated squaring procedure. Yes, this module
22 # implements one, because it was easiest to draft it in SPARCv9
23 # instructions...
24
25 # (*)   Engine accessing the driver in question is on my TODO list.
26 #       For reference, acceleator is estimated to give 6 to 10 times
27 #       improvement on single-threaded RSA sign. It should be noted
28 #       that 6-10x improvement coefficient does not actually mean
29 #       something extraordinary in terms of absolute [single-threaded]
30 #       performance, as SPARCv9 instruction set is by all means least
31 #       suitable for high performance crypto among other 64 bit
32 #       platforms. 6-10x factor simply places T1 in same performance
33 #       domain as say AMD64 and IA-64. Improvement of RSA verify don't
34 #       appear impressive at all, but it's the sign operation which is
35 #       far more critical/interesting.
36
37 # You might notice that inner loops are modulo-scheduled:-) This has
38 # essentially negligible impact on UltraSPARC performance, it's
39 # Fujitsu SPARC64 V users who should notice and hopefully appreciate
40 # the advantage... Currently this module surpasses sparcv9a-mont.pl
41 # by ~20% on UltraSPARC-III and later cores, but recall that sparcv9a
42 # module still have hidden potential [see TODO list there], which is
43 # estimated to be larger than 20%...
44
45 $output = pop;
46 open STDOUT,">$output";
47
48 # int bn_mul_mont(
49 $rp="%i0";      # BN_ULONG *rp,
50 $ap="%i1";      # const BN_ULONG *ap,
51 $bp="%i2";      # const BN_ULONG *bp,
52 $np="%i3";      # const BN_ULONG *np,
53 $n0="%i4";      # const BN_ULONG *n0,
54 $num="%i5";     # int num);
55
56 $frame="STACK_FRAME";
57 $bias="STACK_BIAS";
58
59 $car0="%o0";
60 $car1="%o1";
61 $car2="%o2";    # 1 bit
62 $acc0="%o3";
63 $acc1="%o4";
64 $mask="%g1";    # 32 bits, what a waste...
65 $tmp0="%g4";
66 $tmp1="%g5";
67
68 $i="%l0";
69 $j="%l1";
70 $mul0="%l2";
71 $mul1="%l3";
72 $tp="%l4";
73 $apj="%l5";
74 $npj="%l6";
75 $tpj="%l7";
76
77 $fname="bn_mul_mont_int";
78
79 $code=<<___;
80 #include "sparc_arch.h"
81
82 .section        ".text",#alloc,#execinstr
83
84 .global $fname
85 .align  32
86 $fname:
87         cmp     %o5,4                   ! 128 bits minimum
88         bge,pt  %icc,.Lenter
89         sethi   %hi(0xffffffff),$mask
90         retl
91         clr     %o0
92 .align  32
93 .Lenter:
94         save    %sp,-$frame,%sp
95         sll     $num,2,$num             ! num*=4
96         or      $mask,%lo(0xffffffff),$mask
97         ld      [$n0],$n0
98         cmp     $ap,$bp
99         and     $num,$mask,$num
100         ld      [$bp],$mul0             ! bp[0]
101         nop
102
103         add     %sp,$bias,%o7           ! real top of stack
104         ld      [$ap],$car0             ! ap[0] ! redundant in squaring context
105         sub     %o7,$num,%o7
106         ld      [$ap+4],$apj            ! ap[1]
107         and     %o7,-1024,%o7
108         ld      [$np],$car1             ! np[0]
109         sub     %o7,$bias,%sp           ! alloca
110         ld      [$np+4],$npj            ! np[1]
111         be,pt   SIZE_T_CC,.Lbn_sqr_mont
112         mov     12,$j
113
114         mulx    $car0,$mul0,$car0       ! ap[0]*bp[0]
115         mulx    $apj,$mul0,$tmp0        !prologue! ap[1]*bp[0]
116         and     $car0,$mask,$acc0
117         add     %sp,$bias+$frame,$tp
118         ld      [$ap+8],$apj            !prologue!
119
120         mulx    $n0,$acc0,$mul1         ! "t[0]"*n0
121         and     $mul1,$mask,$mul1
122
123         mulx    $car1,$mul1,$car1       ! np[0]*"t[0]"*n0
124         mulx    $npj,$mul1,$acc1        !prologue! np[1]*"t[0]"*n0
125         srlx    $car0,32,$car0
126         add     $acc0,$car1,$car1
127         ld      [$np+8],$npj            !prologue!
128         srlx    $car1,32,$car1
129         mov     $tmp0,$acc0             !prologue!
130
131 .L1st:
132         mulx    $apj,$mul0,$tmp0
133         mulx    $npj,$mul1,$tmp1
134         add     $acc0,$car0,$car0
135         ld      [$ap+$j],$apj           ! ap[j]
136         and     $car0,$mask,$acc0
137         add     $acc1,$car1,$car1
138         ld      [$np+$j],$npj           ! np[j]
139         srlx    $car0,32,$car0
140         add     $acc0,$car1,$car1
141         add     $j,4,$j                 ! j++
142         mov     $tmp0,$acc0
143         st      $car1,[$tp]
144         cmp     $j,$num
145         mov     $tmp1,$acc1
146         srlx    $car1,32,$car1
147         bl      %icc,.L1st
148         add     $tp,4,$tp               ! tp++
149 !.L1st
150
151         mulx    $apj,$mul0,$tmp0        !epilogue!
152         mulx    $npj,$mul1,$tmp1
153         add     $acc0,$car0,$car0
154         and     $car0,$mask,$acc0
155         add     $acc1,$car1,$car1
156         srlx    $car0,32,$car0
157         add     $acc0,$car1,$car1
158         st      $car1,[$tp]
159         srlx    $car1,32,$car1
160
161         add     $tmp0,$car0,$car0
162         and     $car0,$mask,$acc0
163         add     $tmp1,$car1,$car1
164         srlx    $car0,32,$car0
165         add     $acc0,$car1,$car1
166         st      $car1,[$tp+4]
167         srlx    $car1,32,$car1
168
169         add     $car0,$car1,$car1
170         st      $car1,[$tp+8]
171         srlx    $car1,32,$car2
172 \f
173         mov     4,$i                    ! i++
174         ld      [$bp+4],$mul0           ! bp[1]
175 .Louter:
176         add     %sp,$bias+$frame,$tp
177         ld      [$ap],$car0             ! ap[0]
178         ld      [$ap+4],$apj            ! ap[1]
179         ld      [$np],$car1             ! np[0]
180         ld      [$np+4],$npj            ! np[1]
181         ld      [$tp],$tmp1             ! tp[0]
182         ld      [$tp+4],$tpj            ! tp[1]
183         mov     12,$j
184
185         mulx    $car0,$mul0,$car0
186         mulx    $apj,$mul0,$tmp0        !prologue!
187         add     $tmp1,$car0,$car0
188         ld      [$ap+8],$apj            !prologue!
189         and     $car0,$mask,$acc0
190
191         mulx    $n0,$acc0,$mul1
192         and     $mul1,$mask,$mul1
193
194         mulx    $car1,$mul1,$car1
195         mulx    $npj,$mul1,$acc1        !prologue!
196         srlx    $car0,32,$car0
197         add     $acc0,$car1,$car1
198         ld      [$np+8],$npj            !prologue!
199         srlx    $car1,32,$car1
200         mov     $tmp0,$acc0             !prologue!
201
202 .Linner:
203         mulx    $apj,$mul0,$tmp0
204         mulx    $npj,$mul1,$tmp1
205         add     $tpj,$car0,$car0
206         ld      [$ap+$j],$apj           ! ap[j]
207         add     $acc0,$car0,$car0
208         add     $acc1,$car1,$car1
209         ld      [$np+$j],$npj           ! np[j]
210         and     $car0,$mask,$acc0
211         ld      [$tp+8],$tpj            ! tp[j]
212         srlx    $car0,32,$car0
213         add     $acc0,$car1,$car1
214         add     $j,4,$j                 ! j++
215         mov     $tmp0,$acc0
216         st      $car1,[$tp]             ! tp[j-1]
217         srlx    $car1,32,$car1
218         mov     $tmp1,$acc1
219         cmp     $j,$num
220         bl      %icc,.Linner
221         add     $tp,4,$tp               ! tp++
222 !.Linner
223
224         mulx    $apj,$mul0,$tmp0        !epilogue!
225         mulx    $npj,$mul1,$tmp1
226         add     $tpj,$car0,$car0
227         add     $acc0,$car0,$car0
228         ld      [$tp+8],$tpj            ! tp[j]
229         and     $car0,$mask,$acc0
230         add     $acc1,$car1,$car1
231         srlx    $car0,32,$car0
232         add     $acc0,$car1,$car1
233         st      $car1,[$tp]             ! tp[j-1]
234         srlx    $car1,32,$car1
235
236         add     $tpj,$car0,$car0
237         add     $tmp0,$car0,$car0
238         and     $car0,$mask,$acc0
239         add     $tmp1,$car1,$car1
240         add     $acc0,$car1,$car1
241         st      $car1,[$tp+4]           ! tp[j-1]
242         srlx    $car0,32,$car0
243         add     $i,4,$i                 ! i++
244         srlx    $car1,32,$car1
245
246         add     $car0,$car1,$car1
247         cmp     $i,$num
248         add     $car2,$car1,$car1
249         st      $car1,[$tp+8]
250
251         srlx    $car1,32,$car2
252         bl,a    %icc,.Louter
253         ld      [$bp+$i],$mul0          ! bp[i]
254 !.Louter
255
256         add     $tp,12,$tp
257 \f
258 .Ltail:
259         add     $np,$num,$np
260         add     $rp,$num,$rp
261         mov     $tp,$ap
262         sub     %g0,$num,%o7            ! k=-num
263         ba      .Lsub
264         subcc   %g0,%g0,%g0             ! clear %icc.c
265 .align  16
266 .Lsub:
267         ld      [$tp+%o7],%o0
268         ld      [$np+%o7],%o1
269         subccc  %o0,%o1,%o1             ! tp[j]-np[j]
270         add     $rp,%o7,$i
271         add     %o7,4,%o7
272         brnz    %o7,.Lsub
273         st      %o1,[$i]
274         subc    $car2,0,$car2           ! handle upmost overflow bit
275         and     $tp,$car2,$ap
276         andn    $rp,$car2,$np
277         or      $ap,$np,$ap
278         sub     %g0,$num,%o7
279
280 .Lcopy:
281         ld      [$ap+%o7],%o0           ! copy or in-place refresh
282         st      %g0,[$tp+%o7]           ! zap tp
283         st      %o0,[$rp+%o7]
284         add     %o7,4,%o7
285         brnz    %o7,.Lcopy
286         nop
287         mov     1,%i0
288         ret
289         restore
290 ___
291 \f
292 ########
293 ######## .Lbn_sqr_mont gives up to 20% *overall* improvement over
294 ######## code without following dedicated squaring procedure.
295 ########
296 $sbit="%i2";            # re-use $bp!
297
298 $code.=<<___;
299 .align  32
300 .Lbn_sqr_mont:
301         mulx    $mul0,$mul0,$car0               ! ap[0]*ap[0]
302         mulx    $apj,$mul0,$tmp0                !prologue!
303         and     $car0,$mask,$acc0
304         add     %sp,$bias+$frame,$tp
305         ld      [$ap+8],$apj                    !prologue!
306
307         mulx    $n0,$acc0,$mul1                 ! "t[0]"*n0
308         srlx    $car0,32,$car0
309         and     $mul1,$mask,$mul1
310
311         mulx    $car1,$mul1,$car1               ! np[0]*"t[0]"*n0
312         mulx    $npj,$mul1,$acc1                !prologue!
313         and     $car0,1,$sbit
314         ld      [$np+8],$npj                    !prologue!
315         srlx    $car0,1,$car0
316         add     $acc0,$car1,$car1
317         srlx    $car1,32,$car1
318         mov     $tmp0,$acc0                     !prologue!
319
320 .Lsqr_1st:
321         mulx    $apj,$mul0,$tmp0
322         mulx    $npj,$mul1,$tmp1
323         add     $acc0,$car0,$car0               ! ap[j]*a0+c0
324         add     $acc1,$car1,$car1
325         ld      [$ap+$j],$apj                   ! ap[j]
326         and     $car0,$mask,$acc0
327         ld      [$np+$j],$npj                   ! np[j]
328         srlx    $car0,32,$car0
329         add     $acc0,$acc0,$acc0
330         or      $sbit,$acc0,$acc0
331         mov     $tmp1,$acc1
332         srlx    $acc0,32,$sbit
333         add     $j,4,$j                         ! j++
334         and     $acc0,$mask,$acc0
335         cmp     $j,$num
336         add     $acc0,$car1,$car1
337         st      $car1,[$tp]
338         mov     $tmp0,$acc0
339         srlx    $car1,32,$car1
340         bl      %icc,.Lsqr_1st
341         add     $tp,4,$tp                       ! tp++
342 !.Lsqr_1st
343
344         mulx    $apj,$mul0,$tmp0                ! epilogue
345         mulx    $npj,$mul1,$tmp1
346         add     $acc0,$car0,$car0               ! ap[j]*a0+c0
347         add     $acc1,$car1,$car1
348         and     $car0,$mask,$acc0
349         srlx    $car0,32,$car0
350         add     $acc0,$acc0,$acc0
351         or      $sbit,$acc0,$acc0
352         srlx    $acc0,32,$sbit
353         and     $acc0,$mask,$acc0
354         add     $acc0,$car1,$car1
355         st      $car1,[$tp]
356         srlx    $car1,32,$car1
357
358         add     $tmp0,$car0,$car0               ! ap[j]*a0+c0
359         add     $tmp1,$car1,$car1
360         and     $car0,$mask,$acc0
361         srlx    $car0,32,$car0
362         add     $acc0,$acc0,$acc0
363         or      $sbit,$acc0,$acc0
364         srlx    $acc0,32,$sbit
365         and     $acc0,$mask,$acc0
366         add     $acc0,$car1,$car1
367         st      $car1,[$tp+4]
368         srlx    $car1,32,$car1
369
370         add     $car0,$car0,$car0
371         or      $sbit,$car0,$car0
372         add     $car0,$car1,$car1
373         st      $car1,[$tp+8]
374         srlx    $car1,32,$car2
375 \f
376         ld      [%sp+$bias+$frame],$tmp0        ! tp[0]
377         ld      [%sp+$bias+$frame+4],$tmp1      ! tp[1]
378         ld      [%sp+$bias+$frame+8],$tpj       ! tp[2]
379         ld      [$ap+4],$mul0                   ! ap[1]
380         ld      [$ap+8],$apj                    ! ap[2]
381         ld      [$np],$car1                     ! np[0]
382         ld      [$np+4],$npj                    ! np[1]
383         mulx    $n0,$tmp0,$mul1
384
385         mulx    $mul0,$mul0,$car0
386         and     $mul1,$mask,$mul1
387
388         mulx    $car1,$mul1,$car1
389         mulx    $npj,$mul1,$acc1
390         add     $tmp0,$car1,$car1
391         and     $car0,$mask,$acc0
392         ld      [$np+8],$npj                    ! np[2]
393         srlx    $car1,32,$car1
394         add     $tmp1,$car1,$car1
395         srlx    $car0,32,$car0
396         add     $acc0,$car1,$car1
397         and     $car0,1,$sbit
398         add     $acc1,$car1,$car1
399         srlx    $car0,1,$car0
400         mov     12,$j
401         st      $car1,[%sp+$bias+$frame]        ! tp[0]=
402         srlx    $car1,32,$car1
403         add     %sp,$bias+$frame+4,$tp
404
405 .Lsqr_2nd:
406         mulx    $apj,$mul0,$acc0
407         mulx    $npj,$mul1,$acc1
408         add     $acc0,$car0,$car0
409         add     $tpj,$car1,$car1
410         ld      [$ap+$j],$apj                   ! ap[j]
411         and     $car0,$mask,$acc0
412         ld      [$np+$j],$npj                   ! np[j]
413         srlx    $car0,32,$car0
414         add     $acc1,$car1,$car1
415         ld      [$tp+8],$tpj                    ! tp[j]
416         add     $acc0,$acc0,$acc0
417         add     $j,4,$j                         ! j++
418         or      $sbit,$acc0,$acc0
419         srlx    $acc0,32,$sbit
420         and     $acc0,$mask,$acc0
421         cmp     $j,$num
422         add     $acc0,$car1,$car1
423         st      $car1,[$tp]                     ! tp[j-1]
424         srlx    $car1,32,$car1
425         bl      %icc,.Lsqr_2nd
426         add     $tp,4,$tp                       ! tp++
427 !.Lsqr_2nd
428
429         mulx    $apj,$mul0,$acc0
430         mulx    $npj,$mul1,$acc1
431         add     $acc0,$car0,$car0
432         add     $tpj,$car1,$car1
433         and     $car0,$mask,$acc0
434         srlx    $car0,32,$car0
435         add     $acc1,$car1,$car1
436         add     $acc0,$acc0,$acc0
437         or      $sbit,$acc0,$acc0
438         srlx    $acc0,32,$sbit
439         and     $acc0,$mask,$acc0
440         add     $acc0,$car1,$car1
441         st      $car1,[$tp]                     ! tp[j-1]
442         srlx    $car1,32,$car1
443
444         add     $car0,$car0,$car0
445         or      $sbit,$car0,$car0
446         add     $car0,$car1,$car1
447         add     $car2,$car1,$car1
448         st      $car1,[$tp+4]
449         srlx    $car1,32,$car2
450 \f
451         ld      [%sp+$bias+$frame],$tmp1        ! tp[0]
452         ld      [%sp+$bias+$frame+4],$tpj       ! tp[1]
453         ld      [$ap+8],$mul0                   ! ap[2]
454         ld      [$np],$car1                     ! np[0]
455         ld      [$np+4],$npj                    ! np[1]
456         mulx    $n0,$tmp1,$mul1
457         and     $mul1,$mask,$mul1
458         mov     8,$i
459
460         mulx    $mul0,$mul0,$car0
461         mulx    $car1,$mul1,$car1
462         and     $car0,$mask,$acc0
463         add     $tmp1,$car1,$car1
464         srlx    $car0,32,$car0
465         add     %sp,$bias+$frame,$tp
466         srlx    $car1,32,$car1
467         and     $car0,1,$sbit
468         srlx    $car0,1,$car0
469         mov     4,$j
470
471 .Lsqr_outer:
472 .Lsqr_inner1:
473         mulx    $npj,$mul1,$acc1
474         add     $tpj,$car1,$car1
475         add     $j,4,$j
476         ld      [$tp+8],$tpj
477         cmp     $j,$i
478         add     $acc1,$car1,$car1
479         ld      [$np+$j],$npj
480         st      $car1,[$tp]
481         srlx    $car1,32,$car1
482         bl      %icc,.Lsqr_inner1
483         add     $tp,4,$tp
484 !.Lsqr_inner1
485
486         add     $j,4,$j
487         ld      [$ap+$j],$apj                   ! ap[j]
488         mulx    $npj,$mul1,$acc1
489         add     $tpj,$car1,$car1
490         ld      [$np+$j],$npj                   ! np[j]
491         add     $acc0,$car1,$car1
492         ld      [$tp+8],$tpj                    ! tp[j]
493         add     $acc1,$car1,$car1
494         st      $car1,[$tp]
495         srlx    $car1,32,$car1
496
497         add     $j,4,$j
498         cmp     $j,$num
499         be,pn   %icc,.Lsqr_no_inner2
500         add     $tp,4,$tp
501
502 .Lsqr_inner2:
503         mulx    $apj,$mul0,$acc0
504         mulx    $npj,$mul1,$acc1
505         add     $tpj,$car1,$car1
506         add     $acc0,$car0,$car0
507         ld      [$ap+$j],$apj                   ! ap[j]
508         and     $car0,$mask,$acc0
509         ld      [$np+$j],$npj                   ! np[j]
510         srlx    $car0,32,$car0
511         add     $acc0,$acc0,$acc0
512         ld      [$tp+8],$tpj                    ! tp[j]
513         or      $sbit,$acc0,$acc0
514         add     $j,4,$j                         ! j++
515         srlx    $acc0,32,$sbit
516         and     $acc0,$mask,$acc0
517         cmp     $j,$num
518         add     $acc0,$car1,$car1
519         add     $acc1,$car1,$car1
520         st      $car1,[$tp]                     ! tp[j-1]
521         srlx    $car1,32,$car1
522         bl      %icc,.Lsqr_inner2
523         add     $tp,4,$tp                       ! tp++
524
525 .Lsqr_no_inner2:
526         mulx    $apj,$mul0,$acc0
527         mulx    $npj,$mul1,$acc1
528         add     $tpj,$car1,$car1
529         add     $acc0,$car0,$car0
530         and     $car0,$mask,$acc0
531         srlx    $car0,32,$car0
532         add     $acc0,$acc0,$acc0
533         or      $sbit,$acc0,$acc0
534         srlx    $acc0,32,$sbit
535         and     $acc0,$mask,$acc0
536         add     $acc0,$car1,$car1
537         add     $acc1,$car1,$car1
538         st      $car1,[$tp]                     ! tp[j-1]
539         srlx    $car1,32,$car1
540
541         add     $car0,$car0,$car0
542         or      $sbit,$car0,$car0
543         add     $car0,$car1,$car1
544         add     $car2,$car1,$car1
545         st      $car1,[$tp+4]
546         srlx    $car1,32,$car2
547 \f
548         add     $i,4,$i                         ! i++
549         ld      [%sp+$bias+$frame],$tmp1        ! tp[0]
550         ld      [%sp+$bias+$frame+4],$tpj       ! tp[1]
551         ld      [$ap+$i],$mul0                  ! ap[j]
552         ld      [$np],$car1                     ! np[0]
553         ld      [$np+4],$npj                    ! np[1]
554         mulx    $n0,$tmp1,$mul1
555         and     $mul1,$mask,$mul1
556         add     $i,4,$tmp0
557
558         mulx    $mul0,$mul0,$car0
559         mulx    $car1,$mul1,$car1
560         and     $car0,$mask,$acc0
561         add     $tmp1,$car1,$car1
562         srlx    $car0,32,$car0
563         add     %sp,$bias+$frame,$tp
564         srlx    $car1,32,$car1
565         and     $car0,1,$sbit
566         srlx    $car0,1,$car0
567
568         cmp     $tmp0,$num                      ! i<num-1
569         bl      %icc,.Lsqr_outer
570         mov     4,$j
571 \f
572 .Lsqr_last:
573         mulx    $npj,$mul1,$acc1
574         add     $tpj,$car1,$car1
575         add     $j,4,$j
576         ld      [$tp+8],$tpj
577         cmp     $j,$i
578         add     $acc1,$car1,$car1
579         ld      [$np+$j],$npj
580         st      $car1,[$tp]
581         srlx    $car1,32,$car1
582         bl      %icc,.Lsqr_last
583         add     $tp,4,$tp
584 !.Lsqr_last
585
586         mulx    $npj,$mul1,$acc1
587         add     $tpj,$car1,$car1
588         add     $acc0,$car1,$car1
589         add     $acc1,$car1,$car1
590         st      $car1,[$tp]
591         srlx    $car1,32,$car1
592
593         add     $car0,$car0,$car0               ! recover $car0
594         or      $sbit,$car0,$car0
595         add     $car0,$car1,$car1
596         add     $car2,$car1,$car1
597         st      $car1,[$tp+4]
598         srlx    $car1,32,$car2
599
600         ba      .Ltail
601         add     $tp,8,$tp
602 .type   $fname,#function
603 .size   $fname,(.-$fname)
604 .asciz  "Montgomery Multipltication for SPARCv9, CRYPTOGAMS by <appro\@openssl.org>"
605 .align  32
606 ___
607 $code =~ s/\`([^\`]*)\`/eval($1)/gem;
608 print $code;
609 close STDOUT;