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