Add BN support for SPARC VIS3 and T4 [from master].
[openssl.git] / crypto / bn / asm / sparct4-mont.pl
1 #!/usr/bin/env perl
2
3 # ====================================================================
4 # Written by David S. Miller <davem@devemloft.net> and Andy Polyakov
5 # <appro@openssl.org>. The module is licensed under 2-clause BSD
6 # license. November 2012. All rights reserved.
7 # ====================================================================
8
9 ######################################################################
10 # Montgomery squaring-n-multiplication module for SPARC T4.
11 #
12 # The module consists of three parts:
13 #
14 # 1) collection of "single-op" subroutines that perform single
15 #    operation, Montgomery squaring or multiplication, on 512-,
16 #    1024-, 1536- and 2048-bit operands;
17 # 2) collection of "multi-op" subroutines that perform 5 squaring and
18 #    1 multiplication operations on operands of above lengths;
19 # 3) fall-back and helper VIS3 subroutines.
20 #
21 # RSA sign is dominated by multi-op subroutine, while RSA verify and
22 # DSA - by single-op. Special note about 4096-bit RSA verify result.
23 # Operands are too long for dedicated hardware and it's handled by
24 # VIS3 code, which is why you don't see any improvement. It's surely
25 # possible to improve it [by deploying 'mpmul' instruction], maybe in
26 # the future...
27 #
28 # Performance improvement.
29 #
30 # 64-bit process, VIS3:
31 #                   sign    verify    sign/s verify/s
32 # rsa 1024 bits 0.000633s 0.000033s   1578.9  30513.3
33 # rsa 2048 bits 0.003297s 0.000116s    303.3   8585.8
34 # rsa 4096 bits 0.026000s 0.000387s     38.5   2587.0
35 # dsa 1024 bits 0.000301s 0.000332s   3323.7   3013.9
36 # dsa 2048 bits 0.001056s 0.001233s    946.9    810.8
37 #
38 # 64-bit process, this module:
39 #                   sign    verify    sign/s verify/s
40 # rsa 1024 bits 0.000341s 0.000021s   2931.5  46873.8
41 # rsa 2048 bits 0.001244s 0.000044s    803.9  22569.1
42 # rsa 4096 bits 0.006203s 0.000387s    161.2   2586.3
43 # dsa 1024 bits 0.000179s 0.000195s   5573.9   5115.6
44 # dsa 2048 bits 0.000311s 0.000350s   3212.3   2856.6
45 #
46 ######################################################################
47 # 32-bit process, VIS3:
48 #                   sign    verify    sign/s verify/s
49 # rsa 1024 bits 0.000675s 0.000033s   1480.9  30159.0
50 # rsa 2048 bits 0.003383s 0.000118s    295.6   8499.9
51 # rsa 4096 bits 0.026178s 0.000394s     38.2   2541.3
52 # dsa 1024 bits 0.000326s 0.000343s   3070.0   2918.8
53 # dsa 2048 bits 0.001121s 0.001291s    891.9    774.4
54 #
55 # 32-bit process, this module:
56 #                   sign    verify    sign/s verify/s
57 # rsa 1024 bits 0.000386s 0.000022s   2589.6  45704.9
58 # rsa 2048 bits 0.001335s 0.000046s    749.3  21766.8
59 # rsa 4096 bits 0.006390s 0.000393s    156.5   2544.8
60 # dsa 1024 bits 0.000208s 0.000204s   4817.6   4896.6
61 # dsa 2048 bits 0.000345s 0.000364s   2898.8   2747.3
62 #
63 # 32-bit code is prone to performance degradation as interrupt rate
64 # dispatched to CPU executing the code grows. This is because in
65 # standard process of handling interrupt in 32-bit process context
66 # upper halves of most integer registers used as input or output are
67 # zeroed. This renders result invalid, and operation has to be re-run.
68 # If CPU is "bothered" with timer interrupts only, the penalty is
69 # hardly measurable. But in order to mitigate this problem for higher
70 # interrupt rates contemporary Linux kernel recognizes biased stack
71 # even in 32-bit process context and preserves full register contents.
72 # See http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;h=517ffce4e1a03aea979fe3a18a3dd1761a24fafb
73 # for details.
74
75 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
76 push(@INC,"${dir}","${dir}../../perlasm");
77 require "sparcv9_modes.pl";
78
79 $code.=<<___;
80 #include "sparc_arch.h"
81
82 #ifdef  __arch64__
83 .register       %g2,#scratch
84 .register       %g3,#scratch
85 #endif
86
87 .section        ".text",#alloc,#execinstr
88
89 #ifdef  __PIC__
90 SPARC_PIC_THUNK(%g1)
91 #endif
92 ___
93
94 ########################################################################
95 # Register layout for mont[mul|sqr] instructions.
96 # For details see "Oracle SPARC Architecture 2011" manual at
97 # http://www.oracle.com/technetwork/server-storage/sun-sparc-enterprise/documentation/.
98 #
99 my @R=map("%f".2*$_,(0..11,30,31,12..29));
100 my @N=(map("%l$_",(0..7)),map("%o$_",(0..5))); @N=(@N,@N,@N[0..3]);
101 my @B=(map("%o$_",(0..5)),@N[0..13],@N[0..11]);
102 my @A=(@N[0..13],@R[14..31]);
103 \f
104 ########################################################################
105 # int bn_mul_mont_t4_$NUM(u64 *rp,const u64 *ap,const u64 *bp,
106 #                         const u64 *np,const BN_ULONG *n0);
107 #
108 sub generate_bn_mul_mont_t4() {
109 my $NUM=shift;
110 my ($rp,$ap,$bp,$np,$sentinel)=map("%g$_",(1..5));
111
112 $code.=<<___;
113 .globl  bn_mul_mont_t4_$NUM
114 .align  32
115 bn_mul_mont_t4_$NUM:
116 #ifdef  __arch64__
117         mov     0,$sentinel
118         mov     -128,%g4
119 #elif defined(SPARCV9_64BIT_STACK)
120         SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
121         ld      [%g1+0],%g1     ! OPENSSL_sparcv9_P[0]
122         mov     -2047,%g4
123         and     %g1,SPARCV9_64BIT_STACK,%g1
124         movrz   %g1,0,%g4
125         mov     -1,$sentinel
126         add     %g4,-128,%g4
127 #else
128         mov     -1,$sentinel
129         mov     -128,%g4
130 #endif
131         sllx    $sentinel,32,$sentinel
132         save    %sp,%g4,%sp
133 #ifndef __arch64__
134         save    %sp,-128,%sp    ! warm it up
135         save    %sp,-128,%sp
136         save    %sp,-128,%sp
137         save    %sp,-128,%sp
138         save    %sp,-128,%sp
139         save    %sp,-128,%sp
140         restore
141         restore
142         restore
143         restore
144         restore
145         restore
146 #endif
147         and     %sp,1,%g4
148         or      $sentinel,%fp,%fp
149         or      %g4,$sentinel,$sentinel
150
151         ! copy arguments to global registers
152         mov     %i0,$rp
153         mov     %i1,$ap
154         mov     %i2,$bp
155         mov     %i3,$np
156         ld      [%i4+0],%f1     ! load *n0
157         ld      [%i4+4],%f0
158         fsrc2   %f0,%f60
159 ___
160 \f
161 # load ap[$NUM] ########################################################
162 $code.=<<___;
163         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
164 ___
165 for($i=0; $i<14 && $i<$NUM; $i++) {
166 my $lo=$i<13?@A[$i+1]:"%o7";
167 $code.=<<___;
168         ld      [$ap+$i*8+0],$lo
169         ld      [$ap+$i*8+4],@A[$i]
170         sllx    @A[$i],32,@A[$i]
171         or      $lo,@A[$i],@A[$i]
172 ___
173 }
174 for(; $i<$NUM; $i++) {
175 my ($hi,$lo)=("%f".2*($i%4),"%f".(2*($i%4)+1));
176 $code.=<<___;
177         ld      [$ap+$i*8+0],$lo
178         ld      [$ap+$i*8+4],$hi
179         fsrc2   $hi,@A[$i]
180 ___
181 }
182 # load np[$NUM] ########################################################
183 $code.=<<___;
184         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
185 ___
186 for($i=0; $i<14 && $i<$NUM; $i++) {
187 my $lo=$i<13?@N[$i+1]:"%o7";
188 $code.=<<___;
189         ld      [$np+$i*8+0],$lo
190         ld      [$np+$i*8+4],@N[$i]
191         sllx    @N[$i],32,@N[$i]
192         or      $lo,@N[$i],@N[$i]
193 ___
194 }
195 $code.=<<___;
196         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
197 ___
198 for(; $i<28 && $i<$NUM; $i++) {
199 my $lo=$i<27?@N[$i+1]:"%o7";
200 $code.=<<___;
201         ld      [$np+$i*8+0],$lo
202         ld      [$np+$i*8+4],@N[$i]
203         sllx    @N[$i],32,@N[$i]
204         or      $lo,@N[$i],@N[$i]
205 ___
206 }
207 $code.=<<___;
208         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
209 ___
210 for(; $i<$NUM; $i++) {
211 my $lo=($i<$NUM-1)?@N[$i+1]:"%o7";
212 $code.=<<___;
213         ld      [$np+$i*8+0],$lo
214         ld      [$np+$i*8+4],@N[$i]
215         sllx    @N[$i],32,@N[$i]
216         or      $lo,@N[$i],@N[$i]
217 ___
218 }
219 $code.=<<___;
220         cmp     $ap,$bp
221         be      SIZE_T_CC,.Lmsquare_$NUM
222         nop
223 ___
224 \f
225 # load bp[$NUM] ########################################################
226 for($i=0; $i<6 && $i<$NUM; $i++) {
227 my $lo=$i<5?@B[$i+1]:"%o7";
228 $code.=<<___;
229         ld      [$bp+$i*8+0],$lo
230         ld      [$bp+$i*8+4],@B[$i]
231         sllx    @B[$i],32,@B[$i]
232         or      $lo,@B[$i],@B[$i]
233 ___
234 }
235 $code.=<<___;
236         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
237 ___
238 for(; $i<20 && $i<$NUM; $i++) {
239 my $lo=$i<19?@B[$i+1]:"%o7";
240 $code.=<<___;
241         ld      [$bp+$i*8+0],$lo
242         ld      [$bp+$i*8+4],@B[$i]
243         sllx    @B[$i],32,@B[$i]
244         or      $lo,@B[$i],@B[$i]
245 ___
246 }
247 $code.=<<___;
248         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
249 ___
250 for(; $i<$NUM; $i++) {
251 my $lo=($i<$NUM-1)?@B[$i+1]:"%o7";
252 $code.=<<___;
253         ld      [$bp+$i*8+0],$lo
254         ld      [$bp+$i*8+4],@B[$i]
255         sllx    @B[$i],32,@B[$i]
256         or      $lo,@B[$i],@B[$i]
257 ___
258 }
259 # magic ################################################################
260 $code.=<<___;
261         .word   0x81b02920+$NUM-1       ! montmul       $NUM-1
262 .Lmresume_$NUM:
263         fbu,pn  %fcc3,.Lmabort_$NUM
264 #ifndef __arch64__
265         and     %fp,$sentinel,$sentinel
266         brz,pn  $sentinel,.Lmabort_$NUM
267 #endif
268         nop
269 #ifdef  __arch64__
270         restore
271         restore
272         restore
273         restore
274         restore
275 #else
276         restore;                and     %fp,$sentinel,$sentinel
277         restore;                and     %fp,$sentinel,$sentinel
278         restore;                and     %fp,$sentinel,$sentinel
279         restore;                and     %fp,$sentinel,$sentinel
280          brz,pn $sentinel,.Lmabort1_$NUM
281         restore
282 #endif
283 ___
284 \f
285 # save tp[$NUM] ########################################################
286 for($i=0; $i<14 && $i<$NUM; $i++) {
287 $code.=<<___;
288         movxtod @A[$i],@R[$i]
289 ___
290 }
291 $code.=<<___;
292 #ifdef  __arch64__
293         restore
294 #else
295          and    %fp,$sentinel,$sentinel
296         restore
297          and    $sentinel,1,%o7
298          and    %fp,$sentinel,$sentinel
299          srl    %fp,0,%fp               ! just in case?
300          or     %o7,$sentinel,$sentinel
301         brz,a,pn $sentinel,.Lmdone_$NUM
302         mov     0,%i0           ! return failure
303 #endif
304 ___
305 for($i=0; $i<12 && $i<$NUM; $i++) {
306 @R[$i] =~ /%f([0-9]+)/;
307 my $lo = "%f".($1+1);
308 $code.=<<___;
309         st      $lo,[$rp+$i*8+0]
310         st      @R[$i],[$rp+$i*8+4]
311 ___
312 }
313 for(; $i<$NUM; $i++) {
314 my ($hi,$lo)=("%f".2*($i%4),"%f".(2*($i%4)+1));
315 $code.=<<___;
316         fsrc2   @R[$i],$hi
317         st      $lo,[$rp+$i*8+0]
318         st      $hi,[$rp+$i*8+4]
319 ___
320 }
321 $code.=<<___;
322         mov     1,%i0           ! return success
323 .Lmdone_$NUM:
324         ret
325         restore
326
327 .Lmabort_$NUM:
328         restore
329         restore
330         restore
331         restore
332         restore
333 .Lmabort1_$NUM:
334         restore
335
336         mov     0,%i0           ! return failure
337         ret
338         restore
339
340 .align  32
341 .Lmsquare_$NUM:
342         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
343         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
344         .word   0x81b02940+$NUM-1       ! montsqr       $NUM-1
345         ba      .Lmresume_$NUM
346         nop
347 .type   bn_mul_mont_t4_$NUM, #function
348 .size   bn_mul_mont_t4_$NUM, .-bn_mul_mont_t4_$NUM
349 ___
350 }
351
352 for ($i=8;$i<=32;$i+=8) {
353         &generate_bn_mul_mont_t4($i);
354 }
355 \f
356 ########################################################################
357 #
358 sub load_fcc() {
359 my ($ptbl,$pwr,$tmp)=@_;
360 $code.=<<___;
361         sethi   %hi(.Lmagic-1f),$tmp
362 1:      call    .+8
363         add     %o7,    $tmp,   %o7
364         inc     %lo(.Lmagic-1b),%o7
365         and     $pwr,   7<<2,   $tmp    ! offset within "magic table"
366         add     $tmp,   %o7,    %o7
367         and     $pwr,   3,      $tmp
368         sll     $tmp,   3,      $tmp    ! offset within first cache line
369         add     $tmp,   $ptbl,  $ptbl   ! of the pwrtbl
370
371         ! "magic table" is organized in such way that below comparisons
372         ! make %fcc3:%fcc2:%fcc1:%fcc0 form a byte of 1s with one 0,
373         ! e.g. 0b11011111, with 0 denoting relevant cache line.
374         ld      [%o7+0],        %f0     ! load column
375         ld      [%o7+32],       %f1
376         ld      [%o7+64],       %f2
377         fcmps   %fcc0,  %f0,    %f1
378         ld      [%o7+96],       %f3
379         fcmps   %fcc1,  %f1,    %f2
380         fcmps   %fcc2,  %f2,    %f3
381         fcmps   %fcc3,  %f3,    %f0
382 ___
383 }
384 sub load_f16() {
385 my $ptbl=shift;
386 $code.=<<___;
387         ldd     [$ptbl+0*32],%f0        ! load all cache lines
388         ldd     [$ptbl+1*32],%f2
389         ldd     [$ptbl+2*32],%f4
390         fmovdg  %fcc0,%f0,%f16          ! pick one value
391         ldd     [$ptbl+3*32],%f6
392         fmovdl  %fcc0,%f2,%f16
393         ldd     [$ptbl+4*32],%f8
394         fmovdg  %fcc1,%f4,%f16
395         ldd     [$ptbl+5*32],%f10
396         fmovdl  %fcc1,%f6,%f16
397         ldd     [$ptbl+6*32],%f12
398         fmovdg  %fcc2,%f8,%f16
399         ldd     [$ptbl+7*32],%f14
400         fmovdl  %fcc2,%f10,%f16
401         fmovdg  %fcc3,%f12,%f16
402         fmovdl  %fcc3,%f14,%f16
403         add     $ptbl,8*32,$ptbl
404 ___
405 }
406 \f
407 ########################################################################
408 # int bn_pwr5_mont_t4_$NUM(u64 *tp,const u64 *np,const BN_ULONG *n0,
409 #                          const u64 *pwrtbl,int pwr);
410 #
411 sub generate_bn_pwr5_mont_t4() {
412 my $NUM=shift;
413 my ($tp,$np,$pwrtbl,$pwr,$sentinel)=map("%g$_",(1..5));
414
415 $code.=<<___;
416 .globl  bn_pwr5_mont_t4_$NUM
417 .align  32
418 bn_pwr5_mont_t4_$NUM:
419 #ifdef  __arch64__
420         mov     0,$sentinel
421         mov     -128,%g4
422 #elif defined(SPARCV9_64BIT_STACK)
423         SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
424         ld      [%g1+0],%g1     ! OPENSSL_sparcv9_P[0]
425         mov     -2047,%g4
426         and     %g1,SPARCV9_64BIT_STACK,%g1
427         movrz   %g1,0,%g4
428         mov     -1,$sentinel
429         add     %g4,-128,%g4
430 #else
431         mov     -1,$sentinel
432         mov     -128,%g4
433 #endif
434         sllx    $sentinel,32,$sentinel
435         save    %sp,%g4,%sp
436 #ifndef __arch64__
437         save    %sp,-128,%sp    ! warm it up
438         save    %sp,-128,%sp
439         save    %sp,-128,%sp
440         save    %sp,-128,%sp
441         save    %sp,-128,%sp
442         save    %sp,-128,%sp
443         restore
444         restore
445         restore
446         restore
447         restore
448         restore
449 #endif
450         and     %sp,1,%g4
451         or      $sentinel,%fp,%fp
452         or      %g4,$sentinel,$sentinel
453
454         ! copy arguments to global registers
455         mov     %i0,$tp
456         mov     %i1,$np
457         ld      [%i2+0],%f1     ! load *n0
458         ld      [%i2+4],%f0
459         mov     %i3,$pwrtbl
460         mov     %i4,$pwr
461         fsrc2   %f0,%f60
462 ___
463 \f
464 # load tp[$NUM] ########################################################
465 $code.=<<___;
466         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
467 ___
468 for($i=0; $i<14 && $i<$NUM; $i++) {
469 $code.=<<___;
470         ldx     [$tp+$i*8],@A[$i]
471 ___
472 }
473 for(; $i<$NUM; $i++) {
474 $code.=<<___;
475         ldd     [$tp+$i*8],@A[$i]
476 ___
477 }
478 # load np[$NUM] ########################################################
479 $code.=<<___;
480         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
481 ___
482 for($i=0; $i<14 && $i<$NUM; $i++) {
483 $code.=<<___;
484         ldx     [$np+$i*8],@N[$i]
485 ___
486 }
487 $code.=<<___;
488         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
489 ___
490 for(; $i<28 && $i<$NUM; $i++) {
491 $code.=<<___;
492         ldx     [$np+$i*8],@N[$i]
493 ___
494 }
495 $code.=<<___;
496         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
497 ___
498 for(; $i<$NUM; $i++) {
499 $code.=<<___;
500         ldx     [$np+$i*8],@N[$i]
501 ___
502 }
503 # load pwrtbl[pwr] ########################################################
504         &load_fcc($pwrtbl,$pwr,@B[0]);
505 for($i=0; $i<6 && $i<$NUM; $i++) {
506         &load_f16($pwrtbl);
507 $code.=<<___;
508         movdtox %f16,@B[$i]
509 ___
510 }
511 $code.=<<___;
512         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
513 ___
514 for(; $i<20 && $i<$NUM; $i++) {
515         &load_f16($pwrtbl);
516 $code.=<<___;
517         movdtox %f16,@B[$i]
518 ___
519 }
520 $code.=<<___;
521         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
522 ___
523 for(; $i<$NUM; $i++) {
524         &load_f16($pwrtbl);
525 $code.=<<___;
526         movdtox %f16,@B[$i]
527 ___
528 }
529 \f
530 # magic ################################################################
531 for($i=0; $i<5; $i++) {
532 $code.=<<___;
533         .word   0x81b02940+$NUM-1       ! montsqr       $NUM-1
534         fbu,pn  %fcc3,.Labort_$NUM
535 #ifndef __arch64__
536         and     %fp,$sentinel,$sentinel
537         brz,pn  $sentinel,.Labort_$NUM
538 #endif
539         nop
540 ___
541 }
542 $code.=<<___;
543         .word   0x81b02920+$NUM-1       ! montmul       $NUM-1
544         fbu,pn  %fcc3,.Labort_$NUM
545 #ifndef __arch64__
546         and     %fp,$sentinel,$sentinel
547         brz,pn  $sentinel,.Labort_$NUM
548 #endif
549         nop
550
551 #ifdef  __arch64__
552         restore
553         restore
554         restore
555         restore
556         restore
557 #else
558         restore;                and     %fp,$sentinel,$sentinel
559         restore;                and     %fp,$sentinel,$sentinel
560         restore;                and     %fp,$sentinel,$sentinel
561         restore;                and     %fp,$sentinel,$sentinel
562          brz,pn $sentinel,.Labort1_$NUM
563         restore
564 #endif
565 ___
566 \f
567 # save tp[$NUM] ########################################################
568 for($i=0; $i<14 && $i<$NUM; $i++) {
569 $code.=<<___;
570         movxtod @A[$i],@R[$i]
571 ___
572 }
573 $code.=<<___;
574 #ifdef  __arch64__
575         restore
576 #else
577          and    %fp,$sentinel,$sentinel
578         restore
579          and    $sentinel,1,%o7
580          and    %fp,$sentinel,$sentinel
581          srl    %fp,0,%fp               ! just in case?
582          or     %o7,$sentinel,$sentinel
583         brz,a,pn $sentinel,.Ldone_$NUM
584         mov     0,%i0           ! return failure
585 #endif
586 ___
587 for($i=0; $i<$NUM; $i++) {
588 $code.=<<___;
589         std     @R[$i],[$tp+$i*8]
590 ___
591 }
592 $code.=<<___;
593         mov     1,%i0           ! return success
594 .Ldone_$NUM:
595         ret
596         restore
597
598 .Labort_$NUM:
599         restore
600         restore
601         restore
602         restore
603         restore
604 .Labort1_$NUM:
605         restore
606
607         mov     0,%i0           ! return failure
608         ret
609         restore
610 .type   bn_pwr5_mont_t4_$NUM, #function
611 .size   bn_pwr5_mont_t4_$NUM, .-bn_pwr5_mont_t4_$NUM
612 ___
613 }
614
615 for ($i=8;$i<=32;$i+=8) {
616         &generate_bn_pwr5_mont_t4($i);
617 }
618 \f
619 {
620 ########################################################################
621 # Fall-back subroutines
622 #
623 # copy of bn_mul_mont_vis3 adjusted for vectors of 64-bit values
624 #
625 ($n0,$m0,$m1,$lo0,$hi0, $lo1,$hi1,$aj,$alo,$nj,$nlo,$tj)=
626         (map("%g$_",(1..5)),map("%o$_",(0..5,7)));
627
628 # int bn_mul_mont(
629 $rp="%o0";      # u64 *rp,
630 $ap="%o1";      # const u64 *ap,
631 $bp="%o2";      # const u64 *bp,
632 $np="%o3";      # const u64 *np,
633 $n0p="%o4";     # const BN_ULONG *n0,
634 $num="%o5";     # int num);     # caller ensures that num is >=3
635 $code.=<<___;
636 .globl  bn_mul_mont_t4
637 .align  32
638 bn_mul_mont_t4:
639         add     %sp,    STACK_BIAS,     %g4     ! real top of stack
640         sll     $num,   3,      $num            ! size in bytes
641         add     $num,   63,     %g1
642         andn    %g1,    63,     %g1             ! buffer size rounded up to 64 bytes
643         sub     %g4,    %g1,    %g1
644         andn    %g1,    63,     %g1             ! align at 64 byte
645         sub     %g1,    STACK_FRAME,    %g1     ! new top of stack
646         sub     %g1,    %g4,    %g1
647
648         save    %sp,    %g1,    %sp
649 ___
650 #       +-------------------------------+<----- %sp
651 #       .                               .
652 #       +-------------------------------+<----- aligned at 64 bytes
653 #       | __int64 tmp[0]                |
654 #       +-------------------------------+
655 #       .                               .
656 #       .                               .
657 #       +-------------------------------+<----- aligned at 64 bytes
658 #       .                               .
659 ($rp,$ap,$bp,$np,$n0p,$num)=map("%i$_",(0..5));
660 ($t0,$t1,$t2,$t3,$cnt,$tp,$bufsz)=map("%l$_",(0..7));
661 ($ovf,$i)=($t0,$t1);
662 $code.=<<___;
663         ld      [$n0p+0],       $t0     ! pull n0[0..1] value
664         ld      [$n0p+4],       $t1
665         add     %sp, STACK_BIAS+STACK_FRAME, $tp
666         ldx     [$bp+0],        $m0     ! m0=bp[0]
667         sllx    $t1,    32,     $n0
668         add     $bp,    8,      $bp
669         or      $t0,    $n0,    $n0
670 \f
671         ldx     [$ap+0],        $aj     ! ap[0]
672
673         mulx    $aj,    $m0,    $lo0    ! ap[0]*bp[0]
674         umulxhi $aj,    $m0,    $hi0
675
676         ldx     [$ap+8],        $aj     ! ap[1]
677         add     $ap,    16,     $ap
678         ldx     [$np+0],        $nj     ! np[0]
679
680         mulx    $lo0,   $n0,    $m1     ! "tp[0]"*n0
681
682         mulx    $aj,    $m0,    $alo    ! ap[1]*bp[0]
683         umulxhi $aj,    $m0,    $aj     ! ahi=aj
684
685         mulx    $nj,    $m1,    $lo1    ! np[0]*m1
686         umulxhi $nj,    $m1,    $hi1
687
688         ldx     [$np+8],        $nj     ! np[1]
689
690         addcc   $lo0,   $lo1,   $lo1
691         add     $np,    16,     $np
692         addxc   %g0,    $hi1,   $hi1
693
694         mulx    $nj,    $m1,    $nlo    ! np[1]*m1
695         umulxhi $nj,    $m1,    $nj     ! nhi=nj
696 \f
697         ba      .L1st
698         sub     $num,   24,     $cnt    ! cnt=num-3
699
700 .align  16
701 .L1st:
702         addcc   $alo,   $hi0,   $lo0
703         addxc   $aj,    %g0,    $hi0
704
705         ldx     [$ap+0],        $aj     ! ap[j]
706         addcc   $nlo,   $hi1,   $lo1
707         add     $ap,    8,      $ap
708         addxc   $nj,    %g0,    $hi1    ! nhi=nj
709
710         ldx     [$np+0],        $nj     ! np[j]
711         mulx    $aj,    $m0,    $alo    ! ap[j]*bp[0]
712         add     $np,    8,      $np
713         umulxhi $aj,    $m0,    $aj     ! ahi=aj
714
715         mulx    $nj,    $m1,    $nlo    ! np[j]*m1
716         addcc   $lo0,   $lo1,   $lo1    ! np[j]*m1+ap[j]*bp[0]
717         umulxhi $nj,    $m1,    $nj     ! nhi=nj
718         addxc   %g0,    $hi1,   $hi1
719         stxa    $lo1,   [$tp]0xe2       ! tp[j-1]
720         add     $tp,    8,      $tp     ! tp++
721
722         brnz,pt $cnt,   .L1st
723         sub     $cnt,   8,      $cnt    ! j--
724 !.L1st
725         addcc   $alo,   $hi0,   $lo0
726         addxc   $aj,    %g0,    $hi0    ! ahi=aj
727
728         addcc   $nlo,   $hi1,   $lo1
729         addxc   $nj,    %g0,    $hi1
730         addcc   $lo0,   $lo1,   $lo1    ! np[j]*m1+ap[j]*bp[0]
731         addxc   %g0,    $hi1,   $hi1
732         stxa    $lo1,   [$tp]0xe2       ! tp[j-1]
733         add     $tp,    8,      $tp
734
735         addcc   $hi0,   $hi1,   $hi1
736         addxc   %g0,    %g0,    $ovf    ! upmost overflow bit
737         stxa    $hi1,   [$tp]0xe2
738         add     $tp,    8,      $tp
739 \f
740         ba      .Louter
741         sub     $num,   16,     $i      ! i=num-2
742
743 .align  16
744 .Louter:
745         ldx     [$bp+0],        $m0     ! m0=bp[i]
746         add     $bp,    8,      $bp
747
748         sub     $ap,    $num,   $ap     ! rewind
749         sub     $np,    $num,   $np
750         sub     $tp,    $num,   $tp
751
752         ldx     [$ap+0],        $aj     ! ap[0]
753         ldx     [$np+0],        $nj     ! np[0]
754
755         mulx    $aj,    $m0,    $lo0    ! ap[0]*bp[i]
756         ldx     [$tp],          $tj     ! tp[0]
757         umulxhi $aj,    $m0,    $hi0
758         ldx     [$ap+8],        $aj     ! ap[1]
759         addcc   $lo0,   $tj,    $lo0    ! ap[0]*bp[i]+tp[0]
760         mulx    $aj,    $m0,    $alo    ! ap[1]*bp[i]
761         addxc   %g0,    $hi0,   $hi0
762         mulx    $lo0,   $n0,    $m1     ! tp[0]*n0
763         umulxhi $aj,    $m0,    $aj     ! ahi=aj
764         mulx    $nj,    $m1,    $lo1    ! np[0]*m1
765         add     $ap,    16,     $ap
766         umulxhi $nj,    $m1,    $hi1
767         ldx     [$np+8],        $nj     ! np[1]
768         add     $np,    16,     $np
769         addcc   $lo1,   $lo0,   $lo1
770         mulx    $nj,    $m1,    $nlo    ! np[1]*m1
771         addxc   %g0,    $hi1,   $hi1
772         umulxhi $nj,    $m1,    $nj     ! nhi=nj
773 \f
774         ba      .Linner
775         sub     $num,   24,     $cnt    ! cnt=num-3
776 .align  16
777 .Linner:
778         addcc   $alo,   $hi0,   $lo0
779         ldx     [$tp+8],        $tj     ! tp[j]
780         addxc   $aj,    %g0,    $hi0    ! ahi=aj
781         ldx     [$ap+0],        $aj     ! ap[j]
782         add     $ap,    8,      $ap
783         addcc   $nlo,   $hi1,   $lo1
784         mulx    $aj,    $m0,    $alo    ! ap[j]*bp[i]
785         addxc   $nj,    %g0,    $hi1    ! nhi=nj
786         ldx     [$np+0],        $nj     ! np[j]
787         add     $np,    8,      $np
788         umulxhi $aj,    $m0,    $aj     ! ahi=aj
789         addcc   $lo0,   $tj,    $lo0    ! ap[j]*bp[i]+tp[j]
790         mulx    $nj,    $m1,    $nlo    ! np[j]*m1
791         addxc   %g0,    $hi0,   $hi0
792         umulxhi $nj,    $m1,    $nj     ! nhi=nj
793         addcc   $lo1,   $lo0,   $lo1    ! np[j]*m1+ap[j]*bp[i]+tp[j]
794         addxc   %g0,    $hi1,   $hi1
795         stx     $lo1,   [$tp]           ! tp[j-1]
796         add     $tp,    8,      $tp
797         brnz,pt $cnt,   .Linner
798         sub     $cnt,   8,      $cnt
799 !.Linner
800         ldx     [$tp+8],        $tj     ! tp[j]
801         addcc   $alo,   $hi0,   $lo0
802         addxc   $aj,    %g0,    $hi0    ! ahi=aj
803         addcc   $lo0,   $tj,    $lo0    ! ap[j]*bp[i]+tp[j]
804         addxc   %g0,    $hi0,   $hi0
805
806         addcc   $nlo,   $hi1,   $lo1
807         addxc   $nj,    %g0,    $hi1    ! nhi=nj
808         addcc   $lo1,   $lo0,   $lo1    ! np[j]*m1+ap[j]*bp[i]+tp[j]
809         addxc   %g0,    $hi1,   $hi1
810         stx     $lo1,   [$tp]           ! tp[j-1]
811
812         subcc   %g0,    $ovf,   %g0     ! move upmost overflow to CCR.xcc
813         addxccc $hi1,   $hi0,   $hi1
814         addxc   %g0,    %g0,    $ovf
815         stx     $hi1,   [$tp+8]
816         add     $tp,    16,     $tp
817
818         brnz,pt $i,     .Louter
819         sub     $i,     8,      $i
820 \f
821         sub     $ap,    $num,   $ap     ! rewind
822         sub     $np,    $num,   $np
823         sub     $tp,    $num,   $tp
824         ba      .Lsub
825         subcc   $num,   8,      $cnt    ! cnt=num-1 and clear CCR.xcc
826
827 .align  16
828 .Lsub:
829         ldx     [$tp],          $tj
830         add     $tp,    8,      $tp
831         ldx     [$np+0],        $nj
832         add     $np,    8,      $np
833         subccc  $tj,    $nj,    $t2     ! tp[j]-np[j]
834         srlx    $tj,    32,     $tj
835         srlx    $nj,    32,     $nj
836         subccc  $tj,    $nj,    $t3
837         add     $rp,    8,      $rp
838         st      $t2,    [$rp-4]         ! reverse order
839         st      $t3,    [$rp-8]
840         brnz,pt $cnt,   .Lsub
841         sub     $cnt,   8,      $cnt
842
843         sub     $np,    $num,   $np     ! rewind
844         sub     $tp,    $num,   $tp
845         sub     $rp,    $num,   $rp
846
847         subc    $ovf,   %g0,    $ovf    ! handle upmost overflow bit
848         and     $tp,    $ovf,   $ap
849         andn    $rp,    $ovf,   $np
850         or      $np,    $ap,    $ap     ! ap=borrow?tp:rp
851         ba      .Lcopy
852         sub     $num,   8,      $cnt
853
854 .align  16
855 .Lcopy:                                 ! copy or in-place refresh
856         ldx     [$ap+0],        $t2
857         add     $ap,    8,      $ap
858         stx     %g0,    [$tp]           ! zap
859         add     $tp,    8,      $tp
860         stx     $t2,    [$rp+0]
861         add     $rp,    8,      $rp
862         brnz    $cnt,   .Lcopy
863         sub     $cnt,   8,      $cnt
864
865         mov     1,      %o0
866         ret
867         restore
868 .type   bn_mul_mont_t4, #function
869 .size   bn_mul_mont_t4, .-bn_mul_mont_t4
870 ___
871 \f
872 # int bn_mul_mont_gather5(
873 $rp="%o0";      # u64 *rp,
874 $ap="%o1";      # const u64 *ap,
875 $bp="%o2";      # const u64 *pwrtbl,
876 $np="%o3";      # const u64 *np,
877 $n0p="%o4";     # const BN_ULONG *n0,
878 $num="%o5";     # int num,      # caller ensures that num is >=3
879                 # int power);
880 $code.=<<___;
881 .globl  bn_mul_mont_gather5_t4
882 .align  32
883 bn_mul_mont_gather5_t4:
884         add     %sp,    STACK_BIAS,     %g4     ! real top of stack
885         sll     $num,   3,      $num            ! size in bytes
886         add     $num,   63,     %g1
887         andn    %g1,    63,     %g1             ! buffer size rounded up to 64 bytes
888         sub     %g4,    %g1,    %g1
889         andn    %g1,    63,     %g1             ! align at 64 byte
890         sub     %g1,    STACK_FRAME,    %g1     ! new top of stack
891         sub     %g1,    %g4,    %g1
892         LDPTR   [%sp+STACK_7thARG],     %g4     ! load power, 7th argument
893
894         save    %sp,    %g1,    %sp
895 ___
896 #       +-------------------------------+<----- %sp
897 #       .                               .
898 #       +-------------------------------+<----- aligned at 64 bytes
899 #       | __int64 tmp[0]                |
900 #       +-------------------------------+
901 #       .                               .
902 #       .                               .
903 #       +-------------------------------+<----- aligned at 64 bytes
904 #       .                               .
905 ($rp,$ap,$bp,$np,$n0p,$num)=map("%i$_",(0..5));
906 ($t0,$t1,$t2,$t3,$cnt,$tp,$bufsz)=map("%l$_",(0..7));
907 ($ovf,$i)=($t0,$t1);
908         &load_fcc($bp,"%g4","%g1");
909         &load_f16($bp);
910 $code.=<<___;
911         movdtox %f16,   $m0             ! m0=bp[0]
912
913         ld      [$n0p+0],       $t0     ! pull n0[0..1] value
914         ld      [$n0p+4],       $t1
915         add     %sp, STACK_BIAS+STACK_FRAME, $tp
916         sllx    $t1,    32,     $n0
917         or      $t0,    $n0,    $n0
918 \f
919         ldx     [$ap+0],        $aj     ! ap[0]
920
921         mulx    $aj,    $m0,    $lo0    ! ap[0]*bp[0]
922         umulxhi $aj,    $m0,    $hi0
923
924         ldx     [$ap+8],        $aj     ! ap[1]
925         add     $ap,    16,     $ap
926         ldx     [$np+0],        $nj     ! np[0]
927
928         mulx    $lo0,   $n0,    $m1     ! "tp[0]"*n0
929
930         mulx    $aj,    $m0,    $alo    ! ap[1]*bp[0]
931         umulxhi $aj,    $m0,    $aj     ! ahi=aj
932
933         mulx    $nj,    $m1,    $lo1    ! np[0]*m1
934         umulxhi $nj,    $m1,    $hi1
935
936         ldx     [$np+8],        $nj     ! np[1]
937
938         addcc   $lo0,   $lo1,   $lo1
939         add     $np,    16,     $np
940         addxc   %g0,    $hi1,   $hi1
941
942         mulx    $nj,    $m1,    $nlo    ! np[1]*m1
943         umulxhi $nj,    $m1,    $nj     ! nhi=nj
944 \f
945         ba      .L1st_g5
946         sub     $num,   24,     $cnt    ! cnt=num-3
947
948 .align  16
949 .L1st_g5:
950         addcc   $alo,   $hi0,   $lo0
951         addxc   $aj,    %g0,    $hi0
952
953         ldx     [$ap+0],        $aj     ! ap[j]
954         addcc   $nlo,   $hi1,   $lo1
955         add     $ap,    8,      $ap
956         addxc   $nj,    %g0,    $hi1    ! nhi=nj
957
958         ldx     [$np+0],        $nj     ! np[j]
959         mulx    $aj,    $m0,    $alo    ! ap[j]*bp[0]
960         add     $np,    8,      $np
961         umulxhi $aj,    $m0,    $aj     ! ahi=aj
962
963         mulx    $nj,    $m1,    $nlo    ! np[j]*m1
964         addcc   $lo0,   $lo1,   $lo1    ! np[j]*m1+ap[j]*bp[0]
965         umulxhi $nj,    $m1,    $nj     ! nhi=nj
966         addxc   %g0,    $hi1,   $hi1
967         stxa    $lo1,   [$tp]0xe2       ! tp[j-1]
968         add     $tp,    8,      $tp     ! tp++
969
970         brnz,pt $cnt,   .L1st_g5
971         sub     $cnt,   8,      $cnt    ! j--
972 !.L1st_g5
973         addcc   $alo,   $hi0,   $lo0
974         addxc   $aj,    %g0,    $hi0    ! ahi=aj
975
976         addcc   $nlo,   $hi1,   $lo1
977         addxc   $nj,    %g0,    $hi1
978         addcc   $lo0,   $lo1,   $lo1    ! np[j]*m1+ap[j]*bp[0]
979         addxc   %g0,    $hi1,   $hi1
980         stxa    $lo1,   [$tp]0xe2       ! tp[j-1]
981         add     $tp,    8,      $tp
982
983         addcc   $hi0,   $hi1,   $hi1
984         addxc   %g0,    %g0,    $ovf    ! upmost overflow bit
985         stxa    $hi1,   [$tp]0xe2
986         add     $tp,    8,      $tp
987 \f
988         ba      .Louter_g5
989         sub     $num,   16,     $i      ! i=num-2
990
991 .align  16
992 .Louter_g5:
993 ___
994         &load_f16($bp);
995 $code.=<<___;
996         movdtox %f16,   $m0             ! m0=bp[i]
997
998         sub     $ap,    $num,   $ap     ! rewind
999         sub     $np,    $num,   $np
1000         sub     $tp,    $num,   $tp
1001
1002         ldx     [$ap+0],        $aj     ! ap[0]
1003         ldx     [$np+0],        $nj     ! np[0]
1004
1005         mulx    $aj,    $m0,    $lo0    ! ap[0]*bp[i]
1006         ldx     [$tp],          $tj     ! tp[0]
1007         umulxhi $aj,    $m0,    $hi0
1008         ldx     [$ap+8],        $aj     ! ap[1]
1009         addcc   $lo0,   $tj,    $lo0    ! ap[0]*bp[i]+tp[0]
1010         mulx    $aj,    $m0,    $alo    ! ap[1]*bp[i]
1011         addxc   %g0,    $hi0,   $hi0
1012         mulx    $lo0,   $n0,    $m1     ! tp[0]*n0
1013         umulxhi $aj,    $m0,    $aj     ! ahi=aj
1014         mulx    $nj,    $m1,    $lo1    ! np[0]*m1
1015         add     $ap,    16,     $ap
1016         umulxhi $nj,    $m1,    $hi1
1017         ldx     [$np+8],        $nj     ! np[1]
1018         add     $np,    16,     $np
1019         addcc   $lo1,   $lo0,   $lo1
1020         mulx    $nj,    $m1,    $nlo    ! np[1]*m1
1021         addxc   %g0,    $hi1,   $hi1
1022         umulxhi $nj,    $m1,    $nj     ! nhi=nj
1023 \f
1024         ba      .Linner_g5
1025         sub     $num,   24,     $cnt    ! cnt=num-3
1026 .align  16
1027 .Linner_g5:
1028         addcc   $alo,   $hi0,   $lo0
1029         ldx     [$tp+8],        $tj     ! tp[j]
1030         addxc   $aj,    %g0,    $hi0    ! ahi=aj
1031         ldx     [$ap+0],        $aj     ! ap[j]
1032         add     $ap,    8,      $ap
1033         addcc   $nlo,   $hi1,   $lo1
1034         mulx    $aj,    $m0,    $alo    ! ap[j]*bp[i]
1035         addxc   $nj,    %g0,    $hi1    ! nhi=nj
1036         ldx     [$np+0],        $nj     ! np[j]
1037         add     $np,    8,      $np
1038         umulxhi $aj,    $m0,    $aj     ! ahi=aj
1039         addcc   $lo0,   $tj,    $lo0    ! ap[j]*bp[i]+tp[j]
1040         mulx    $nj,    $m1,    $nlo    ! np[j]*m1
1041         addxc   %g0,    $hi0,   $hi0
1042         umulxhi $nj,    $m1,    $nj     ! nhi=nj
1043         addcc   $lo1,   $lo0,   $lo1    ! np[j]*m1+ap[j]*bp[i]+tp[j]
1044         addxc   %g0,    $hi1,   $hi1
1045         stx     $lo1,   [$tp]           ! tp[j-1]
1046         add     $tp,    8,      $tp
1047         brnz,pt $cnt,   .Linner_g5
1048         sub     $cnt,   8,      $cnt
1049 !.Linner_g5
1050         ldx     [$tp+8],        $tj     ! tp[j]
1051         addcc   $alo,   $hi0,   $lo0
1052         addxc   $aj,    %g0,    $hi0    ! ahi=aj
1053         addcc   $lo0,   $tj,    $lo0    ! ap[j]*bp[i]+tp[j]
1054         addxc   %g0,    $hi0,   $hi0
1055
1056         addcc   $nlo,   $hi1,   $lo1
1057         addxc   $nj,    %g0,    $hi1    ! nhi=nj
1058         addcc   $lo1,   $lo0,   $lo1    ! np[j]*m1+ap[j]*bp[i]+tp[j]
1059         addxc   %g0,    $hi1,   $hi1
1060         stx     $lo1,   [$tp]           ! tp[j-1]
1061
1062         subcc   %g0,    $ovf,   %g0     ! move upmost overflow to CCR.xcc
1063         addxccc $hi1,   $hi0,   $hi1
1064         addxc   %g0,    %g0,    $ovf
1065         stx     $hi1,   [$tp+8]
1066         add     $tp,    16,     $tp
1067
1068         brnz,pt $i,     .Louter_g5
1069         sub     $i,     8,      $i
1070 \f
1071         sub     $ap,    $num,   $ap     ! rewind
1072         sub     $np,    $num,   $np
1073         sub     $tp,    $num,   $tp
1074         ba      .Lsub_g5
1075         subcc   $num,   8,      $cnt    ! cnt=num-1 and clear CCR.xcc
1076
1077 .align  16
1078 .Lsub_g5:
1079         ldx     [$tp],          $tj
1080         add     $tp,    8,      $tp
1081         ldx     [$np+0],        $nj
1082         add     $np,    8,      $np
1083         subccc  $tj,    $nj,    $t2     ! tp[j]-np[j]
1084         srlx    $tj,    32,     $tj
1085         srlx    $nj,    32,     $nj
1086         subccc  $tj,    $nj,    $t3
1087         add     $rp,    8,      $rp
1088         st      $t2,    [$rp-4]         ! reverse order
1089         st      $t3,    [$rp-8]
1090         brnz,pt $cnt,   .Lsub_g5
1091         sub     $cnt,   8,      $cnt
1092
1093         sub     $np,    $num,   $np     ! rewind
1094         sub     $tp,    $num,   $tp
1095         sub     $rp,    $num,   $rp
1096
1097         subc    $ovf,   %g0,    $ovf    ! handle upmost overflow bit
1098         and     $tp,    $ovf,   $ap
1099         andn    $rp,    $ovf,   $np
1100         or      $np,    $ap,    $ap     ! ap=borrow?tp:rp
1101         ba      .Lcopy_g5
1102         sub     $num,   8,      $cnt
1103
1104 .align  16
1105 .Lcopy_g5:                              ! copy or in-place refresh
1106         ldx     [$ap+0],        $t2
1107         add     $ap,    8,      $ap
1108         stx     %g0,    [$tp]           ! zap
1109         add     $tp,    8,      $tp
1110         stx     $t2,    [$rp+0]
1111         add     $rp,    8,      $rp
1112         brnz    $cnt,   .Lcopy_g5
1113         sub     $cnt,   8,      $cnt
1114
1115         mov     1,      %o0
1116         ret
1117         restore
1118 .type   bn_mul_mont_gather5_t4, #function
1119 .size   bn_mul_mont_gather5_t4, .-bn_mul_mont_gather5_t4
1120 ___
1121 }
1122 \f
1123 $code.=<<___;
1124 .globl  bn_flip_t4
1125 .align  32
1126 bn_flip_t4:
1127 .Loop_flip:
1128         ld      [%o1+0],        %o4
1129         sub     %o2,    1,      %o2
1130         ld      [%o1+4],        %o5
1131         add     %o1,    8,      %o1
1132         st      %o5,    [%o0+0]
1133         st      %o4,    [%o0+4]
1134         brnz    %o2,    .Loop_flip
1135         add     %o0,    8,      %o0
1136         retl
1137         nop
1138 .type   bn_flip_t4, #function
1139 .size   bn_flip_t4, .-bn_flip_t4
1140
1141 .globl  bn_scatter5_t4
1142 .align  32
1143 bn_scatter5_t4:
1144         sll     %o3,    3,      %o3
1145         sub     %o1,    1,      %o1
1146         add     %o3,    %o2,    %o2     ! &pwrtbl[pwr]
1147         nop
1148 .Loop_scatter5:
1149         ldx     [%o0],  %g1             ! inp[i]
1150         add     %o0,    8,      %o0
1151         stx     %g1,    [%o2]
1152         add     %o2,    32*8,   %o2
1153         brnz    %o1,    .Loop_scatter5
1154         sub     %o1,    1,      %o1
1155         retl
1156         nop
1157 .type   bn_scatter5_t4, #function
1158 .size   bn_scatter5_t4, .-bn_scatter5_t4
1159
1160 .globl  bn_gather5_t4
1161 .align  32
1162 bn_gather5_t4:
1163         mov     %o7,    %o5
1164 ___
1165         &load_fcc("%o2","%o3","%o4");
1166 $code.=<<___;
1167         mov     %o5,    %o7
1168         sub     %o1,    1,      %o1
1169 .Loop_gather5:
1170 ___
1171         &load_f16("%o2");
1172 $code.=<<___;
1173         std     %f16,   [%o0]
1174         add     %o0,    8,      %o0
1175         brnz    %o1,    .Loop_gather5
1176         sub     %o1,    1,      %o1
1177
1178         retl
1179         nop
1180 .type   bn_gather5_t4, #function
1181 .size   bn_gather5_t4, .-bn_gather5_t4
1182 ___
1183 \f
1184 $code.=<<___;
1185 #define ONE     0x3f800000
1186 #define NUL     0x00000000
1187 #define NaN     0xffffffff
1188
1189 .align  64
1190 .Lmagic:
1191         .long   ONE,NUL,NaN,NaN,NaN,NaN,NUL,ONE
1192         .long   NUL,ONE,ONE,NUL,NaN,NaN,NaN,NaN
1193         .long   NaN,NaN,NUL,ONE,ONE,NUL,NaN,NaN
1194         .long   NaN,NaN,NaN,NaN,NUL,ONE,ONE,NUL
1195 .asciz  "Montgomery Multiplication for SPARC T4, David S. Miller, Andy Polyakov"
1196 .align  4
1197 ___
1198
1199 &emit_assembler();
1200
1201 close STDOUT;