Add support for 32-bit ABI to sparcv9a-mont.pl module.
[oweals/openssl.git] / crypto / bn / asm / sparcv9a-mont.pl
1 #!/usr/bin/env perl
2
3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. Rights for redistribution and usage in source and binary
6 # forms are granted according to the OpenSSL license.
7 # ====================================================================
8
9 # October 2005
10 #
11 # "Teaser" Montgomery multiplication module for UltraSPARC. Why FPU?
12 # Because unlike integer multiplier, which simply stalls whole CPU,
13 # FPU is fully pipelined and can effectively emit 48 bit partial
14 # product every cycle. Why not blended SPARC v9? One can argue that
15 # making this module dependent on UltraSPARC VIS extension limits its
16 # binary compatibility. Very well may be, but the simple fact is that
17 # there is no known SPARC v9 implementation, which does not implement
18 # VIS. Even brand new Fujitsu's SPARC64 V is equipped with VIS unit.
19
20 # USI&II cores currently exhibit uniform 2x improvement [over pre-
21 # bn_mul_mont codebase] for all key lengths and benchmarks. On USIII
22 # performance improves few percents for shorter keys and worsens few
23 # percents for longer keys. This is because USIII integer multiplier
24 # is >3x faster than USI&II one, which is harder to match [but see
25 # TODO list below]. It should also be noted that SPARC64 V features
26 # out-of-order execution, which *might* mean that integer multiplier
27 # is pipelined, which in turn *might* be impossible to match...
28
29 # In 32-bit context the implementation implies following additional
30 # limitations on input arguments:
31 # - num may not be less than 4;
32 # - num has to be even;
33 # - ap, bp, rp, np has to be 64-bit aligned [which is not a problem
34 #   as long as BIGNUM.d are malloc-ated];
35 # Failure to meet either condition has no fatal effects, simply
36 # doesn't give any performance gain.
37
38 # TODO:
39 # - modulo-schedule inner loop for better performance (on in-order
40 #   execution core such as UltraSPARC this shall result in further
41 #   noticeable(!) improvement);
42 # - dedicated squaring procedure[?];
43
44 $fname="bn_mul_mont";
45 $bits=32;
46 for (@ARGV) {
47         $bits=64    if (/\-m64/        || /\-xarch\=v9/);
48         $vis=1      if (/\-mcpu=ultra/ || /\-xarch\=v[9|8plus]\S/);
49 }
50
51 if (!$vis) {
52 print<<___;
53 .section        ".text",#alloc,#execinstr
54 .global $fname
55 $fname:
56         retl
57         xor     %o0,%o0,%o0     ! just signal "not implemented"
58 .type   $fname,#function
59 .size   $fname,(.-$fname)
60 ___
61 exit;
62 }
63
64 if ($bits==64) {
65         $bias=2047;
66         $frame=192;
67 } else {
68         $bias=0;
69         $frame=128;     # 96 rounded up to largest known cache-line
70 }
71 $locals=64;
72
73 # In order to provide for 32-/64-bit ABI duality, I keep integers wider
74 # than 32 bit in %g1-%g4 and %o0-%o5. %l0-%l7 and %i0-%i5 are used
75 # exclusively for pointers, indexes and other small values...
76 # int bn_mul_mont(
77 $rp="%i0";      # BN_ULONG *rp,
78 $ap="%i1";      # const BN_ULONG *ap,
79 $bp="%i2";      # const BN_ULONG *bp,
80 $np="%i3";      # const BN_ULONG *np,
81 $n0="%i4";      # const BN_ULONG *n0,
82 $num="%i5";     # int num);
83
84 $tp="%l0";      # t[num]
85 $ap_l="%l1";    # a[num],n[num] are smashed to 32-bit words and saved
86 $ap_h="%l2";    # to these four vectors as double-precision FP values.
87 $np_l="%l3";    # This way a bunch of fxtods are eliminated in second
88 $np_h="%l4";    # loop and L1-cache aliasing is minimized...
89 $i="%l5";
90 $j="%l6";
91 $mask="%l7";    # 16-bit mask, 0xffff
92
93 $n0="%g4";      # reassigned(!) to "64-bit" register
94 $carry="%i4";   # %i4 reused(!) for a carry bit
95
96 # FP register naming chart
97 #
98 #     ..HILO
99 #       dcba
100 #   --------
101 #        LOa
102 #       LOb
103 #      LOc
104 #     LOd
105 #      HIa
106 #     HIb
107 #    HIc
108 #   HId
109 #    ..a
110 #   ..b
111 $ba="%f0";    $bb="%f2";    $bc="%f4";    $bd="%f6";
112 $na="%f8";    $nb="%f10";   $nc="%f12";   $nd="%f14";
113 $alo="%f16";  $alo_="%f17"; $ahi="%f18";  $ahi_="%f19";
114 $nlo="%f20";  $nlo_="%f21"; $nhi="%f22";  $nhi_="%f23";
115
116 $dota="%f24"; $dotb="%f26";
117
118 $aloa="%f32"; $alob="%f34"; $aloc="%f36"; $alod="%f38";
119 $ahia="%f40"; $ahib="%f42"; $ahic="%f44"; $ahid="%f46";
120 $nloa="%f48"; $nlob="%f50"; $nloc="%f52"; $nlod="%f54";
121 $nhia="%f56"; $nhib="%f58"; $nhic="%f60"; $nhid="%f62";
122
123 $ASI_FL16_P=0xD2;       # magic ASI value to engage 16-bit FP load
124
125 $code=<<___;
126 .ident          "UltraSPARC Montgomery multiply by <appro\@fy.chalmers.se>"
127 .section        ".text",#alloc,#execinstr
128
129 .global $fname
130 .align  32
131 $fname:
132         save    %sp,-$frame-$locals,%sp
133         sethi   %hi(0xffff),$mask
134         or      $mask,%lo(0xffff),$mask
135 ___
136 $code.=<<___ if ($bits==64);
137         ldx     [%i4],$n0               ! $n0 reassigned, remember?
138 ___
139 $code.=<<___ if ($bits==32);
140         cmp     $num,4
141         bl,a,pn %icc,.Lret
142         clr     %i0
143         andcc   $num,1,%g0              ! $num has to be even...
144         bnz,a,pn %icc,.Lret
145         clr     %i0                     ! signal "unsupported input value"
146         or      $bp,$ap,%l0
147         srl     $num,1,$num
148         or      $rp,$np,%l1
149         or      %l0,%l1,%l0
150         andcc   %l0,7,%g0               ! ...and pointers has to be 8-byte aligned
151         bnz,a,pn %icc,.Lret
152         clr     %i0                     ! signal "unsupported input value"
153         ld      [%i4+0],$n0             ! $n0 reassigned, remember?
154         ld      [%i4+4],%o0
155         sllx    %o0,32,%o0
156         or      %o0,$n0,$n0             ! $n0=n0[1].n0[0]
157 ___
158 $code.=<<___;
159         sll     $num,3,$num             ! num*=8
160
161         add     %sp,$bias,%o0           ! real top of stack
162         sll     $num,2,%o1
163         add     %o1,$num,%o1            ! %o1=num*5
164         sub     %o0,%o1,%o0
165         and     %o0,-2048,%o0           ! optimize TLB utilization
166         sub     %o0,$bias,%sp           ! alloca(5*num*8)
167
168         rd      %asi,%o7                ! save %asi
169         add     %sp,$bias+$frame+$locals,$tp
170         add     $tp,$num,$ap_l
171         add     $ap_l,$num,$ap_l        ! [an]p_[lh] point at the vectors' ends !
172         add     $ap_l,$num,$ap_h
173         add     $ap_h,$num,$np_l
174         add     $np_l,$num,$np_h
175
176         wr      %g0,$ASI_FL16_P,%asi    ! setup %asi for 16-bit FP loads
177
178         add     $rp,$num,$rp            ! readjust input pointers to point
179         add     $ap,$num,$ap            ! at the ends too...
180         add     $bp,$num,$bp
181         add     $np,$num,$np
182
183         stx     %o7,[%sp+$bias+$frame+48]       ! save %asi
184 \f
185         sub     %g0,$num,$i
186         sub     %g0,$num,$j
187
188         add     $ap,$j,%o3
189         add     $bp,$i,%o4
190 ___
191 $code.=<<___ if ($bits==64);
192         ldx     [$bp+$i],%o0            ! bp[0]
193         ldx     [$ap+$j],%o1            ! ap[0]
194 ___
195 $code.=<<___ if ($bits==32);
196         ldd     [$bp+$i],%o0            ! bp[0]
197         ldd     [$ap+$j],%g2            ! ap[0]
198         sllx    %o1,32,%o1
199         sllx    %g3,32,%g3
200         or      %o0,%o1,%o0
201         or      %g2,%g3,%o1
202 ___
203 $code.=<<___;
204         add     $np,$j,%o5
205
206         mulx    %o1,%o0,%o0             ! ap[0]*bp[0]
207         mulx    $n0,%o0,%o0             ! ap[0]*bp[0]*n0
208         stx     %o0,[%sp+$bias+$frame+0]
209
210         ld      [%o3+`$bits==32 ? 0 : 4`],$alo_ ! load a[j] as pair of 32-bit words
211         fzeros  $alo
212         ld      [%o3+`$bits==32 ? 4 : 0`],$ahi_
213         fzeros  $ahi
214         ld      [%o5+`$bits==32 ? 0 : 4`],$nlo_ ! load n[j] as pair of 32-bit words
215         fzeros  $nlo
216         ld      [%o5+`$bits==32 ? 4 : 0`],$nhi_
217         fzeros  $nhi
218
219         ! transfer b[i] to FPU as 4x16-bit values
220         ldda    [%o4+`$bits==32 ? 2 : 6`]%asi,$ba
221         fxtod   $alo,$alo
222         ldda    [%o4+`$bits==32 ? 0 : 4`]%asi,$bb
223         fxtod   $ahi,$ahi
224         ldda    [%o4+`$bits==32 ? 6 : 2`]%asi,$bc
225         fxtod   $nlo,$nlo
226         ldda    [%o4+`$bits==32 ? 4 : 0`]%asi,$bd
227         fxtod   $nhi,$nhi
228
229         ! transfer ap[0]*b[0]*n0 to FPU as 4x16-bit values
230         ldda    [%sp+$bias+$frame+6]%asi,$na
231         fxtod   $ba,$ba
232         ldda    [%sp+$bias+$frame+4]%asi,$nb
233         fxtod   $bb,$bb
234         ldda    [%sp+$bias+$frame+2]%asi,$nc
235         fxtod   $bc,$bc
236         ldda    [%sp+$bias+$frame+0]%asi,$nd
237         fxtod   $bd,$bd
238
239         std     $alo,[$ap_l+$j]         ! save smashed ap[j] in double format
240         fxtod   $na,$na
241         std     $ahi,[$ap_h+$j]
242         fxtod   $nb,$nb
243         std     $nlo,[$np_l+$j]         ! save smashed np[j] in double format
244         fxtod   $nc,$nc
245         std     $nhi,[$np_h+$j]
246         fxtod   $nd,$nd
247
248                 fmuld   $alo,$ba,$aloa
249                 fmuld   $nlo,$na,$nloa
250                 fmuld   $alo,$bb,$alob
251                 fmuld   $nlo,$nb,$nlob
252                 fmuld   $alo,$bc,$aloc
253                 fmuld   $nlo,$nc,$nloc
254         faddd   $aloa,$nloa,$nloa
255                 fmuld   $alo,$bd,$alod
256                 fmuld   $nlo,$nd,$nlod
257         faddd   $alob,$nlob,$nlob
258                 fmuld   $ahi,$ba,$ahia
259                 fmuld   $nhi,$na,$nhia
260         faddd   $aloc,$nloc,$nloc
261                 fmuld   $ahi,$bb,$ahib
262                 fmuld   $nhi,$nb,$nhib
263         faddd   $alod,$nlod,$nlod
264                 fmuld   $ahi,$bc,$ahic
265                 fmuld   $nhi,$nc,$nhic
266         faddd   $ahia,$nhia,$nhia
267                 fmuld   $ahi,$bd,$ahid
268                 fmuld   $nhi,$nd,$nhid
269
270         faddd   $ahib,$nhib,$nhib
271         faddd   $ahic,$nhic,$dota       ! $nhic
272         faddd   $ahid,$nhid,$dotb       ! $nhid
273
274         faddd   $nloc,$nhia,$nloc
275         faddd   $nlod,$nhib,$nlod
276
277         fdtox   $nloa,$nloa
278         fdtox   $nlob,$nlob
279         fdtox   $nloc,$nloc
280         fdtox   $nlod,$nlod
281
282         std     $nloa,[%sp+$bias+$frame+0]
283         std     $nlob,[%sp+$bias+$frame+8]
284         std     $nloc,[%sp+$bias+$frame+16]
285         std     $nlod,[%sp+$bias+$frame+24]
286         ldx     [%sp+$bias+$frame+0],%o0
287         ldx     [%sp+$bias+$frame+8],%o1
288         ldx     [%sp+$bias+$frame+16],%o2
289         ldx     [%sp+$bias+$frame+24],%o3
290
291         srlx    %o0,16,%o7
292         add     %o7,%o1,%o1
293         srlx    %o1,16,%o7
294         add     %o7,%o2,%o2
295         srlx    %o2,16,%o7
296         add     %o7,%o3,%o3             ! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
297         !and    %o0,$mask,%o0
298         !and    %o1,$mask,%o1
299         !and    %o2,$mask,%o2
300         !sllx   %o1,16,%o1
301         !sllx   %o2,32,%o2
302         !sllx   %o3,48,%o7
303         !or     %o1,%o0,%o0
304         !or     %o2,%o0,%o0
305         !or     %o7,%o0,%o0             ! 64-bit result
306         srlx    %o3,16,%g1              ! 34-bit carry
307 \f
308         ba      .L1st
309         add     $j,8,$j
310 .align  32
311 .L1st:
312         add     $ap,$j,%o3
313         add     $np,$j,%o4
314         ld      [%o3+`$bits==32 ? 0 : 4`],$alo_ ! load a[j] as pair of 32-bit words
315         fzeros  $alo
316         ld      [%o3+`$bits==32 ? 4 : 0`],$ahi_
317         fzeros  $ahi
318         ld      [%o4+`$bits==32 ? 0 : 4`],$nlo_ ! load n[j] as pair of 32-bit words
319         fzeros  $nlo
320         ld      [%o4+`$bits==32 ? 4 : 0`],$nhi_
321         fzeros  $nhi
322
323         fxtod   $alo,$alo
324         fxtod   $ahi,$ahi
325         fxtod   $nlo,$nlo
326         fxtod   $nhi,$nhi
327
328         std     $alo,[$ap_l+$j]         ! save smashed ap[j] in double format
329                 fmuld   $alo,$ba,$aloa
330         std     $ahi,[$ap_h+$j]
331                 fmuld   $nlo,$na,$nloa
332         std     $nlo,[$np_l+$j]         ! save smashed np[j] in double format
333                 fmuld   $alo,$bb,$alob
334         std     $nhi,[$np_h+$j]
335                 fmuld   $nlo,$nb,$nlob
336                 fmuld   $alo,$bc,$aloc
337                 fmuld   $nlo,$nc,$nloc
338         faddd   $aloa,$nloa,$nloa
339                 fmuld   $alo,$bd,$alod
340                 fmuld   $nlo,$nd,$nlod
341         faddd   $alob,$nlob,$nlob
342                 fmuld   $ahi,$ba,$ahia
343                 fmuld   $nhi,$na,$nhia
344         faddd   $aloc,$nloc,$nloc
345                 fmuld   $ahi,$bb,$ahib
346                 fmuld   $nhi,$nb,$nhib
347         faddd   $alod,$nlod,$nlod
348                 fmuld   $ahi,$bc,$ahic
349                 fmuld   $nhi,$nc,$nhic
350         faddd   $ahia,$nhia,$nhia
351                 fmuld   $ahi,$bd,$ahid
352                 fmuld   $nhi,$nd,$nhid
353         faddd   $ahib,$nhib,$nhib
354
355         faddd   $dota,$nloa,$nloa
356         faddd   $dotb,$nlob,$nlob
357         faddd   $ahic,$nhic,$dota       ! $nhic
358         faddd   $ahid,$nhid,$dotb       ! $nhid
359
360         faddd   $nloc,$nhia,$nloc
361         faddd   $nlod,$nhib,$nlod
362
363         fdtox   $nloa,$nloa
364         fdtox   $nlob,$nlob
365         fdtox   $nloc,$nloc
366         fdtox   $nlod,$nlod
367
368         std     $nloa,[%sp+$bias+$frame+0]
369         std     $nlob,[%sp+$bias+$frame+8]
370         std     $nloc,[%sp+$bias+$frame+16]
371         std     $nlod,[%sp+$bias+$frame+24]
372         ldx     [%sp+$bias+$frame+0],%o0
373         ldx     [%sp+$bias+$frame+8],%o1
374         ldx     [%sp+$bias+$frame+16],%o2
375         ldx     [%sp+$bias+$frame+24],%o3
376
377         srlx    %o0,16,%o7
378         add     %o7,%o1,%o1
379         srlx    %o1,16,%o7
380         add     %o7,%o2,%o2
381         srlx    %o2,16,%o7
382         add     %o7,%o3,%o3             ! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
383         and     %o0,$mask,%o0
384         and     %o1,$mask,%o1
385         and     %o2,$mask,%o2
386         sllx    %o1,16,%o1
387         sllx    %o2,32,%o2
388         sllx    %o3,48,%o7
389         or      %o1,%o0,%o0
390         or      %o2,%o0,%o0
391         or      %o7,%o0,%o0             ! 64-bit result
392         addcc   %g1,%o0,%o0
393         srlx    %o3,16,%g1              ! 34-bit carry
394         bcs,a   %xcc,.+8
395         add     %g1,1,%g1
396
397         stx     %o0,[$tp]               ! tp[j-1]=
398         addcc   $j,8,$j
399         bnz,pt  %icc,.L1st
400         add     $tp,8,$tp
401 \f
402         fdtox   $dota,$dota
403         fdtox   $dotb,$dotb
404         std     $dota,[%sp+$bias+$frame+32]
405         std     $dotb,[%sp+$bias+$frame+40]
406         ldx     [%sp+$bias+$frame+32],%o0
407         ldx     [%sp+$bias+$frame+40],%o1
408
409         srlx    %o0,16,%o7
410         add     %o7,%o1,%o1
411         and     %o0,$mask,%o0
412         sllx    %o1,16,%o7
413         or      %o7,%o0,%o0
414         addcc   %g1,%o0,%o0
415         srlx    %o1,48,%g1
416         bcs,a   %xcc,.+8
417         add     %g1,1,%g1
418
419         mov     %g1,$carry
420         stx     %o0,[$tp]               ! tp[num-1]=
421 \f
422         ba      .Louter
423         add     $i,8,$i
424 .align  32
425 .Louter:
426         sub     %g0,$num,$j
427         add     %sp,$bias+$frame+$locals,$tp
428
429         add     $bp,$i,%o4
430 ___
431 $code.=<<___ if ($bits==64);
432         ldx     [$bp+$i],%o0            ! bp[i]
433         ldx     [$ap+$j],%o1            ! ap[0]
434 ___
435 $code.=<<___ if ($bits==32);
436         ldd     [$bp+$i],%o0            ! bp[i]
437         ldd     [$ap+$j],%g2            ! ap[0]
438         sllx    %o1,32,%o1
439         sllx    %g3,32,%g3
440         or      %o0,%o1,%o0
441         or      %g2,%g3,%o1
442 ___
443 $code.=<<___;
444         ldx     [$tp],%o2               ! tp[0]
445         mulx    %o1,%o0,%o0
446         addcc   %o2,%o0,%o0
447         mulx    $n0,%o0,%o0             ! (ap[0]*bp[i]+t[0])*n0
448         stx     %o0,[%sp+$bias+$frame+0]
449
450
451         ! transfer b[i] to FPU as 4x16-bit values
452         ldda    [%o4+`$bits==32 ? 2 : 6`]%asi,$ba
453         ldda    [%o4+`$bits==32 ? 0 : 4`]%asi,$bb
454         ldda    [%o4+`$bits==32 ? 6 : 2`]%asi,$bc
455         ldda    [%o4+`$bits==32 ? 4 : 0`]%asi,$bd
456
457         ! transfer (ap[0]*b[i]+t[0])*n0 to FPU as 4x16-bit values
458         ldda    [%sp+$bias+$frame+6]%asi,$na
459         fxtod   $ba,$ba
460         ldda    [%sp+$bias+$frame+4]%asi,$nb
461         fxtod   $bb,$bb
462         ldda    [%sp+$bias+$frame+2]%asi,$nc
463         fxtod   $bc,$bc
464         ldda    [%sp+$bias+$frame+0]%asi,$nd
465         fxtod   $bd,$bd
466         ldd     [$ap_l+$j],$alo         ! load a[j] in double format
467         fxtod   $na,$na
468         ldd     [$ap_h+$j],$ahi
469         fxtod   $nb,$nb
470         ldd     [$np_l+$j],$nlo         ! load n[j] in double format
471         fxtod   $nc,$nc
472         ldd     [$np_h+$j],$nhi
473         fxtod   $nd,$nd
474
475                 fmuld   $alo,$ba,$aloa
476                 fmuld   $nlo,$na,$nloa
477                 fmuld   $alo,$bb,$alob
478                 fmuld   $nlo,$nb,$nlob
479                 fmuld   $alo,$bc,$aloc
480                 fmuld   $nlo,$nc,$nloc
481         faddd   $aloa,$nloa,$nloa
482                 fmuld   $alo,$bd,$alod
483                 fmuld   $nlo,$nd,$nlod
484         faddd   $alob,$nlob,$nlob
485                 fmuld   $ahi,$ba,$ahia
486                 fmuld   $nhi,$na,$nhia
487         faddd   $aloc,$nloc,$nloc
488                 fmuld   $ahi,$bb,$ahib
489                 fmuld   $nhi,$nb,$nhib
490         faddd   $alod,$nlod,$nlod
491                 fmuld   $ahi,$bc,$ahic
492                 fmuld   $nhi,$nc,$nhic
493         faddd   $ahia,$nhia,$nhia
494                 fmuld   $ahi,$bd,$ahid
495                 fmuld   $nhi,$nd,$nhid
496
497         faddd   $ahib,$nhib,$nhib
498         faddd   $ahic,$nhic,$dota       ! $nhic
499         faddd   $ahid,$nhid,$dotb       ! $nhid
500
501         faddd   $nloc,$nhia,$nloc
502         faddd   $nlod,$nhib,$nlod
503
504         fdtox   $nloa,$nloa
505         fdtox   $nlob,$nlob
506         fdtox   $nloc,$nloc
507         fdtox   $nlod,$nlod
508
509         std     $nloa,[%sp+$bias+$frame+0]
510         std     $nlob,[%sp+$bias+$frame+8]
511         std     $nloc,[%sp+$bias+$frame+16]
512         std     $nlod,[%sp+$bias+$frame+24]
513         ldx     [%sp+$bias+$frame+0],%o0
514         ldx     [%sp+$bias+$frame+8],%o1
515         ldx     [%sp+$bias+$frame+16],%o2
516         ldx     [%sp+$bias+$frame+24],%o3
517
518         srlx    %o0,16,%o7
519         add     %o7,%o1,%o1
520         srlx    %o1,16,%o7
521         add     %o7,%o2,%o2
522         srlx    %o2,16,%o7
523         add     %o7,%o3,%o3             ! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
524         ! why?
525         and     %o0,$mask,%o0
526         and     %o1,$mask,%o1
527         and     %o2,$mask,%o2
528         sllx    %o1,16,%o1
529         sllx    %o2,32,%o2
530         sllx    %o3,48,%o7
531         or      %o1,%o0,%o0
532         or      %o2,%o0,%o0
533         or      %o7,%o0,%o0             ! 64-bit result
534         ldx     [$tp],%o7
535         addcc   %o7,%o0,%o0
536         ! end-of-why?
537         srlx    %o3,16,%g1              ! 34-bit carry
538         bcs,a   %xcc,.+8
539         add     %g1,1,%g1
540 \f
541         ba      .Linner
542         add     $j,8,$j
543 .align  32
544 .Linner:
545         ldd     [$ap_l+$j],$alo         ! load a[j] in double format
546         ldd     [$ap_h+$j],$ahi
547         ldd     [$np_l+$j],$nlo         ! load n[j] in double format
548         ldd     [$np_h+$j],$nhi
549
550                 fmuld   $alo,$ba,$aloa
551                 fmuld   $nlo,$na,$nloa
552                 fmuld   $alo,$bb,$alob
553                 fmuld   $nlo,$nb,$nlob
554                 fmuld   $alo,$bc,$aloc
555                 fmuld   $nlo,$nc,$nloc
556         faddd   $aloa,$nloa,$nloa
557                 fmuld   $alo,$bd,$alod
558                 fmuld   $nlo,$nd,$nlod
559         faddd   $alob,$nlob,$nlob
560                 fmuld   $ahi,$ba,$ahia
561                 fmuld   $nhi,$na,$nhia
562         faddd   $aloc,$nloc,$nloc
563                 fmuld   $ahi,$bb,$ahib
564                 fmuld   $nhi,$nb,$nhib
565         faddd   $alod,$nlod,$nlod
566                 fmuld   $ahi,$bc,$ahic
567                 fmuld   $nhi,$nc,$nhic
568         faddd   $ahia,$nhia,$nhia
569                 fmuld   $ahi,$bd,$ahid
570                 fmuld   $nhi,$nd,$nhid
571
572         faddd   $ahib,$nhib,$nhib
573         faddd   $dota,$nloa,$nloa
574         faddd   $dotb,$nlob,$nlob
575         faddd   $ahic,$nhic,$dota       ! $nhic
576         faddd   $ahid,$nhid,$dotb       ! $nhid
577
578         faddd   $nloc,$nhia,$nloc
579         faddd   $nlod,$nhib,$nlod
580
581         fdtox   $nloa,$nloa
582         fdtox   $nlob,$nlob
583         fdtox   $nloc,$nloc
584         fdtox   $nlod,$nlod
585
586         std     $nloa,[%sp+$bias+$frame+0]
587         std     $nlob,[%sp+$bias+$frame+8]
588         std     $nloc,[%sp+$bias+$frame+16]
589         std     $nlod,[%sp+$bias+$frame+24]
590         ldx     [%sp+$bias+$frame+0],%o0
591         ldx     [%sp+$bias+$frame+8],%o1
592         ldx     [%sp+$bias+$frame+16],%o2
593         ldx     [%sp+$bias+$frame+24],%o3
594
595         srlx    %o0,16,%o7
596         add     %o7,%o1,%o1
597         srlx    %o1,16,%o7
598         add     %o7,%o2,%o2
599         srlx    %o2,16,%o7
600         add     %o7,%o3,%o3             ! %o3.%o2[0..15].%o1[0..15].%o0[0..15]
601         and     %o0,$mask,%o0
602         and     %o1,$mask,%o1
603         and     %o2,$mask,%o2
604         sllx    %o1,16,%o1
605         sllx    %o2,32,%o2
606         sllx    %o3,48,%o7
607         or      %o1,%o0,%o0
608         or      %o2,%o0,%o0
609         or      %o7,%o0,%o0             ! 64-bit result
610         addcc   %g1,%o0,%o0
611         srlx    %o3,16,%g1              ! 34-bit carry
612         bcs,a   %xcc,.+8
613         add     %g1,1,%g1
614
615         ldx     [$tp+8],%o7             ! tp[j]
616         addcc   %o7,%o0,%o0
617         bcs,a   %xcc,.+8
618         add     %g1,1,%g1
619
620         stx     %o0,[$tp]               ! tp[j-1]
621         addcc   $j,8,$j
622         bnz,pt  %icc,.Linner
623         add     $tp,8,$tp
624 \f
625         fdtox   $dota,$dota
626         fdtox   $dotb,$dotb
627         std     $dota,[%sp+$bias+$frame+32]
628         std     $dotb,[%sp+$bias+$frame+40]
629         ldx     [%sp+$bias+$frame+32],%o0
630         ldx     [%sp+$bias+$frame+40],%o1
631
632         srlx    %o0,16,%o7
633         add     %o7,%o1,%o1
634         and     %o0,$mask,%o0
635         sllx    %o1,16,%o7
636         or      %o7,%o0,%o0
637         addcc   %g1,%o0,%o0
638         srlx    %o1,48,%g1
639         bcs,a   %xcc,.+8
640         add     %g1,1,%g1
641
642         addcc   $carry,%o0,%o0
643         stx     %o0,[$tp]               ! tp[num-1]
644         mov     %g1,$carry
645         bcs,a   %xcc,.+8
646         add     $carry,1,$carry
647
648         addcc   $i,8,$i
649         bnz     %icc,.Louter
650         nop
651 \f
652         sub     %g0,$num,%o7            ! n=-num
653         cmp     $carry,0                ! clears %icc.c
654         bne,pn  %icc,.Lsub
655         add     $tp,8,$tp               ! adjust tp to point at the end
656
657         ld      [$tp-8],%o0
658         ld      [$np-`$bits==32 ? 4 : 8`],%o1
659         cmp     %o0,%o1                 ! compare topmost words
660         bcs,pt  %icc,.Lcopy             ! %icc.c is clean if not taken
661         nop
662
663 .align  32,0x1000000
664 .Lsub:
665         ldd     [$tp+%o7],%o0
666         ldd     [$np+%o7],%o2
667 ___
668 $code.=<<___ if ($bits==64);
669         subccc  %o1,%o3,%o3
670         subccc  %o0,%o2,%o2
671 ___
672 $code.=<<___ if ($bits==32);
673         subccc  %o1,%o2,%o2
674         subccc  %o0,%o3,%o3
675 ___
676 $code.=<<___;
677         std     %o2,[$rp+%o7]
678         add     %o7,8,%o7
679         brnz,pt %o7,.Lsub
680         nop
681         subccc  $carry,0,$carry
682         bcc,pt  %icc,.Lzap
683         sub     %g0,$num,%o7
684
685 .align  16,0x1000000
686 .Lcopy:
687         ldx     [$tp+%o7],%o0
688 ___
689 $code.=<<___ if ($bits==64);
690         stx     %o0,[$rp+%o7]
691 ___
692 $code.=<<___ if ($bits==32);
693         srlx    %o0,32,%o1
694         std     %o0,[$rp+%o7]
695 ___
696 $code.=<<___;
697         add     %o7,8,%o7
698         brnz,pt %o7,.Lcopy
699         nop
700         ba      .Lzap
701         sub     %g0,$num,%o7
702
703 .align  32
704 .Lzap:
705         stx     %g0,[$tp+%o7]
706         stx     %g0,[$ap_l+%o7]
707         stx     %g0,[$ap_h+%o7]
708         stx     %g0,[$np_l+%o7]
709         stx     %g0,[$np_h+%o7]
710         add     %o7,8,%o7
711         brnz,pt %o7,.Lzap
712         nop
713
714         ldx     [%sp+$bias+$frame+48],%o7
715         wr      %g0,%o7,%asi            ! restore %asi
716
717         mov     1,%i0
718 .Lret:
719         ret
720         restore
721 .type   $fname,#function
722 .size   $fname,(.-$fname)
723 ___
724
725 $code =~ s/\`([^\`]*)\`/eval($1)/gem;
726 print $code;
727 close STDOUT;