985a2b27447edd89a815efce5e722753a65e8e1b
[openssl.git] / crypto / bn / asm / ppc64-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 2007
11
12 # The reason for undertaken effort is basically following. Even though
13 # Power 6 CPU operates at incredible 4.7GHz clock frequency, its PKI
14 # performance was observed to be less than impressive, essentially as
15 # fast as 1.8GHz PPC970, or 2.6 times(!) slower than one would hope.
16 # Well, it's not surprising that IBM had to make some sacrifices to
17 # boost the clock frequency that much, but no overall improvement?
18 # Having observed how much difference did switching to FPU make on
19 # UltraSPARC, playing same stunt on Power 6 appeared appropriate...
20 # Unfortunately the resulting performance improvement is not as
21 # impressive, ~30%, and in absolute terms is still very far from what
22 # one would expect from 4.7GHz CPU. There is a chance that I'm doing
23 # something wrong, but in the lack of assembler level micro-profiling
24 # data or at least decent platform guide I can't tell... Or better
25 # results might be achieved with VMX... Anyway, this module provides
26 # *worse* performance on other PowerPC implementations, ~40-15% slower
27 # on PPC970 depending on key length and ~40% slower on Power 5 for all
28 # key lengths. As it's obviously inappropriate as "best all-round"
29 # alternative, it has to be complemented with run-time CPU family
30 # detection. Oh! It should also be noted that unlike other PowerPC
31 # implementation IALU ppc-mont.pl module performs *suboptimaly* on
32 # >=1024-bit key lengths on Power 6. It should also be noted that
33 # *everything* said so far applies to 64-bit builds! As far as 32-bit
34 # application executed on 64-bit CPU goes, this module is likely to
35 # become preferred choice, because it's easy to adapt it for such
36 # case and *is* faster than 32-bit ppc-mont.pl on *all* processors.
37
38 # February 2008
39
40 # Micro-profiling assisted optimization results in ~15% improvement
41 # over original ppc64-mont.pl version, or overall ~50% improvement
42 # over ppc.pl module on Power 6. If compared to ppc-mont.pl on same
43 # Power 6 CPU, this module is 5-150% faster depending on key length,
44 # [hereafter] more for longer keys. But if compared to ppc-mont.pl
45 # on 1.8GHz PPC970, it's only 5-55% faster. Still far from impressive
46 # in absolute terms, but it's apparently the way Power 6 is...
47
48 # December 2009
49
50 # Adapted for 32-bit build this module delivers 25-120%, more for
51 # longer keys, performance improvement on 1.8GHz PPC970. However!
52 # This implementation utilizes even 64-bit integer operations and
53 # trouble is that most PPC operating systems don't preserve upper
54 # halves of general purpose registers upong signal delivery. They do
55 # preserve them upon context switch, but not signalling:-( This means
56 # that asynchronous signals have to be blocked upon entry to this
57 # subroutine. Signal masking (and complementary unmasking) has quite
58 # an impact on performance, naturally larger for shorter keys. It's
59 # so severe that shorter key performance can be as low as 1/3 of
60 # expected one. This is why this routine can be engaged for longer
61 # key operations only, see crypto/ppccap.c for further details.
62 # Alternative is to break dependance on upper halves on GPRs...
63 # MacOS X is an exception from this and doesn't require signal
64 # masking, and that's where above improvement coefficients were
65 # collected.
66
67 $flavour = shift;
68
69 if ($flavour =~ /32/) {
70         $SIZE_T=4;
71         $RZONE= 224;
72         $FRAME= $SIZE_T*12+8*12;
73         $fname= "bn_mul_mont_fpu64";
74
75         $STUX=  "stwux";        # store indexed and update
76         $PUSH=  "stw";
77         $POP=   "lwz";
78 } elsif ($flavour =~ /64/) {
79         $SIZE_T=8;
80         $RZONE= 288;
81         $FRAME= $SIZE_T*12+8*12;
82         $fname= "bn_mul_mont_fpu64";
83
84         # same as above, but 64-bit mnemonics...
85         $STUX=  "stdux";        # store indexed and update
86         $PUSH=  "std";
87         $POP=   "ld";
88 } else { die "nonsense $flavour"; }
89
90 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
91 ( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
92 ( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
93 die "can't locate ppc-xlate.pl";
94
95 open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
96
97 $FRAME=($FRAME+63)&~63;
98 $TRANSFER=16*8;
99
100 $carry="r0";
101 $sp="r1";
102 $toc="r2";
103 $rp="r3";       $ovf="r3";
104 $ap="r4";
105 $bp="r5";
106 $np="r6";
107 $n0="r7";
108 $num="r8";
109 $rp="r9";       # $rp is reassigned
110 $tp="r10";
111 $j="r11";
112 $i="r12";
113 # non-volatile registers
114 $nap_d="r14";   # interleaved ap and np in double format
115 $a0="r15";      # ap[0]
116 $t0="r16";      # temporary registers
117 $t1="r17";
118 $t2="r18";
119 $t3="r19";
120 $t4="r20";
121 $t5="r21";
122 $t6="r22";
123 $t7="r23";
124
125 # PPC offers enough register bank capacity to unroll inner loops twice
126 #
127 #     ..A3A2A1A0
128 #           dcba
129 #    -----------
130 #            A0a
131 #           A0b
132 #          A0c
133 #         A0d
134 #          A1a
135 #         A1b
136 #        A1c
137 #       A1d
138 #        A2a
139 #       A2b
140 #      A2c
141 #     A2d
142 #      A3a
143 #     A3b
144 #    A3c
145 #   A3d
146 #    ..a
147 #   ..b
148 #
149 $ba="f0";       $bb="f1";       $bc="f2";       $bd="f3";
150 $na="f4";       $nb="f5";       $nc="f6";       $nd="f7";
151 $dota="f8";     $dotb="f9";
152 $A0="f10";      $A1="f11";      $A2="f12";      $A3="f13";
153 $N0="f14";      $N1="f15";      $N2="f16";      $N3="f17";
154 $T0a="f18";     $T0b="f19";
155 $T1a="f20";     $T1b="f21";
156 $T2a="f22";     $T2b="f23";
157 $T3a="f24";     $T3b="f25";
158 \f
159 # sp----------->+-------------------------------+
160 #               | saved sp                      |
161 #               +-------------------------------+
162 #               |                               |
163 #               +-------------------------------+
164 #               | 10 saved gpr, r14-r23         |
165 #               .                               .
166 #               .                               .
167 #   +12*size_t  +-------------------------------+
168 #               | 12 saved fpr, f14-f25         |
169 #               .                               .
170 #               .                               .
171 #   +12*8       +-------------------------------+
172 #               | padding to 64 byte boundary   |
173 #               .                               .
174 #   +X          +-------------------------------+
175 #               | 16 gpr<->fpr transfer zone    |
176 #               .                               .
177 #               .                               .
178 #   +16*8       +-------------------------------+
179 #               | __int64 tmp[-1]               |
180 #               +-------------------------------+
181 #               | __int64 tmp[num]              |
182 #               .                               .
183 #               .                               .
184 #               .                               .
185 #   +(num+1)*8  +-------------------------------+
186 #               | padding to 64 byte boundary   |
187 #               .                               .
188 #   +X          +-------------------------------+
189 #               | double nap_d[4*num]           |
190 #               .                               .
191 #               .                               .
192 #               .                               .
193 #               +-------------------------------+
194 \f
195 $code=<<___;
196 .machine "any"
197 .text
198
199 .globl  .$fname
200 .align  5
201 .$fname:
202         cmpwi   $num,`3*8/$SIZE_T`
203         mr      $rp,r3          ; $rp is reassigned
204         li      r3,0            ; possible "not handled" return code
205         bltlr-
206         andi.   r0,$num,`16/$SIZE_T-1`          ; $num has to be "even"
207         bnelr-
208
209         slwi    $num,$num,`log($SIZE_T)/log(2)` ; num*=sizeof(BN_LONG)
210         li      $i,-4096
211         slwi    $tp,$num,2      ; place for {an}p_{lh}[num], i.e. 4*num
212         add     $tp,$tp,$num    ; place for tp[num+1]
213         addi    $tp,$tp,`$FRAME+$TRANSFER+8+64+$RZONE`
214         subf    $tp,$tp,$sp     ; $sp-$tp
215         and     $tp,$tp,$i      ; minimize TLB usage
216         subf    $tp,$sp,$tp     ; $tp-$sp
217         $STUX   $sp,$sp,$tp     ; alloca
218
219         $PUSH   r14,`2*$SIZE_T`($sp)
220         $PUSH   r15,`3*$SIZE_T`($sp)
221         $PUSH   r16,`4*$SIZE_T`($sp)
222         $PUSH   r17,`5*$SIZE_T`($sp)
223         $PUSH   r18,`6*$SIZE_T`($sp)
224         $PUSH   r19,`7*$SIZE_T`($sp)
225         $PUSH   r20,`8*$SIZE_T`($sp)
226         $PUSH   r21,`9*$SIZE_T`($sp)
227         $PUSH   r22,`10*$SIZE_T`($sp)
228         $PUSH   r23,`11*$SIZE_T`($sp)
229         stfd    f14,`12*$SIZE_T+0`($sp)
230         stfd    f15,`12*$SIZE_T+8`($sp)
231         stfd    f16,`12*$SIZE_T+16`($sp)
232         stfd    f17,`12*$SIZE_T+24`($sp)
233         stfd    f18,`12*$SIZE_T+32`($sp)
234         stfd    f19,`12*$SIZE_T+40`($sp)
235         stfd    f20,`12*$SIZE_T+48`($sp)
236         stfd    f21,`12*$SIZE_T+56`($sp)
237         stfd    f22,`12*$SIZE_T+64`($sp)
238         stfd    f23,`12*$SIZE_T+72`($sp)
239         stfd    f24,`12*$SIZE_T+80`($sp)
240         stfd    f25,`12*$SIZE_T+88`($sp)
241 ___
242 $code.=<<___ if ($SIZE_T==8);
243         ld      $a0,0($ap)      ; pull ap[0] value
244         ld      $n0,0($n0)      ; pull n0[0] value
245         ld      $t3,0($bp)      ; bp[0]
246 ___
247 $code.=<<___ if ($SIZE_T==4);
248         mr      $t1,$n0
249         lwz     $a0,0($ap)      ; pull ap[0,1] value
250         lwz     $t0,4($ap)
251         lwz     $n0,0($t1)      ; pull n0[0,1] value
252         lwz     $t1,4($t1)
253         lwz     $t3,0($bp)      ; bp[0,1]
254         lwz     $t2,4($bp)
255         insrdi  $a0,$t0,32,0
256         insrdi  $n0,$t1,32,0
257         insrdi  $t3,$t2,32,0
258 ___
259 $code.=<<___;
260         addi    $tp,$sp,`$FRAME+$TRANSFER+8+64`
261         li      $i,-64
262         add     $nap_d,$tp,$num
263         and     $nap_d,$nap_d,$i        ; align to 64 bytes
264 \f
265         mulld   $t7,$a0,$t3     ; ap[0]*bp[0]
266         ; nap_d is off by 1, because it's used with stfdu/lfdu
267         addi    $nap_d,$nap_d,-8
268         srwi    $j,$num,`3+1`   ; counter register, num/2
269         mulld   $t7,$t7,$n0     ; tp[0]*n0
270         addi    $j,$j,-1
271         addi    $tp,$sp,`$FRAME+$TRANSFER-8`
272         li      $carry,0
273         mtctr   $j
274
275         ; transfer bp[0] to FPU as 4x16-bit values
276         extrdi  $t0,$t3,16,48
277         extrdi  $t1,$t3,16,32
278         extrdi  $t2,$t3,16,16
279         extrdi  $t3,$t3,16,0
280         std     $t0,`$FRAME+0`($sp)
281         std     $t1,`$FRAME+8`($sp)
282         std     $t2,`$FRAME+16`($sp)
283         std     $t3,`$FRAME+24`($sp)
284         ; transfer (ap[0]*bp[0])*n0 to FPU as 4x16-bit values
285         extrdi  $t4,$t7,16,48
286         extrdi  $t5,$t7,16,32
287         extrdi  $t6,$t7,16,16
288         extrdi  $t7,$t7,16,0
289         std     $t4,`$FRAME+32`($sp)
290         std     $t5,`$FRAME+40`($sp)
291         std     $t6,`$FRAME+48`($sp)
292         std     $t7,`$FRAME+56`($sp)
293 ___
294 $code.=<<___ if ($SIZE_T==8);
295         lwz     $t0,4($ap)              ; load a[j] as 32-bit word pair
296         lwz     $t1,0($ap)
297         lwz     $t2,12($ap)             ; load a[j+1] as 32-bit word pair
298         lwz     $t3,8($ap)
299         lwz     $t4,4($np)              ; load n[j] as 32-bit word pair
300         lwz     $t5,0($np)
301         lwz     $t6,12($np)             ; load n[j+1] as 32-bit word pair
302         lwz     $t7,8($np)
303 ___
304 $code.=<<___ if ($SIZE_T==4);
305         lwz     $t0,0($ap)              ; load a[j..j+3] as 32-bit word pairs
306         lwz     $t1,4($ap)
307         lwz     $t2,8($ap)
308         lwz     $t3,12($ap)
309         lwz     $t4,0($np)              ; load n[j..j+3] as 32-bit word pairs
310         lwz     $t5,4($np)
311         lwz     $t6,8($np)
312         lwz     $t7,12($np)
313 ___
314 $code.=<<___;
315         lfd     $ba,`$FRAME+0`($sp)
316         lfd     $bb,`$FRAME+8`($sp)
317         lfd     $bc,`$FRAME+16`($sp)
318         lfd     $bd,`$FRAME+24`($sp)
319         lfd     $na,`$FRAME+32`($sp)
320         lfd     $nb,`$FRAME+40`($sp)
321         lfd     $nc,`$FRAME+48`($sp)
322         lfd     $nd,`$FRAME+56`($sp)
323         std     $t0,`$FRAME+64`($sp)
324         std     $t1,`$FRAME+72`($sp)
325         std     $t2,`$FRAME+80`($sp)
326         std     $t3,`$FRAME+88`($sp)
327         std     $t4,`$FRAME+96`($sp)
328         std     $t5,`$FRAME+104`($sp)
329         std     $t6,`$FRAME+112`($sp)
330         std     $t7,`$FRAME+120`($sp)
331         fcfid   $ba,$ba
332         fcfid   $bb,$bb
333         fcfid   $bc,$bc
334         fcfid   $bd,$bd
335         fcfid   $na,$na
336         fcfid   $nb,$nb
337         fcfid   $nc,$nc
338         fcfid   $nd,$nd
339
340         lfd     $A0,`$FRAME+64`($sp)
341         lfd     $A1,`$FRAME+72`($sp)
342         lfd     $A2,`$FRAME+80`($sp)
343         lfd     $A3,`$FRAME+88`($sp)
344         lfd     $N0,`$FRAME+96`($sp)
345         lfd     $N1,`$FRAME+104`($sp)
346         lfd     $N2,`$FRAME+112`($sp)
347         lfd     $N3,`$FRAME+120`($sp)
348         fcfid   $A0,$A0
349         fcfid   $A1,$A1
350         fcfid   $A2,$A2
351         fcfid   $A3,$A3
352         fcfid   $N0,$N0
353         fcfid   $N1,$N1
354         fcfid   $N2,$N2
355         fcfid   $N3,$N3
356         addi    $ap,$ap,16
357         addi    $np,$np,16
358
359         fmul    $T1a,$A1,$ba
360         fmul    $T1b,$A1,$bb
361         stfd    $A0,8($nap_d)           ; save a[j] in double format
362         stfd    $A1,16($nap_d)
363         fmul    $T2a,$A2,$ba
364         fmul    $T2b,$A2,$bb
365         stfd    $A2,24($nap_d)          ; save a[j+1] in double format
366         stfd    $A3,32($nap_d)
367         fmul    $T3a,$A3,$ba
368         fmul    $T3b,$A3,$bb
369         stfd    $N0,40($nap_d)          ; save n[j] in double format
370         stfd    $N1,48($nap_d)
371         fmul    $T0a,$A0,$ba
372         fmul    $T0b,$A0,$bb
373         stfd    $N2,56($nap_d)          ; save n[j+1] in double format
374         stfdu   $N3,64($nap_d)
375
376         fmadd   $T1a,$A0,$bc,$T1a
377         fmadd   $T1b,$A0,$bd,$T1b
378         fmadd   $T2a,$A1,$bc,$T2a
379         fmadd   $T2b,$A1,$bd,$T2b
380         fmadd   $T3a,$A2,$bc,$T3a
381         fmadd   $T3b,$A2,$bd,$T3b
382         fmul    $dota,$A3,$bc
383         fmul    $dotb,$A3,$bd
384
385         fmadd   $T1a,$N1,$na,$T1a
386         fmadd   $T1b,$N1,$nb,$T1b
387         fmadd   $T2a,$N2,$na,$T2a
388         fmadd   $T2b,$N2,$nb,$T2b
389         fmadd   $T3a,$N3,$na,$T3a
390         fmadd   $T3b,$N3,$nb,$T3b
391         fmadd   $T0a,$N0,$na,$T0a
392         fmadd   $T0b,$N0,$nb,$T0b
393
394         fmadd   $T1a,$N0,$nc,$T1a
395         fmadd   $T1b,$N0,$nd,$T1b
396         fmadd   $T2a,$N1,$nc,$T2a
397         fmadd   $T2b,$N1,$nd,$T2b
398         fmadd   $T3a,$N2,$nc,$T3a
399         fmadd   $T3b,$N2,$nd,$T3b
400         fmadd   $dota,$N3,$nc,$dota
401         fmadd   $dotb,$N3,$nd,$dotb
402
403         fctid   $T0a,$T0a
404         fctid   $T0b,$T0b
405         fctid   $T1a,$T1a
406         fctid   $T1b,$T1b
407         fctid   $T2a,$T2a
408         fctid   $T2b,$T2b
409         fctid   $T3a,$T3a
410         fctid   $T3b,$T3b
411
412         stfd    $T0a,`$FRAME+0`($sp)
413         stfd    $T0b,`$FRAME+8`($sp)
414         stfd    $T1a,`$FRAME+16`($sp)
415         stfd    $T1b,`$FRAME+24`($sp)
416         stfd    $T2a,`$FRAME+32`($sp)
417         stfd    $T2b,`$FRAME+40`($sp)
418         stfd    $T3a,`$FRAME+48`($sp)
419         stfd    $T3b,`$FRAME+56`($sp)
420 \f
421 .align  5
422 L1st:
423 ___
424 $code.=<<___ if ($SIZE_T==8);
425         lwz     $t0,4($ap)              ; load a[j] as 32-bit word pair
426         lwz     $t1,0($ap)
427         lwz     $t2,12($ap)             ; load a[j+1] as 32-bit word pair
428         lwz     $t3,8($ap)
429         lwz     $t4,4($np)              ; load n[j] as 32-bit word pair
430         lwz     $t5,0($np)
431         lwz     $t6,12($np)             ; load n[j+1] as 32-bit word pair
432         lwz     $t7,8($np)
433 ___
434 $code.=<<___ if ($SIZE_T==4);
435         lwz     $t0,0($ap)              ; load a[j..j+3] as 32-bit word pairs
436         lwz     $t1,4($ap)
437         lwz     $t2,8($ap)
438         lwz     $t3,12($ap)
439         lwz     $t4,0($np)              ; load n[j..j+3] as 32-bit word pairs
440         lwz     $t5,4($np)
441         lwz     $t6,8($np)
442         lwz     $t7,12($np)
443 ___
444 $code.=<<___;
445         std     $t0,`$FRAME+64`($sp)
446         std     $t1,`$FRAME+72`($sp)
447         std     $t2,`$FRAME+80`($sp)
448         std     $t3,`$FRAME+88`($sp)
449         std     $t4,`$FRAME+96`($sp)
450         std     $t5,`$FRAME+104`($sp)
451         std     $t6,`$FRAME+112`($sp)
452         std     $t7,`$FRAME+120`($sp)
453         ld      $t0,`$FRAME+0`($sp)
454         ld      $t1,`$FRAME+8`($sp)
455         ld      $t2,`$FRAME+16`($sp)
456         ld      $t3,`$FRAME+24`($sp)
457         ld      $t4,`$FRAME+32`($sp)
458         ld      $t5,`$FRAME+40`($sp)
459         ld      $t6,`$FRAME+48`($sp)
460         ld      $t7,`$FRAME+56`($sp)
461         lfd     $A0,`$FRAME+64`($sp)
462         lfd     $A1,`$FRAME+72`($sp)
463         lfd     $A2,`$FRAME+80`($sp)
464         lfd     $A3,`$FRAME+88`($sp)
465         lfd     $N0,`$FRAME+96`($sp)
466         lfd     $N1,`$FRAME+104`($sp)
467         lfd     $N2,`$FRAME+112`($sp)
468         lfd     $N3,`$FRAME+120`($sp)
469         fcfid   $A0,$A0
470         fcfid   $A1,$A1
471         fcfid   $A2,$A2
472         fcfid   $A3,$A3
473         fcfid   $N0,$N0
474         fcfid   $N1,$N1
475         fcfid   $N2,$N2
476         fcfid   $N3,$N3
477         addi    $ap,$ap,16
478         addi    $np,$np,16
479
480         fmul    $T1a,$A1,$ba
481         fmul    $T1b,$A1,$bb
482         fmul    $T2a,$A2,$ba
483         fmul    $T2b,$A2,$bb
484         stfd    $A0,8($nap_d)           ; save a[j] in double format
485         stfd    $A1,16($nap_d)
486         fmul    $T3a,$A3,$ba
487         fmul    $T3b,$A3,$bb
488         fmadd   $T0a,$A0,$ba,$dota
489         fmadd   $T0b,$A0,$bb,$dotb
490         stfd    $A2,24($nap_d)          ; save a[j+1] in double format
491         stfd    $A3,32($nap_d)
492
493         fmadd   $T1a,$A0,$bc,$T1a
494         fmadd   $T1b,$A0,$bd,$T1b
495         fmadd   $T2a,$A1,$bc,$T2a
496         fmadd   $T2b,$A1,$bd,$T2b
497         stfd    $N0,40($nap_d)          ; save n[j] in double format
498         stfd    $N1,48($nap_d)
499         fmadd   $T3a,$A2,$bc,$T3a
500         fmadd   $T3b,$A2,$bd,$T3b
501          add    $t0,$t0,$carry          ; can not overflow
502         fmul    $dota,$A3,$bc
503         fmul    $dotb,$A3,$bd
504         stfd    $N2,56($nap_d)          ; save n[j+1] in double format
505         stfdu   $N3,64($nap_d)
506          srdi   $carry,$t0,16
507          add    $t1,$t1,$carry
508          srdi   $carry,$t1,16
509
510         fmadd   $T1a,$N1,$na,$T1a
511         fmadd   $T1b,$N1,$nb,$T1b
512          insrdi $t0,$t1,16,32
513         fmadd   $T2a,$N2,$na,$T2a
514         fmadd   $T2b,$N2,$nb,$T2b
515          add    $t2,$t2,$carry
516         fmadd   $T3a,$N3,$na,$T3a
517         fmadd   $T3b,$N3,$nb,$T3b
518          srdi   $carry,$t2,16
519         fmadd   $T0a,$N0,$na,$T0a
520         fmadd   $T0b,$N0,$nb,$T0b
521          insrdi $t0,$t2,16,16
522          add    $t3,$t3,$carry
523          srdi   $carry,$t3,16
524
525         fmadd   $T1a,$N0,$nc,$T1a
526         fmadd   $T1b,$N0,$nd,$T1b
527          insrdi $t0,$t3,16,0            ; 0..63 bits
528         fmadd   $T2a,$N1,$nc,$T2a
529         fmadd   $T2b,$N1,$nd,$T2b
530          add    $t4,$t4,$carry
531         fmadd   $T3a,$N2,$nc,$T3a
532         fmadd   $T3b,$N2,$nd,$T3b
533          srdi   $carry,$t4,16
534         fmadd   $dota,$N3,$nc,$dota
535         fmadd   $dotb,$N3,$nd,$dotb
536          add    $t5,$t5,$carry
537          srdi   $carry,$t5,16
538          insrdi $t4,$t5,16,32
539
540         fctid   $T0a,$T0a
541         fctid   $T0b,$T0b
542          add    $t6,$t6,$carry
543         fctid   $T1a,$T1a
544         fctid   $T1b,$T1b
545          srdi   $carry,$t6,16
546         fctid   $T2a,$T2a
547         fctid   $T2b,$T2b
548          insrdi $t4,$t6,16,16
549         fctid   $T3a,$T3a
550         fctid   $T3b,$T3b
551          add    $t7,$t7,$carry
552          insrdi $t4,$t7,16,0            ; 64..127 bits
553          srdi   $carry,$t7,16           ; upper 33 bits
554
555         stfd    $T0a,`$FRAME+0`($sp)
556         stfd    $T0b,`$FRAME+8`($sp)
557         stfd    $T1a,`$FRAME+16`($sp)
558         stfd    $T1b,`$FRAME+24`($sp)
559         stfd    $T2a,`$FRAME+32`($sp)
560         stfd    $T2b,`$FRAME+40`($sp)
561         stfd    $T3a,`$FRAME+48`($sp)
562         stfd    $T3b,`$FRAME+56`($sp)
563          std    $t0,8($tp)              ; tp[j-1]
564          stdu   $t4,16($tp)             ; tp[j]
565         bdnz-   L1st
566 \f
567         fctid   $dota,$dota
568         fctid   $dotb,$dotb
569
570         ld      $t0,`$FRAME+0`($sp)
571         ld      $t1,`$FRAME+8`($sp)
572         ld      $t2,`$FRAME+16`($sp)
573         ld      $t3,`$FRAME+24`($sp)
574         ld      $t4,`$FRAME+32`($sp)
575         ld      $t5,`$FRAME+40`($sp)
576         ld      $t6,`$FRAME+48`($sp)
577         ld      $t7,`$FRAME+56`($sp)
578         stfd    $dota,`$FRAME+64`($sp)
579         stfd    $dotb,`$FRAME+72`($sp)
580
581         add     $t0,$t0,$carry          ; can not overflow
582         srdi    $carry,$t0,16
583         add     $t1,$t1,$carry
584         srdi    $carry,$t1,16
585         insrdi  $t0,$t1,16,32
586         add     $t2,$t2,$carry
587         srdi    $carry,$t2,16
588         insrdi  $t0,$t2,16,16
589         add     $t3,$t3,$carry
590         srdi    $carry,$t3,16
591         insrdi  $t0,$t3,16,0            ; 0..63 bits
592         add     $t4,$t4,$carry
593         srdi    $carry,$t4,16
594         add     $t5,$t5,$carry
595         srdi    $carry,$t5,16
596         insrdi  $t4,$t5,16,32
597         add     $t6,$t6,$carry
598         srdi    $carry,$t6,16
599         insrdi  $t4,$t6,16,16
600         add     $t7,$t7,$carry
601         insrdi  $t4,$t7,16,0            ; 64..127 bits
602         srdi    $carry,$t7,16           ; upper 33 bits
603         ld      $t6,`$FRAME+64`($sp)
604         ld      $t7,`$FRAME+72`($sp)
605
606         std     $t0,8($tp)              ; tp[j-1]
607         stdu    $t4,16($tp)             ; tp[j]
608
609         add     $t6,$t6,$carry          ; can not overflow
610         srdi    $carry,$t6,16
611         add     $t7,$t7,$carry
612         insrdi  $t6,$t7,48,0
613         srdi    $ovf,$t7,48
614         std     $t6,8($tp)              ; tp[num-1]
615
616         slwi    $t7,$num,2
617         subf    $nap_d,$t7,$nap_d       ; rewind pointer
618 \f
619         li      $i,8                    ; i=1
620 .align  5
621 Louter:
622 ___
623 $code.=<<___ if ($SIZE_T==8);
624         ldx     $t3,$bp,$i      ; bp[i]
625 ___
626 $code.=<<___ if ($SIZE_T==4);
627         add     $t0,$bp,$i
628         lwz     $t3,0($t0)              ; bp[i,i+1]
629         lwz     $t0,4($t0)
630         insrdi  $t3,$t0,32,0
631 ___
632 $code.=<<___;
633         ld      $t6,`$FRAME+$TRANSFER+8`($sp)   ; tp[0]
634         mulld   $t7,$a0,$t3     ; ap[0]*bp[i]
635
636         addi    $tp,$sp,`$FRAME+$TRANSFER`
637         add     $t7,$t7,$t6     ; ap[0]*bp[i]+tp[0]
638         li      $carry,0
639         mulld   $t7,$t7,$n0     ; tp[0]*n0
640         mtctr   $j
641
642         ; transfer bp[i] to FPU as 4x16-bit values
643         extrdi  $t0,$t3,16,48
644         extrdi  $t1,$t3,16,32
645         extrdi  $t2,$t3,16,16
646         extrdi  $t3,$t3,16,0
647         std     $t0,`$FRAME+0`($sp)
648         std     $t1,`$FRAME+8`($sp)
649         std     $t2,`$FRAME+16`($sp)
650         std     $t3,`$FRAME+24`($sp)
651         ; transfer (ap[0]*bp[i]+tp[0])*n0 to FPU as 4x16-bit values
652         extrdi  $t4,$t7,16,48
653         extrdi  $t5,$t7,16,32
654         extrdi  $t6,$t7,16,16
655         extrdi  $t7,$t7,16,0
656         std     $t4,`$FRAME+32`($sp)
657         std     $t5,`$FRAME+40`($sp)
658         std     $t6,`$FRAME+48`($sp)
659         std     $t7,`$FRAME+56`($sp)
660
661         lfd     $A0,8($nap_d)           ; load a[j] in double format
662         lfd     $A1,16($nap_d)
663         lfd     $A2,24($nap_d)          ; load a[j+1] in double format
664         lfd     $A3,32($nap_d)
665         lfd     $N0,40($nap_d)          ; load n[j] in double format
666         lfd     $N1,48($nap_d)
667         lfd     $N2,56($nap_d)          ; load n[j+1] in double format
668         lfdu    $N3,64($nap_d)
669
670         lfd     $ba,`$FRAME+0`($sp)
671         lfd     $bb,`$FRAME+8`($sp)
672         lfd     $bc,`$FRAME+16`($sp)
673         lfd     $bd,`$FRAME+24`($sp)
674         lfd     $na,`$FRAME+32`($sp)
675         lfd     $nb,`$FRAME+40`($sp)
676         lfd     $nc,`$FRAME+48`($sp)
677         lfd     $nd,`$FRAME+56`($sp)
678
679         fcfid   $ba,$ba
680         fcfid   $bb,$bb
681         fcfid   $bc,$bc
682         fcfid   $bd,$bd
683         fcfid   $na,$na
684         fcfid   $nb,$nb
685         fcfid   $nc,$nc
686         fcfid   $nd,$nd
687
688         fmul    $T1a,$A1,$ba
689         fmul    $T1b,$A1,$bb
690         fmul    $T2a,$A2,$ba
691         fmul    $T2b,$A2,$bb
692         fmul    $T3a,$A3,$ba
693         fmul    $T3b,$A3,$bb
694         fmul    $T0a,$A0,$ba
695         fmul    $T0b,$A0,$bb
696
697         fmadd   $T1a,$A0,$bc,$T1a
698         fmadd   $T1b,$A0,$bd,$T1b
699         fmadd   $T2a,$A1,$bc,$T2a
700         fmadd   $T2b,$A1,$bd,$T2b
701         fmadd   $T3a,$A2,$bc,$T3a
702         fmadd   $T3b,$A2,$bd,$T3b
703         fmul    $dota,$A3,$bc
704         fmul    $dotb,$A3,$bd
705
706         fmadd   $T1a,$N1,$na,$T1a
707         fmadd   $T1b,$N1,$nb,$T1b
708          lfd    $A0,8($nap_d)           ; load a[j] in double format
709          lfd    $A1,16($nap_d)
710         fmadd   $T2a,$N2,$na,$T2a
711         fmadd   $T2b,$N2,$nb,$T2b
712          lfd    $A2,24($nap_d)          ; load a[j+1] in double format
713          lfd    $A3,32($nap_d)
714         fmadd   $T3a,$N3,$na,$T3a
715         fmadd   $T3b,$N3,$nb,$T3b
716         fmadd   $T0a,$N0,$na,$T0a
717         fmadd   $T0b,$N0,$nb,$T0b
718
719         fmadd   $T1a,$N0,$nc,$T1a
720         fmadd   $T1b,$N0,$nd,$T1b
721         fmadd   $T2a,$N1,$nc,$T2a
722         fmadd   $T2b,$N1,$nd,$T2b
723         fmadd   $T3a,$N2,$nc,$T3a
724         fmadd   $T3b,$N2,$nd,$T3b
725         fmadd   $dota,$N3,$nc,$dota
726         fmadd   $dotb,$N3,$nd,$dotb
727
728         fctid   $T0a,$T0a
729         fctid   $T0b,$T0b
730         fctid   $T1a,$T1a
731         fctid   $T1b,$T1b
732         fctid   $T2a,$T2a
733         fctid   $T2b,$T2b
734         fctid   $T3a,$T3a
735         fctid   $T3b,$T3b
736
737         stfd    $T0a,`$FRAME+0`($sp)
738         stfd    $T0b,`$FRAME+8`($sp)
739         stfd    $T1a,`$FRAME+16`($sp)
740         stfd    $T1b,`$FRAME+24`($sp)
741         stfd    $T2a,`$FRAME+32`($sp)
742         stfd    $T2b,`$FRAME+40`($sp)
743         stfd    $T3a,`$FRAME+48`($sp)
744         stfd    $T3b,`$FRAME+56`($sp)
745 \f
746 .align  5
747 Linner:
748         fmul    $T1a,$A1,$ba
749         fmul    $T1b,$A1,$bb
750         fmul    $T2a,$A2,$ba
751         fmul    $T2b,$A2,$bb
752         lfd     $N0,40($nap_d)          ; load n[j] in double format
753         lfd     $N1,48($nap_d)
754         fmul    $T3a,$A3,$ba
755         fmul    $T3b,$A3,$bb
756         fmadd   $T0a,$A0,$ba,$dota
757         fmadd   $T0b,$A0,$bb,$dotb
758         lfd     $N2,56($nap_d)          ; load n[j+1] in double format
759         lfdu    $N3,64($nap_d)
760
761         fmadd   $T1a,$A0,$bc,$T1a
762         fmadd   $T1b,$A0,$bd,$T1b
763         fmadd   $T2a,$A1,$bc,$T2a
764         fmadd   $T2b,$A1,$bd,$T2b
765          lfd    $A0,8($nap_d)           ; load a[j] in double format
766          lfd    $A1,16($nap_d)
767         fmadd   $T3a,$A2,$bc,$T3a
768         fmadd   $T3b,$A2,$bd,$T3b
769         fmul    $dota,$A3,$bc
770         fmul    $dotb,$A3,$bd
771          lfd    $A2,24($nap_d)          ; load a[j+1] in double format
772          lfd    $A3,32($nap_d)
773
774         fmadd   $T1a,$N1,$na,$T1a
775         fmadd   $T1b,$N1,$nb,$T1b
776          ld     $t0,`$FRAME+0`($sp)
777          ld     $t1,`$FRAME+8`($sp)
778         fmadd   $T2a,$N2,$na,$T2a
779         fmadd   $T2b,$N2,$nb,$T2b
780          ld     $t2,`$FRAME+16`($sp)
781          ld     $t3,`$FRAME+24`($sp)
782         fmadd   $T3a,$N3,$na,$T3a
783         fmadd   $T3b,$N3,$nb,$T3b
784          add    $t0,$t0,$carry          ; can not overflow
785          ld     $t4,`$FRAME+32`($sp)
786          ld     $t5,`$FRAME+40`($sp)
787         fmadd   $T0a,$N0,$na,$T0a
788         fmadd   $T0b,$N0,$nb,$T0b
789          srdi   $carry,$t0,16
790          add    $t1,$t1,$carry
791          srdi   $carry,$t1,16
792          ld     $t6,`$FRAME+48`($sp)
793          ld     $t7,`$FRAME+56`($sp)
794
795         fmadd   $T1a,$N0,$nc,$T1a
796         fmadd   $T1b,$N0,$nd,$T1b
797          insrdi $t0,$t1,16,32
798          ld     $t1,8($tp)              ; tp[j]
799         fmadd   $T2a,$N1,$nc,$T2a
800         fmadd   $T2b,$N1,$nd,$T2b
801          add    $t2,$t2,$carry
802         fmadd   $T3a,$N2,$nc,$T3a
803         fmadd   $T3b,$N2,$nd,$T3b
804          srdi   $carry,$t2,16
805          insrdi $t0,$t2,16,16
806         fmadd   $dota,$N3,$nc,$dota
807         fmadd   $dotb,$N3,$nd,$dotb
808          add    $t3,$t3,$carry
809          ldu    $t2,16($tp)             ; tp[j+1]
810          srdi   $carry,$t3,16
811          insrdi $t0,$t3,16,0            ; 0..63 bits
812          add    $t4,$t4,$carry
813
814         fctid   $T0a,$T0a
815         fctid   $T0b,$T0b
816          srdi   $carry,$t4,16
817         fctid   $T1a,$T1a
818         fctid   $T1b,$T1b
819          add    $t5,$t5,$carry
820         fctid   $T2a,$T2a
821         fctid   $T2b,$T2b
822          srdi   $carry,$t5,16
823          insrdi $t4,$t5,16,32
824         fctid   $T3a,$T3a
825         fctid   $T3b,$T3b
826          add    $t6,$t6,$carry
827          srdi   $carry,$t6,16
828          insrdi $t4,$t6,16,16
829
830         stfd    $T0a,`$FRAME+0`($sp)
831         stfd    $T0b,`$FRAME+8`($sp)
832          add    $t7,$t7,$carry
833          addc   $t3,$t0,$t1
834 ___
835 $code.=<<___ if ($SIZE_T==4);           # adjust XER[CA]
836         extrdi  $t0,$t0,32,0
837         extrdi  $t1,$t1,32,0
838         adde    $t0,$t0,$t1
839 ___
840 $code.=<<___;
841         stfd    $T1a,`$FRAME+16`($sp)
842         stfd    $T1b,`$FRAME+24`($sp)
843          insrdi $t4,$t7,16,0            ; 64..127 bits
844          srdi   $carry,$t7,16           ; upper 33 bits
845         stfd    $T2a,`$FRAME+32`($sp)
846         stfd    $T2b,`$FRAME+40`($sp)
847          adde   $t5,$t4,$t2
848 ___
849 $code.=<<___ if ($SIZE_T==4);           # adjust XER[CA]
850         extrdi  $t4,$t4,32,0
851         extrdi  $t2,$t2,32,0
852         adde    $t4,$t4,$t2
853 ___
854 $code.=<<___;
855         stfd    $T3a,`$FRAME+48`($sp)
856         stfd    $T3b,`$FRAME+56`($sp)
857          addze  $carry,$carry
858          std    $t3,-16($tp)            ; tp[j-1]
859          std    $t5,-8($tp)             ; tp[j]
860         bdnz-   Linner
861 \f
862         fctid   $dota,$dota
863         fctid   $dotb,$dotb
864         ld      $t0,`$FRAME+0`($sp)
865         ld      $t1,`$FRAME+8`($sp)
866         ld      $t2,`$FRAME+16`($sp)
867         ld      $t3,`$FRAME+24`($sp)
868         ld      $t4,`$FRAME+32`($sp)
869         ld      $t5,`$FRAME+40`($sp)
870         ld      $t6,`$FRAME+48`($sp)
871         ld      $t7,`$FRAME+56`($sp)
872         stfd    $dota,`$FRAME+64`($sp)
873         stfd    $dotb,`$FRAME+72`($sp)
874
875         add     $t0,$t0,$carry          ; can not overflow
876         srdi    $carry,$t0,16
877         add     $t1,$t1,$carry
878         srdi    $carry,$t1,16
879         insrdi  $t0,$t1,16,32
880         add     $t2,$t2,$carry
881         ld      $t1,8($tp)              ; tp[j]
882         srdi    $carry,$t2,16
883         insrdi  $t0,$t2,16,16
884         add     $t3,$t3,$carry
885         ldu     $t2,16($tp)             ; tp[j+1]
886         srdi    $carry,$t3,16
887         insrdi  $t0,$t3,16,0            ; 0..63 bits
888         add     $t4,$t4,$carry
889         srdi    $carry,$t4,16
890         add     $t5,$t5,$carry
891         srdi    $carry,$t5,16
892         insrdi  $t4,$t5,16,32
893         add     $t6,$t6,$carry
894         srdi    $carry,$t6,16
895         insrdi  $t4,$t6,16,16
896         add     $t7,$t7,$carry
897         insrdi  $t4,$t7,16,0            ; 64..127 bits
898         srdi    $carry,$t7,16           ; upper 33 bits
899         ld      $t6,`$FRAME+64`($sp)
900         ld      $t7,`$FRAME+72`($sp)
901
902         addc    $t3,$t0,$t1
903 ___
904 $code.=<<___ if ($SIZE_T==4);           # adjust XER[CA]
905         extrdi  $t0,$t0,32,0
906         extrdi  $t1,$t1,32,0
907         adde    $t0,$t0,$t1
908 ___
909 $code.=<<___;
910         adde    $t5,$t4,$t2
911 ___
912 $code.=<<___ if ($SIZE_T==4);           # adjust XER[CA]
913         extrdi  $t4,$t4,32,0
914         extrdi  $t2,$t2,32,0
915         adde    $t4,$t4,$t2
916 ___
917 $code.=<<___;
918         addze   $carry,$carry
919
920         std     $t3,-16($tp)            ; tp[j-1]
921         std     $t5,-8($tp)             ; tp[j]
922
923         add     $carry,$carry,$ovf      ; comsume upmost overflow
924         add     $t6,$t6,$carry          ; can not overflow
925         srdi    $carry,$t6,16
926         add     $t7,$t7,$carry
927         insrdi  $t6,$t7,48,0
928         srdi    $ovf,$t7,48
929         std     $t6,0($tp)              ; tp[num-1]
930
931         slwi    $t7,$num,2
932         addi    $i,$i,8
933         subf    $nap_d,$t7,$nap_d       ; rewind pointer
934         cmpw    $i,$num
935         blt-    Louter
936 ___
937 \f
938 $code.=<<___ if ($SIZE_T==8);
939         subf    $np,$num,$np    ; rewind np
940         addi    $j,$j,1         ; restore counter
941         subfc   $i,$i,$i        ; j=0 and "clear" XER[CA]
942         addi    $tp,$sp,`$FRAME+$TRANSFER+8`
943         addi    $t4,$sp,`$FRAME+$TRANSFER+16`
944         addi    $t5,$np,8
945         addi    $t6,$rp,8
946         mtctr   $j
947
948 .align  4
949 Lsub:   ldx     $t0,$tp,$i
950         ldx     $t1,$np,$i
951         ldx     $t2,$t4,$i
952         ldx     $t3,$t5,$i
953         subfe   $t0,$t1,$t0     ; tp[j]-np[j]
954         subfe   $t2,$t3,$t2     ; tp[j+1]-np[j+1]
955         stdx    $t0,$rp,$i
956         stdx    $t2,$t6,$i
957         addi    $i,$i,16
958         bdnz-   Lsub
959
960         li      $i,0
961         subfe   $ovf,$i,$ovf    ; handle upmost overflow bit
962         and     $ap,$tp,$ovf
963         andc    $np,$rp,$ovf
964         or      $ap,$ap,$np     ; ap=borrow?tp:rp
965         addi    $t7,$ap,8
966         mtctr   $j
967
968 .align  4
969 Lcopy:                          ; copy or in-place refresh
970         ldx     $t0,$ap,$i
971         ldx     $t1,$t7,$i
972         std     $i,8($nap_d)    ; zap nap_d
973         std     $i,16($nap_d)
974         std     $i,24($nap_d)
975         std     $i,32($nap_d)
976         std     $i,40($nap_d)
977         std     $i,48($nap_d)
978         std     $i,56($nap_d)
979         stdu    $i,64($nap_d)
980         stdx    $t0,$rp,$i
981         stdx    $t1,$t6,$i
982         stdx    $i,$tp,$i       ; zap tp at once
983         stdx    $i,$t4,$i
984         addi    $i,$i,16
985         bdnz-   Lcopy
986 ___
987 $code.=<<___ if ($SIZE_T==4);
988         subf    $np,$num,$np    ; rewind np
989         addi    $j,$j,1         ; restore counter
990         subfc   $i,$i,$i        ; j=0 and "clear" XER[CA]
991         addi    $tp,$sp,`$FRAME+$TRANSFER`
992         addi    $np,$np,-4
993         addi    $rp,$rp,-4
994         addi    $ap,$sp,`$FRAME+$TRANSFER+4`
995         mtctr   $j
996
997 .align  4
998 Lsub:   ld      $t0,8($tp)      ; load tp[j..j+3] in 64-bit word order
999         ldu     $t2,16($tp)
1000         lwz     $t4,4($np)      ; load np[j..j+3] in 32-bit word order
1001         lwz     $t5,8($np)
1002         lwz     $t6,12($np)
1003         lwzu    $t7,16($np)
1004         extrdi  $t1,$t0,32,0
1005         extrdi  $t3,$t2,32,0
1006         subfe   $t4,$t4,$t0     ; tp[j]-np[j]
1007          stw    $t0,4($ap)      ; save tp[j..j+3] in 32-bit word order
1008         subfe   $t5,$t5,$t1     ; tp[j+1]-np[j+1]
1009          stw    $t1,8($ap)
1010         subfe   $t6,$t6,$t2     ; tp[j+2]-np[j+2]
1011          stw    $t2,12($ap)
1012         subfe   $t7,$t7,$t3     ; tp[j+3]-np[j+3]
1013          stwu   $t3,16($ap)
1014         stw     $t4,4($rp)
1015         stw     $t5,8($rp)
1016         stw     $t6,12($rp)
1017         stwu    $t7,16($rp)
1018         bdnz-   Lsub
1019
1020         li      $i,0
1021         subfe   $ovf,$i,$ovf    ; handle upmost overflow bit
1022         addi    $tp,$sp,`$FRAME+$TRANSFER+4`
1023         subf    $rp,$num,$rp    ; rewind rp
1024         and     $ap,$tp,$ovf
1025         andc    $np,$rp,$ovf
1026         or      $ap,$ap,$np     ; ap=borrow?tp:rp
1027         addi    $tp,$sp,`$FRAME+$TRANSFER`
1028         mtctr   $j
1029
1030 .align  4
1031 Lcopy:                          ; copy or in-place refresh
1032         lwz     $t0,4($ap)
1033         lwz     $t1,8($ap)
1034         lwz     $t2,12($ap)
1035         lwzu    $t3,16($ap)
1036         std     $i,8($nap_d)    ; zap nap_d
1037         std     $i,16($nap_d)
1038         std     $i,24($nap_d)
1039         std     $i,32($nap_d)
1040         std     $i,40($nap_d)
1041         std     $i,48($nap_d)
1042         std     $i,56($nap_d)
1043         stdu    $i,64($nap_d)
1044         stw     $t0,4($rp)
1045         stw     $t1,8($rp)
1046         stw     $t2,12($rp)
1047         stwu    $t3,16($rp)
1048         std     $i,8($tp)       ; zap tp at once
1049         stdu    $i,16($tp)
1050         bdnz-   Lcopy
1051 ___
1052 \f
1053 $code.=<<___;
1054         $POP    r14,`2*$SIZE_T`($sp)
1055         $POP    r15,`3*$SIZE_T`($sp)
1056         $POP    r16,`4*$SIZE_T`($sp)
1057         $POP    r17,`5*$SIZE_T`($sp)
1058         $POP    r18,`6*$SIZE_T`($sp)
1059         $POP    r19,`7*$SIZE_T`($sp)
1060         $POP    r20,`8*$SIZE_T`($sp)
1061         $POP    r21,`9*$SIZE_T`($sp)
1062         $POP    r22,`10*$SIZE_T`($sp)
1063         $POP    r23,`11*$SIZE_T`($sp)
1064         lfd     f14,`12*$SIZE_T+0`($sp)
1065         lfd     f15,`12*$SIZE_T+8`($sp)
1066         lfd     f16,`12*$SIZE_T+16`($sp)
1067         lfd     f17,`12*$SIZE_T+24`($sp)
1068         lfd     f18,`12*$SIZE_T+32`($sp)
1069         lfd     f19,`12*$SIZE_T+40`($sp)
1070         lfd     f20,`12*$SIZE_T+48`($sp)
1071         lfd     f21,`12*$SIZE_T+56`($sp)
1072         lfd     f22,`12*$SIZE_T+64`($sp)
1073         lfd     f23,`12*$SIZE_T+72`($sp)
1074         lfd     f24,`12*$SIZE_T+80`($sp)
1075         lfd     f25,`12*$SIZE_T+88`($sp)
1076         $POP    $sp,0($sp)
1077         li      r3,1    ; signal "handled"
1078         blr
1079         .long   0
1080 .asciz  "Montgomery Multiplication for PPC64, CRYPTOGAMS by <appro\@fy.chalmers.se>"
1081 ___
1082
1083 $code =~ s/\`([^\`]*)\`/eval $1/gem;
1084 print $code;
1085 close STDOUT;