Unified - adapt the generation of bignum assembler to use GENERATE
[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.000628s 0.000028s   1592.4  35434.4
33 # rsa 2048 bits 0.003282s 0.000106s    304.7   9438.3
34 # rsa 4096 bits 0.025866s 0.000340s     38.7   2940.9
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.000256s 0.000016s   3904.4  61411.9
41 # rsa 2048 bits 0.000946s 0.000029s   1056.8  34292.7
42 # rsa 4096 bits 0.005061s 0.000340s    197.6   2940.5
43 # dsa 1024 bits 0.000176s 0.000195s   5674.7   5130.5
44 # dsa 2048 bits 0.000296s 0.000354s   3383.2   2827.6
45 #
46 ######################################################################
47 # 32-bit process, VIS3:
48 #                   sign    verify    sign/s verify/s
49 # rsa 1024 bits 0.000665s 0.000028s   1504.8  35233.3
50 # rsa 2048 bits 0.003349s 0.000106s    298.6   9433.4
51 # rsa 4096 bits 0.025959s 0.000341s     38.5   2934.8
52 # dsa 1024 bits 0.000320s 0.000341s   3123.3   2929.6
53 # dsa 2048 bits 0.001101s 0.001260s    908.2    793.4
54 #
55 # 32-bit process, this module:
56 #                   sign    verify    sign/s verify/s
57 # rsa 1024 bits 0.000301s 0.000017s   3317.1  60240.0
58 # rsa 2048 bits 0.001034s 0.000030s    966.9  33812.7
59 # rsa 4096 bits 0.005244s 0.000341s    190.7   2935.4
60 # dsa 1024 bits 0.000201s 0.000205s   4976.1   4879.2
61 # dsa 2048 bits 0.000328s 0.000360s   3051.1   2774.2
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/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=517ffce4e1a03aea979fe3a18a3dd1761a24fafb
73 # for details.
74
75 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
76 push(@INC,"${dir}","${dir}../../perlasm");
77 require "sparcv9_modes.pl";
78
79 $output = pop;
80 open STDOUT,">$output";
81
82 $code.=<<___;
83 #include "sparc_arch.h"
84
85 #ifdef  __arch64__
86 .register       %g2,#scratch
87 .register       %g3,#scratch
88 #endif
89
90 .section        ".text",#alloc,#execinstr
91
92 #ifdef  __PIC__
93 SPARC_PIC_THUNK(%g1)
94 #endif
95 ___
96
97 ########################################################################
98 # Register layout for mont[mul|sqr] instructions.
99 # For details see "Oracle SPARC Architecture 2011" manual at
100 # http://www.oracle.com/technetwork/server-storage/sun-sparc-enterprise/documentation/.
101 #
102 my @R=map("%f".2*$_,(0..11,30,31,12..29));
103 my @N=(map("%l$_",(0..7)),map("%o$_",(0..5))); @N=(@N,@N,@N[0..3]);
104 my @A=(@N[0..13],@R[14..31]);
105 my @B=(map("%i$_",(0..5)),map("%l$_",(0..7))); @B=(@B,@B,map("%o$_",(0..3)));
106 \f
107 ########################################################################
108 # int bn_mul_mont_t4_$NUM(u64 *rp,const u64 *ap,const u64 *bp,
109 #                         const u64 *np,const BN_ULONG *n0);
110 #
111 sub generate_bn_mul_mont_t4() {
112 my $NUM=shift;
113 my ($rp,$ap,$bp,$np,$sentinel)=map("%g$_",(1..5));
114
115 $code.=<<___;
116 .globl  bn_mul_mont_t4_$NUM
117 .align  32
118 bn_mul_mont_t4_$NUM:
119 #ifdef  __arch64__
120         mov     0,$sentinel
121         mov     -128,%g4
122 #elif defined(SPARCV9_64BIT_STACK)
123         SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
124         ld      [%g1+0],%g1     ! OPENSSL_sparcv9_P[0]
125         mov     -2047,%g4
126         and     %g1,SPARCV9_64BIT_STACK,%g1
127         movrz   %g1,0,%g4
128         mov     -1,$sentinel
129         add     %g4,-128,%g4
130 #else
131         mov     -1,$sentinel
132         mov     -128,%g4
133 #endif
134         sllx    $sentinel,32,$sentinel
135         save    %sp,%g4,%sp
136 #ifndef __arch64__
137         save    %sp,-128,%sp    ! warm it up
138         save    %sp,-128,%sp
139         save    %sp,-128,%sp
140         save    %sp,-128,%sp
141         save    %sp,-128,%sp
142         save    %sp,-128,%sp
143         restore
144         restore
145         restore
146         restore
147         restore
148         restore
149 #endif
150         and     %sp,1,%g4
151         or      $sentinel,%fp,%fp
152         or      %g4,$sentinel,$sentinel
153
154         ! copy arguments to global registers
155         mov     %i0,$rp
156         mov     %i1,$ap
157         mov     %i2,$bp
158         mov     %i3,$np
159         ld      [%i4+0],%f1     ! load *n0
160         ld      [%i4+4],%f0
161         fsrc2   %f0,%f60
162 ___
163 \f
164 # load ap[$NUM] ########################################################
165 $code.=<<___;
166         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
167 ___
168 for($i=0; $i<14 && $i<$NUM; $i++) {
169 my $lo=$i<13?@A[$i+1]:"%o7";
170 $code.=<<___;
171         ld      [$ap+$i*8+0],$lo
172         ld      [$ap+$i*8+4],@A[$i]
173         sllx    @A[$i],32,@A[$i]
174         or      $lo,@A[$i],@A[$i]
175 ___
176 }
177 for(; $i<$NUM; $i++) {
178 my ($hi,$lo)=("%f".2*($i%4),"%f".(2*($i%4)+1));
179 $code.=<<___;
180         ld      [$ap+$i*8+0],$lo
181         ld      [$ap+$i*8+4],$hi
182         fsrc2   $hi,@A[$i]
183 ___
184 }
185 # load np[$NUM] ########################################################
186 $code.=<<___;
187         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
188 ___
189 for($i=0; $i<14 && $i<$NUM; $i++) {
190 my $lo=$i<13?@N[$i+1]:"%o7";
191 $code.=<<___;
192         ld      [$np+$i*8+0],$lo
193         ld      [$np+$i*8+4],@N[$i]
194         sllx    @N[$i],32,@N[$i]
195         or      $lo,@N[$i],@N[$i]
196 ___
197 }
198 $code.=<<___;
199         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
200 ___
201 for(; $i<28 && $i<$NUM; $i++) {
202 my $lo=$i<27?@N[$i+1]:"%o7";
203 $code.=<<___;
204         ld      [$np+$i*8+0],$lo
205         ld      [$np+$i*8+4],@N[$i]
206         sllx    @N[$i],32,@N[$i]
207         or      $lo,@N[$i],@N[$i]
208 ___
209 }
210 $code.=<<___;
211         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
212 ___
213 for(; $i<$NUM; $i++) {
214 my $lo=($i<$NUM-1)?@N[$i+1]:"%o7";
215 $code.=<<___;
216         ld      [$np+$i*8+0],$lo
217         ld      [$np+$i*8+4],@N[$i]
218         sllx    @N[$i],32,@N[$i]
219         or      $lo,@N[$i],@N[$i]
220 ___
221 }
222 $code.=<<___;
223         cmp     $ap,$bp
224         be      SIZE_T_CC,.Lmsquare_$NUM
225         nop
226 ___
227 \f
228 # load bp[$NUM] ########################################################
229 $code.=<<___;
230         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
231 ___
232 for($i=0; $i<14 && $i<$NUM; $i++) {
233 my $lo=$i<13?@B[$i+1]:"%o7";
234 $code.=<<___;
235         ld      [$bp+$i*8+0],$lo
236         ld      [$bp+$i*8+4],@B[$i]
237         sllx    @B[$i],32,@B[$i]
238         or      $lo,@B[$i],@B[$i]
239 ___
240 }
241 $code.=<<___;
242         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
243 ___
244 for(; $i<$NUM; $i++) {
245 my $lo=($i<$NUM-1)?@B[$i+1]:"%o7";
246 $code.=<<___;
247         ld      [$bp+$i*8+0],$lo
248         ld      [$bp+$i*8+4],@B[$i]
249         sllx    @B[$i],32,@B[$i]
250         or      $lo,@B[$i],@B[$i]
251 ___
252 }
253 # magic ################################################################
254 $code.=<<___;
255         .word   0x81b02920+$NUM-1       ! montmul       $NUM-1
256 .Lmresume_$NUM:
257         fbu,pn  %fcc3,.Lmabort_$NUM
258 #ifndef __arch64__
259         and     %fp,$sentinel,$sentinel
260         brz,pn  $sentinel,.Lmabort_$NUM
261 #endif
262         nop
263 #ifdef  __arch64__
264         restore
265         restore
266         restore
267         restore
268         restore
269 #else
270         restore;                and     %fp,$sentinel,$sentinel
271         restore;                and     %fp,$sentinel,$sentinel
272         restore;                and     %fp,$sentinel,$sentinel
273         restore;                and     %fp,$sentinel,$sentinel
274          brz,pn $sentinel,.Lmabort1_$NUM
275         restore
276 #endif
277 ___
278 \f
279 # save tp[$NUM] ########################################################
280 for($i=0; $i<14 && $i<$NUM; $i++) {
281 $code.=<<___;
282         movxtod @A[$i],@R[$i]
283 ___
284 }
285 $code.=<<___;
286 #ifdef  __arch64__
287         restore
288 #else
289          and    %fp,$sentinel,$sentinel
290         restore
291          and    $sentinel,1,%o7
292          and    %fp,$sentinel,$sentinel
293          srl    %fp,0,%fp               ! just in case?
294          or     %o7,$sentinel,$sentinel
295         brz,a,pn $sentinel,.Lmdone_$NUM
296         mov     0,%i0           ! return failure
297 #endif
298 ___
299 for($i=0; $i<12 && $i<$NUM; $i++) {
300 @R[$i] =~ /%f([0-9]+)/;
301 my $lo = "%f".($1+1);
302 $code.=<<___;
303         st      $lo,[$rp+$i*8+0]
304         st      @R[$i],[$rp+$i*8+4]
305 ___
306 }
307 for(; $i<$NUM; $i++) {
308 my ($hi,$lo)=("%f".2*($i%4),"%f".(2*($i%4)+1));
309 $code.=<<___;
310         fsrc2   @R[$i],$hi
311         st      $lo,[$rp+$i*8+0]
312         st      $hi,[$rp+$i*8+4]
313 ___
314 }
315 $code.=<<___;
316         mov     1,%i0           ! return success
317 .Lmdone_$NUM:
318         ret
319         restore
320
321 .Lmabort_$NUM:
322         restore
323         restore
324         restore
325         restore
326         restore
327 .Lmabort1_$NUM:
328         restore
329
330         mov     0,%i0           ! return failure
331         ret
332         restore
333
334 .align  32
335 .Lmsquare_$NUM:
336         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
337         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
338         .word   0x81b02940+$NUM-1       ! montsqr       $NUM-1
339         ba      .Lmresume_$NUM
340         nop
341 .type   bn_mul_mont_t4_$NUM, #function
342 .size   bn_mul_mont_t4_$NUM, .-bn_mul_mont_t4_$NUM
343 ___
344 }
345
346 for ($i=8;$i<=32;$i+=8) {
347         &generate_bn_mul_mont_t4($i);
348 }
349 \f
350 ########################################################################
351 #
352 sub load_ccr {
353 my ($ptbl,$pwr,$ccr,$skip_wr)=@_;
354 $code.=<<___;
355         srl     $pwr,   2,      %o4
356         and     $pwr,   3,      %o5
357         and     %o4,    7,      %o4
358         sll     %o5,    3,      %o5     ! offset within first cache line
359         add     %o5,    $ptbl,  $ptbl   ! of the pwrtbl
360         or      %g0,    1,      %o5
361         sll     %o5,    %o4,    $ccr
362 ___
363 $code.=<<___    if (!$skip_wr);
364         wr      $ccr,   %g0,    %ccr
365 ___
366 }
367 sub load_b_pair {
368 my ($pwrtbl,$B0,$B1)=@_;
369
370 $code.=<<___;
371         ldx     [$pwrtbl+0*32], $B0
372         ldx     [$pwrtbl+8*32], $B1
373         ldx     [$pwrtbl+1*32], %o4
374         ldx     [$pwrtbl+9*32], %o5
375         movvs   %icc,   %o4,    $B0
376         ldx     [$pwrtbl+2*32], %o4
377         movvs   %icc,   %o5,    $B1
378         ldx     [$pwrtbl+10*32],%o5
379         move    %icc,   %o4,    $B0
380         ldx     [$pwrtbl+3*32], %o4
381         move    %icc,   %o5,    $B1
382         ldx     [$pwrtbl+11*32],%o5
383         movneg  %icc,   %o4,    $B0
384         ldx     [$pwrtbl+4*32], %o4
385         movneg  %icc,   %o5,    $B1
386         ldx     [$pwrtbl+12*32],%o5
387         movcs   %xcc,   %o4,    $B0
388         ldx     [$pwrtbl+5*32],%o4
389         movcs   %xcc,   %o5,    $B1
390         ldx     [$pwrtbl+13*32],%o5
391         movvs   %xcc,   %o4,    $B0
392         ldx     [$pwrtbl+6*32], %o4
393         movvs   %xcc,   %o5,    $B1
394         ldx     [$pwrtbl+14*32],%o5
395         move    %xcc,   %o4,    $B0
396         ldx     [$pwrtbl+7*32], %o4
397         move    %xcc,   %o5,    $B1
398         ldx     [$pwrtbl+15*32],%o5
399         movneg  %xcc,   %o4,    $B0
400         add     $pwrtbl,16*32,  $pwrtbl
401         movneg  %xcc,   %o5,    $B1
402 ___
403 }
404 sub load_b {
405 my ($pwrtbl,$Bi)=@_;
406
407 $code.=<<___;
408         ldx     [$pwrtbl+0*32], $Bi
409         ldx     [$pwrtbl+1*32], %o4
410         ldx     [$pwrtbl+2*32], %o5
411         movvs   %icc,   %o4,    $Bi
412         ldx     [$pwrtbl+3*32], %o4
413         move    %icc,   %o5,    $Bi
414         ldx     [$pwrtbl+4*32], %o5
415         movneg  %icc,   %o4,    $Bi
416         ldx     [$pwrtbl+5*32], %o4
417         movcs   %xcc,   %o5,    $Bi
418         ldx     [$pwrtbl+6*32], %o5
419         movvs   %xcc,   %o4,    $Bi
420         ldx     [$pwrtbl+7*32], %o4
421         move    %xcc,   %o5,    $Bi
422         add     $pwrtbl,8*32,   $pwrtbl
423         movneg  %xcc,   %o4,    $Bi
424 ___
425 }
426 \f
427 ########################################################################
428 # int bn_pwr5_mont_t4_$NUM(u64 *tp,const u64 *np,const BN_ULONG *n0,
429 #                          const u64 *pwrtbl,int pwr,int stride);
430 #
431 sub generate_bn_pwr5_mont_t4() {
432 my $NUM=shift;
433 my ($tp,$np,$pwrtbl,$pwr,$sentinel)=map("%g$_",(1..5));
434
435 $code.=<<___;
436 .globl  bn_pwr5_mont_t4_$NUM
437 .align  32
438 bn_pwr5_mont_t4_$NUM:
439 #ifdef  __arch64__
440         mov     0,$sentinel
441         mov     -128,%g4
442 #elif defined(SPARCV9_64BIT_STACK)
443         SPARC_LOAD_ADDRESS_LEAF(OPENSSL_sparcv9cap_P,%g1,%g5)
444         ld      [%g1+0],%g1     ! OPENSSL_sparcv9_P[0]
445         mov     -2047,%g4
446         and     %g1,SPARCV9_64BIT_STACK,%g1
447         movrz   %g1,0,%g4
448         mov     -1,$sentinel
449         add     %g4,-128,%g4
450 #else
451         mov     -1,$sentinel
452         mov     -128,%g4
453 #endif
454         sllx    $sentinel,32,$sentinel
455         save    %sp,%g4,%sp
456 #ifndef __arch64__
457         save    %sp,-128,%sp    ! warm it up
458         save    %sp,-128,%sp
459         save    %sp,-128,%sp
460         save    %sp,-128,%sp
461         save    %sp,-128,%sp
462         save    %sp,-128,%sp
463         restore
464         restore
465         restore
466         restore
467         restore
468         restore
469 #endif
470         and     %sp,1,%g4
471         or      $sentinel,%fp,%fp
472         or      %g4,$sentinel,$sentinel
473
474         ! copy arguments to global registers
475         mov     %i0,$tp
476         mov     %i1,$np
477         ld      [%i2+0],%f1     ! load *n0
478         ld      [%i2+4],%f0
479         mov     %i3,$pwrtbl
480         srl     %i4,%g0,%i4     ! pack last arguments
481         sllx    %i5,32,$pwr
482         or      %i4,$pwr,$pwr
483         fsrc2   %f0,%f60
484 ___
485 \f
486 # load tp[$NUM] ########################################################
487 $code.=<<___;
488         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
489 ___
490 for($i=0; $i<14 && $i<$NUM; $i++) {
491 $code.=<<___;
492         ldx     [$tp+$i*8],@A[$i]
493 ___
494 }
495 for(; $i<$NUM; $i++) {
496 $code.=<<___;
497         ldd     [$tp+$i*8],@A[$i]
498 ___
499 }
500 # load np[$NUM] ########################################################
501 $code.=<<___;
502         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
503 ___
504 for($i=0; $i<14 && $i<$NUM; $i++) {
505 $code.=<<___;
506         ldx     [$np+$i*8],@N[$i]
507 ___
508 }
509 $code.=<<___;
510         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
511 ___
512 for(; $i<28 && $i<$NUM; $i++) {
513 $code.=<<___;
514         ldx     [$np+$i*8],@N[$i]
515 ___
516 }
517 $code.=<<___;
518         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
519 ___
520 for(; $i<$NUM; $i++) {
521 $code.=<<___;
522         ldx     [$np+$i*8],@N[$i]
523 ___
524 }
525 # load pwrtbl[pwr] ########################################################
526 $code.=<<___;
527         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
528
529         srlx    $pwr,   32,     %o4             ! unpack $pwr
530         srl     $pwr,   %g0,    %o5
531         sub     %o4,    5,      %o4
532         mov     $pwrtbl,        %o7
533         sllx    %o4,    32,     $pwr            ! re-pack $pwr
534         or      %o5,    $pwr,   $pwr
535         srl     %o5,    %o4,    %o5
536 ___
537         &load_ccr("%o7","%o5","%o4");
538 $code.=<<___;
539         b       .Lstride_$NUM
540         nop
541 .align  16
542 .Lstride_$NUM:
543 ___
544 for($i=0; $i<14 && $i<$NUM; $i+=2) {
545         &load_b_pair("%o7",@B[$i],@B[$i+1]);
546 }
547 $code.=<<___;
548         save    %sp,-128,%sp;           or      $sentinel,%fp,%fp
549 ___
550 for(; $i<$NUM; $i+=2) {
551         &load_b_pair("%i7",@B[$i],@B[$i+1]);
552 }
553 $code.=<<___;
554         srax    $pwr,   32,     %o4             ! unpack $pwr
555         srl     $pwr,   %g0,    %o5
556         sub     %o4,    5,      %o4
557         mov     $pwrtbl,        %i7
558         sllx    %o4,    32,     $pwr            ! re-pack $pwr
559         or      %o5,    $pwr,   $pwr
560         srl     %o5,    %o4,    %o5
561 ___
562         &load_ccr("%i7","%o5","%o4",1);
563 \f
564 # magic ################################################################
565 for($i=0; $i<5; $i++) {
566 $code.=<<___;
567         .word   0x81b02940+$NUM-1       ! montsqr       $NUM-1
568         fbu,pn  %fcc3,.Labort_$NUM
569 #ifndef __arch64__
570         and     %fp,$sentinel,$sentinel
571         brz,pn  $sentinel,.Labort_$NUM
572 #endif
573         nop
574 ___
575 }
576 $code.=<<___;
577         wr      %o4,    %g0,    %ccr
578         .word   0x81b02920+$NUM-1       ! montmul       $NUM-1
579         fbu,pn  %fcc3,.Labort_$NUM
580 #ifndef __arch64__
581         and     %fp,$sentinel,$sentinel
582         brz,pn  $sentinel,.Labort_$NUM
583 #endif
584
585         srax    $pwr,   32,     %o4
586 #ifdef  __arch64__
587         brgez   %o4,.Lstride_$NUM
588         restore
589         restore
590         restore
591         restore
592         restore
593 #else
594         brgez   %o4,.Lstride_$NUM
595         restore;                and     %fp,$sentinel,$sentinel
596         restore;                and     %fp,$sentinel,$sentinel
597         restore;                and     %fp,$sentinel,$sentinel
598         restore;                and     %fp,$sentinel,$sentinel
599          brz,pn $sentinel,.Labort1_$NUM
600         restore
601 #endif
602 ___
603 \f
604 # save tp[$NUM] ########################################################
605 for($i=0; $i<14 && $i<$NUM; $i++) {
606 $code.=<<___;
607         movxtod @A[$i],@R[$i]
608 ___
609 }
610 $code.=<<___;
611 #ifdef  __arch64__
612         restore
613 #else
614          and    %fp,$sentinel,$sentinel
615         restore
616          and    $sentinel,1,%o7
617          and    %fp,$sentinel,$sentinel
618          srl    %fp,0,%fp               ! just in case?
619          or     %o7,$sentinel,$sentinel
620         brz,a,pn $sentinel,.Ldone_$NUM
621         mov     0,%i0           ! return failure
622 #endif
623 ___
624 for($i=0; $i<$NUM; $i++) {
625 $code.=<<___;
626         std     @R[$i],[$tp+$i*8]
627 ___
628 }
629 $code.=<<___;
630         mov     1,%i0           ! return success
631 .Ldone_$NUM:
632         ret
633         restore
634
635 .Labort_$NUM:
636         restore
637         restore
638         restore
639         restore
640         restore
641 .Labort1_$NUM:
642         restore
643
644         mov     0,%i0           ! return failure
645         ret
646         restore
647 .type   bn_pwr5_mont_t4_$NUM, #function
648 .size   bn_pwr5_mont_t4_$NUM, .-bn_pwr5_mont_t4_$NUM
649 ___
650 }
651
652 for ($i=8;$i<=32;$i+=8) {
653         &generate_bn_pwr5_mont_t4($i);
654 }
655 \f
656 {
657 ########################################################################
658 # Fall-back subroutines
659 #
660 # copy of bn_mul_mont_vis3 adjusted for vectors of 64-bit values
661 #
662 ($n0,$m0,$m1,$lo0,$hi0, $lo1,$hi1,$aj,$alo,$nj,$nlo,$tj)=
663         (map("%g$_",(1..5)),map("%o$_",(0..5,7)));
664
665 # int bn_mul_mont(
666 $rp="%o0";      # u64 *rp,
667 $ap="%o1";      # const u64 *ap,
668 $bp="%o2";      # const u64 *bp,
669 $np="%o3";      # const u64 *np,
670 $n0p="%o4";     # const BN_ULONG *n0,
671 $num="%o5";     # int num);     # caller ensures that num is >=3
672 $code.=<<___;
673 .globl  bn_mul_mont_t4
674 .align  32
675 bn_mul_mont_t4:
676         add     %sp,    STACK_BIAS,     %g4     ! real top of stack
677         sll     $num,   3,      $num            ! size in bytes
678         add     $num,   63,     %g1
679         andn    %g1,    63,     %g1             ! buffer size rounded up to 64 bytes
680         sub     %g4,    %g1,    %g1
681         andn    %g1,    63,     %g1             ! align at 64 byte
682         sub     %g1,    STACK_FRAME,    %g1     ! new top of stack
683         sub     %g1,    %g4,    %g1
684
685         save    %sp,    %g1,    %sp
686 ___
687 #       +-------------------------------+<----- %sp
688 #       .                               .
689 #       +-------------------------------+<----- aligned at 64 bytes
690 #       | __int64 tmp[0]                |
691 #       +-------------------------------+
692 #       .                               .
693 #       .                               .
694 #       +-------------------------------+<----- aligned at 64 bytes
695 #       .                               .
696 ($rp,$ap,$bp,$np,$n0p,$num)=map("%i$_",(0..5));
697 ($t0,$t1,$t2,$t3,$cnt,$tp,$bufsz)=map("%l$_",(0..7));
698 ($ovf,$i)=($t0,$t1);
699 $code.=<<___;
700         ld      [$n0p+0],       $t0     ! pull n0[0..1] value
701         ld      [$n0p+4],       $t1
702         add     %sp, STACK_BIAS+STACK_FRAME, $tp
703         ldx     [$bp+0],        $m0     ! m0=bp[0]
704         sllx    $t1,    32,     $n0
705         add     $bp,    8,      $bp
706         or      $t0,    $n0,    $n0
707 \f
708         ldx     [$ap+0],        $aj     ! ap[0]
709
710         mulx    $aj,    $m0,    $lo0    ! ap[0]*bp[0]
711         umulxhi $aj,    $m0,    $hi0
712
713         ldx     [$ap+8],        $aj     ! ap[1]
714         add     $ap,    16,     $ap
715         ldx     [$np+0],        $nj     ! np[0]
716
717         mulx    $lo0,   $n0,    $m1     ! "tp[0]"*n0
718
719         mulx    $aj,    $m0,    $alo    ! ap[1]*bp[0]
720         umulxhi $aj,    $m0,    $aj     ! ahi=aj
721
722         mulx    $nj,    $m1,    $lo1    ! np[0]*m1
723         umulxhi $nj,    $m1,    $hi1
724
725         ldx     [$np+8],        $nj     ! np[1]
726
727         addcc   $lo0,   $lo1,   $lo1
728         add     $np,    16,     $np
729         addxc   %g0,    $hi1,   $hi1
730
731         mulx    $nj,    $m1,    $nlo    ! np[1]*m1
732         umulxhi $nj,    $m1,    $nj     ! nhi=nj
733 \f
734         ba      .L1st
735         sub     $num,   24,     $cnt    ! cnt=num-3
736
737 .align  16
738 .L1st:
739         addcc   $alo,   $hi0,   $lo0
740         addxc   $aj,    %g0,    $hi0
741
742         ldx     [$ap+0],        $aj     ! ap[j]
743         addcc   $nlo,   $hi1,   $lo1
744         add     $ap,    8,      $ap
745         addxc   $nj,    %g0,    $hi1    ! nhi=nj
746
747         ldx     [$np+0],        $nj     ! np[j]
748         mulx    $aj,    $m0,    $alo    ! ap[j]*bp[0]
749         add     $np,    8,      $np
750         umulxhi $aj,    $m0,    $aj     ! ahi=aj
751
752         mulx    $nj,    $m1,    $nlo    ! np[j]*m1
753         addcc   $lo0,   $lo1,   $lo1    ! np[j]*m1+ap[j]*bp[0]
754         umulxhi $nj,    $m1,    $nj     ! nhi=nj
755         addxc   %g0,    $hi1,   $hi1
756         stxa    $lo1,   [$tp]0xe2       ! tp[j-1]
757         add     $tp,    8,      $tp     ! tp++
758
759         brnz,pt $cnt,   .L1st
760         sub     $cnt,   8,      $cnt    ! j--
761 !.L1st
762         addcc   $alo,   $hi0,   $lo0
763         addxc   $aj,    %g0,    $hi0    ! ahi=aj
764
765         addcc   $nlo,   $hi1,   $lo1
766         addxc   $nj,    %g0,    $hi1
767         addcc   $lo0,   $lo1,   $lo1    ! np[j]*m1+ap[j]*bp[0]
768         addxc   %g0,    $hi1,   $hi1
769         stxa    $lo1,   [$tp]0xe2       ! tp[j-1]
770         add     $tp,    8,      $tp
771
772         addcc   $hi0,   $hi1,   $hi1
773         addxc   %g0,    %g0,    $ovf    ! upmost overflow bit
774         stxa    $hi1,   [$tp]0xe2
775         add     $tp,    8,      $tp
776 \f
777         ba      .Louter
778         sub     $num,   16,     $i      ! i=num-2
779
780 .align  16
781 .Louter:
782         ldx     [$bp+0],        $m0     ! m0=bp[i]
783         add     $bp,    8,      $bp
784
785         sub     $ap,    $num,   $ap     ! rewind
786         sub     $np,    $num,   $np
787         sub     $tp,    $num,   $tp
788
789         ldx     [$ap+0],        $aj     ! ap[0]
790         ldx     [$np+0],        $nj     ! np[0]
791
792         mulx    $aj,    $m0,    $lo0    ! ap[0]*bp[i]
793         ldx     [$tp],          $tj     ! tp[0]
794         umulxhi $aj,    $m0,    $hi0
795         ldx     [$ap+8],        $aj     ! ap[1]
796         addcc   $lo0,   $tj,    $lo0    ! ap[0]*bp[i]+tp[0]
797         mulx    $aj,    $m0,    $alo    ! ap[1]*bp[i]
798         addxc   %g0,    $hi0,   $hi0
799         mulx    $lo0,   $n0,    $m1     ! tp[0]*n0
800         umulxhi $aj,    $m0,    $aj     ! ahi=aj
801         mulx    $nj,    $m1,    $lo1    ! np[0]*m1
802         add     $ap,    16,     $ap
803         umulxhi $nj,    $m1,    $hi1
804         ldx     [$np+8],        $nj     ! np[1]
805         add     $np,    16,     $np
806         addcc   $lo1,   $lo0,   $lo1
807         mulx    $nj,    $m1,    $nlo    ! np[1]*m1
808         addxc   %g0,    $hi1,   $hi1
809         umulxhi $nj,    $m1,    $nj     ! nhi=nj
810 \f
811         ba      .Linner
812         sub     $num,   24,     $cnt    ! cnt=num-3
813 .align  16
814 .Linner:
815         addcc   $alo,   $hi0,   $lo0
816         ldx     [$tp+8],        $tj     ! tp[j]
817         addxc   $aj,    %g0,    $hi0    ! ahi=aj
818         ldx     [$ap+0],        $aj     ! ap[j]
819         add     $ap,    8,      $ap
820         addcc   $nlo,   $hi1,   $lo1
821         mulx    $aj,    $m0,    $alo    ! ap[j]*bp[i]
822         addxc   $nj,    %g0,    $hi1    ! nhi=nj
823         ldx     [$np+0],        $nj     ! np[j]
824         add     $np,    8,      $np
825         umulxhi $aj,    $m0,    $aj     ! ahi=aj
826         addcc   $lo0,   $tj,    $lo0    ! ap[j]*bp[i]+tp[j]
827         mulx    $nj,    $m1,    $nlo    ! np[j]*m1
828         addxc   %g0,    $hi0,   $hi0
829         umulxhi $nj,    $m1,    $nj     ! nhi=nj
830         addcc   $lo1,   $lo0,   $lo1    ! np[j]*m1+ap[j]*bp[i]+tp[j]
831         addxc   %g0,    $hi1,   $hi1
832         stx     $lo1,   [$tp]           ! tp[j-1]
833         add     $tp,    8,      $tp
834         brnz,pt $cnt,   .Linner
835         sub     $cnt,   8,      $cnt
836 !.Linner
837         ldx     [$tp+8],        $tj     ! tp[j]
838         addcc   $alo,   $hi0,   $lo0
839         addxc   $aj,    %g0,    $hi0    ! ahi=aj
840         addcc   $lo0,   $tj,    $lo0    ! ap[j]*bp[i]+tp[j]
841         addxc   %g0,    $hi0,   $hi0
842
843         addcc   $nlo,   $hi1,   $lo1
844         addxc   $nj,    %g0,    $hi1    ! nhi=nj
845         addcc   $lo1,   $lo0,   $lo1    ! np[j]*m1+ap[j]*bp[i]+tp[j]
846         addxc   %g0,    $hi1,   $hi1
847         stx     $lo1,   [$tp]           ! tp[j-1]
848
849         subcc   %g0,    $ovf,   %g0     ! move upmost overflow to CCR.xcc
850         addxccc $hi1,   $hi0,   $hi1
851         addxc   %g0,    %g0,    $ovf
852         stx     $hi1,   [$tp+8]
853         add     $tp,    16,     $tp
854
855         brnz,pt $i,     .Louter
856         sub     $i,     8,      $i
857 \f
858         sub     $ap,    $num,   $ap     ! rewind
859         sub     $np,    $num,   $np
860         sub     $tp,    $num,   $tp
861         ba      .Lsub
862         subcc   $num,   8,      $cnt    ! cnt=num-1 and clear CCR.xcc
863
864 .align  16
865 .Lsub:
866         ldx     [$tp],          $tj
867         add     $tp,    8,      $tp
868         ldx     [$np+0],        $nj
869         add     $np,    8,      $np
870         subccc  $tj,    $nj,    $t2     ! tp[j]-np[j]
871         srlx    $tj,    32,     $tj
872         srlx    $nj,    32,     $nj
873         subccc  $tj,    $nj,    $t3
874         add     $rp,    8,      $rp
875         st      $t2,    [$rp-4]         ! reverse order
876         st      $t3,    [$rp-8]
877         brnz,pt $cnt,   .Lsub
878         sub     $cnt,   8,      $cnt
879
880         sub     $np,    $num,   $np     ! rewind
881         sub     $tp,    $num,   $tp
882         sub     $rp,    $num,   $rp
883
884         subc    $ovf,   %g0,    $ovf    ! handle upmost overflow bit
885         and     $tp,    $ovf,   $ap
886         andn    $rp,    $ovf,   $np
887         or      $np,    $ap,    $ap     ! ap=borrow?tp:rp
888         ba      .Lcopy
889         sub     $num,   8,      $cnt
890
891 .align  16
892 .Lcopy:                                 ! copy or in-place refresh
893         ldx     [$ap+0],        $t2
894         add     $ap,    8,      $ap
895         stx     %g0,    [$tp]           ! zap
896         add     $tp,    8,      $tp
897         stx     $t2,    [$rp+0]
898         add     $rp,    8,      $rp
899         brnz    $cnt,   .Lcopy
900         sub     $cnt,   8,      $cnt
901
902         mov     1,      %o0
903         ret
904         restore
905 .type   bn_mul_mont_t4, #function
906 .size   bn_mul_mont_t4, .-bn_mul_mont_t4
907 ___
908 \f
909 # int bn_mul_mont_gather5(
910 $rp="%o0";      # u64 *rp,
911 $ap="%o1";      # const u64 *ap,
912 $bp="%o2";      # const u64 *pwrtbl,
913 $np="%o3";      # const u64 *np,
914 $n0p="%o4";     # const BN_ULONG *n0,
915 $num="%o5";     # int num,      # caller ensures that num is >=3
916                 # int power);
917 $code.=<<___;
918 .globl  bn_mul_mont_gather5_t4
919 .align  32
920 bn_mul_mont_gather5_t4:
921         add     %sp,    STACK_BIAS,     %g4     ! real top of stack
922         sll     $num,   3,      $num            ! size in bytes
923         add     $num,   63,     %g1
924         andn    %g1,    63,     %g1             ! buffer size rounded up to 64 bytes
925         sub     %g4,    %g1,    %g1
926         andn    %g1,    63,     %g1             ! align at 64 byte
927         sub     %g1,    STACK_FRAME,    %g1     ! new top of stack
928         sub     %g1,    %g4,    %g1
929         LDPTR   [%sp+STACK_7thARG],     %g4     ! load power, 7th argument
930
931         save    %sp,    %g1,    %sp
932 ___
933 #       +-------------------------------+<----- %sp
934 #       .                               .
935 #       +-------------------------------+<----- aligned at 64 bytes
936 #       | __int64 tmp[0]                |
937 #       +-------------------------------+
938 #       .                               .
939 #       .                               .
940 #       +-------------------------------+<----- aligned at 64 bytes
941 #       .                               .
942 ($rp,$ap,$bp,$np,$n0p,$num)=map("%i$_",(0..5));
943 ($t0,$t1,$t2,$t3,$cnt,$tp,$bufsz,$ccr)=map("%l$_",(0..7));
944 ($ovf,$i)=($t0,$t1);
945         &load_ccr($bp,"%g4",$ccr);
946         &load_b($bp,$m0,"%o7");         # m0=bp[0]
947
948 $code.=<<___;
949         ld      [$n0p+0],       $t0     ! pull n0[0..1] value
950         ld      [$n0p+4],       $t1
951         add     %sp, STACK_BIAS+STACK_FRAME, $tp
952         sllx    $t1,    32,     $n0
953         or      $t0,    $n0,    $n0
954 \f
955         ldx     [$ap+0],        $aj     ! ap[0]
956
957         mulx    $aj,    $m0,    $lo0    ! ap[0]*bp[0]
958         umulxhi $aj,    $m0,    $hi0
959
960         ldx     [$ap+8],        $aj     ! ap[1]
961         add     $ap,    16,     $ap
962         ldx     [$np+0],        $nj     ! np[0]
963
964         mulx    $lo0,   $n0,    $m1     ! "tp[0]"*n0
965
966         mulx    $aj,    $m0,    $alo    ! ap[1]*bp[0]
967         umulxhi $aj,    $m0,    $aj     ! ahi=aj
968
969         mulx    $nj,    $m1,    $lo1    ! np[0]*m1
970         umulxhi $nj,    $m1,    $hi1
971
972         ldx     [$np+8],        $nj     ! np[1]
973
974         addcc   $lo0,   $lo1,   $lo1
975         add     $np,    16,     $np
976         addxc   %g0,    $hi1,   $hi1
977
978         mulx    $nj,    $m1,    $nlo    ! np[1]*m1
979         umulxhi $nj,    $m1,    $nj     ! nhi=nj
980 \f
981         ba      .L1st_g5
982         sub     $num,   24,     $cnt    ! cnt=num-3
983
984 .align  16
985 .L1st_g5:
986         addcc   $alo,   $hi0,   $lo0
987         addxc   $aj,    %g0,    $hi0
988
989         ldx     [$ap+0],        $aj     ! ap[j]
990         addcc   $nlo,   $hi1,   $lo1
991         add     $ap,    8,      $ap
992         addxc   $nj,    %g0,    $hi1    ! nhi=nj
993
994         ldx     [$np+0],        $nj     ! np[j]
995         mulx    $aj,    $m0,    $alo    ! ap[j]*bp[0]
996         add     $np,    8,      $np
997         umulxhi $aj,    $m0,    $aj     ! ahi=aj
998
999         mulx    $nj,    $m1,    $nlo    ! np[j]*m1
1000         addcc   $lo0,   $lo1,   $lo1    ! np[j]*m1+ap[j]*bp[0]
1001         umulxhi $nj,    $m1,    $nj     ! nhi=nj
1002         addxc   %g0,    $hi1,   $hi1
1003         stxa    $lo1,   [$tp]0xe2       ! tp[j-1]
1004         add     $tp,    8,      $tp     ! tp++
1005
1006         brnz,pt $cnt,   .L1st_g5
1007         sub     $cnt,   8,      $cnt    ! j--
1008 !.L1st_g5
1009         addcc   $alo,   $hi0,   $lo0
1010         addxc   $aj,    %g0,    $hi0    ! ahi=aj
1011
1012         addcc   $nlo,   $hi1,   $lo1
1013         addxc   $nj,    %g0,    $hi1
1014         addcc   $lo0,   $lo1,   $lo1    ! np[j]*m1+ap[j]*bp[0]
1015         addxc   %g0,    $hi1,   $hi1
1016         stxa    $lo1,   [$tp]0xe2       ! tp[j-1]
1017         add     $tp,    8,      $tp
1018
1019         addcc   $hi0,   $hi1,   $hi1
1020         addxc   %g0,    %g0,    $ovf    ! upmost overflow bit
1021         stxa    $hi1,   [$tp]0xe2
1022         add     $tp,    8,      $tp
1023 \f
1024         ba      .Louter_g5
1025         sub     $num,   16,     $i      ! i=num-2
1026
1027 .align  16
1028 .Louter_g5:
1029         wr      $ccr,   %g0,    %ccr
1030 ___
1031         &load_b($bp,$m0);               # m0=bp[i]
1032 $code.=<<___;
1033         sub     $ap,    $num,   $ap     ! rewind
1034         sub     $np,    $num,   $np
1035         sub     $tp,    $num,   $tp
1036
1037         ldx     [$ap+0],        $aj     ! ap[0]
1038         ldx     [$np+0],        $nj     ! np[0]
1039
1040         mulx    $aj,    $m0,    $lo0    ! ap[0]*bp[i]
1041         ldx     [$tp],          $tj     ! tp[0]
1042         umulxhi $aj,    $m0,    $hi0
1043         ldx     [$ap+8],        $aj     ! ap[1]
1044         addcc   $lo0,   $tj,    $lo0    ! ap[0]*bp[i]+tp[0]
1045         mulx    $aj,    $m0,    $alo    ! ap[1]*bp[i]
1046         addxc   %g0,    $hi0,   $hi0
1047         mulx    $lo0,   $n0,    $m1     ! tp[0]*n0
1048         umulxhi $aj,    $m0,    $aj     ! ahi=aj
1049         mulx    $nj,    $m1,    $lo1    ! np[0]*m1
1050         add     $ap,    16,     $ap
1051         umulxhi $nj,    $m1,    $hi1
1052         ldx     [$np+8],        $nj     ! np[1]
1053         add     $np,    16,     $np
1054         addcc   $lo1,   $lo0,   $lo1
1055         mulx    $nj,    $m1,    $nlo    ! np[1]*m1
1056         addxc   %g0,    $hi1,   $hi1
1057         umulxhi $nj,    $m1,    $nj     ! nhi=nj
1058 \f
1059         ba      .Linner_g5
1060         sub     $num,   24,     $cnt    ! cnt=num-3
1061 .align  16
1062 .Linner_g5:
1063         addcc   $alo,   $hi0,   $lo0
1064         ldx     [$tp+8],        $tj     ! tp[j]
1065         addxc   $aj,    %g0,    $hi0    ! ahi=aj
1066         ldx     [$ap+0],        $aj     ! ap[j]
1067         add     $ap,    8,      $ap
1068         addcc   $nlo,   $hi1,   $lo1
1069         mulx    $aj,    $m0,    $alo    ! ap[j]*bp[i]
1070         addxc   $nj,    %g0,    $hi1    ! nhi=nj
1071         ldx     [$np+0],        $nj     ! np[j]
1072         add     $np,    8,      $np
1073         umulxhi $aj,    $m0,    $aj     ! ahi=aj
1074         addcc   $lo0,   $tj,    $lo0    ! ap[j]*bp[i]+tp[j]
1075         mulx    $nj,    $m1,    $nlo    ! np[j]*m1
1076         addxc   %g0,    $hi0,   $hi0
1077         umulxhi $nj,    $m1,    $nj     ! nhi=nj
1078         addcc   $lo1,   $lo0,   $lo1    ! np[j]*m1+ap[j]*bp[i]+tp[j]
1079         addxc   %g0,    $hi1,   $hi1
1080         stx     $lo1,   [$tp]           ! tp[j-1]
1081         add     $tp,    8,      $tp
1082         brnz,pt $cnt,   .Linner_g5
1083         sub     $cnt,   8,      $cnt
1084 !.Linner_g5
1085         ldx     [$tp+8],        $tj     ! tp[j]
1086         addcc   $alo,   $hi0,   $lo0
1087         addxc   $aj,    %g0,    $hi0    ! ahi=aj
1088         addcc   $lo0,   $tj,    $lo0    ! ap[j]*bp[i]+tp[j]
1089         addxc   %g0,    $hi0,   $hi0
1090
1091         addcc   $nlo,   $hi1,   $lo1
1092         addxc   $nj,    %g0,    $hi1    ! nhi=nj
1093         addcc   $lo1,   $lo0,   $lo1    ! np[j]*m1+ap[j]*bp[i]+tp[j]
1094         addxc   %g0,    $hi1,   $hi1
1095         stx     $lo1,   [$tp]           ! tp[j-1]
1096
1097         subcc   %g0,    $ovf,   %g0     ! move upmost overflow to CCR.xcc
1098         addxccc $hi1,   $hi0,   $hi1
1099         addxc   %g0,    %g0,    $ovf
1100         stx     $hi1,   [$tp+8]
1101         add     $tp,    16,     $tp
1102
1103         brnz,pt $i,     .Louter_g5
1104         sub     $i,     8,      $i
1105 \f
1106         sub     $ap,    $num,   $ap     ! rewind
1107         sub     $np,    $num,   $np
1108         sub     $tp,    $num,   $tp
1109         ba      .Lsub_g5
1110         subcc   $num,   8,      $cnt    ! cnt=num-1 and clear CCR.xcc
1111
1112 .align  16
1113 .Lsub_g5:
1114         ldx     [$tp],          $tj
1115         add     $tp,    8,      $tp
1116         ldx     [$np+0],        $nj
1117         add     $np,    8,      $np
1118         subccc  $tj,    $nj,    $t2     ! tp[j]-np[j]
1119         srlx    $tj,    32,     $tj
1120         srlx    $nj,    32,     $nj
1121         subccc  $tj,    $nj,    $t3
1122         add     $rp,    8,      $rp
1123         st      $t2,    [$rp-4]         ! reverse order
1124         st      $t3,    [$rp-8]
1125         brnz,pt $cnt,   .Lsub_g5
1126         sub     $cnt,   8,      $cnt
1127
1128         sub     $np,    $num,   $np     ! rewind
1129         sub     $tp,    $num,   $tp
1130         sub     $rp,    $num,   $rp
1131
1132         subc    $ovf,   %g0,    $ovf    ! handle upmost overflow bit
1133         and     $tp,    $ovf,   $ap
1134         andn    $rp,    $ovf,   $np
1135         or      $np,    $ap,    $ap     ! ap=borrow?tp:rp
1136         ba      .Lcopy_g5
1137         sub     $num,   8,      $cnt
1138
1139 .align  16
1140 .Lcopy_g5:                              ! copy or in-place refresh
1141         ldx     [$ap+0],        $t2
1142         add     $ap,    8,      $ap
1143         stx     %g0,    [$tp]           ! zap
1144         add     $tp,    8,      $tp
1145         stx     $t2,    [$rp+0]
1146         add     $rp,    8,      $rp
1147         brnz    $cnt,   .Lcopy_g5
1148         sub     $cnt,   8,      $cnt
1149
1150         mov     1,      %o0
1151         ret
1152         restore
1153 .type   bn_mul_mont_gather5_t4, #function
1154 .size   bn_mul_mont_gather5_t4, .-bn_mul_mont_gather5_t4
1155 ___
1156 }
1157 \f
1158 $code.=<<___;
1159 .globl  bn_flip_t4
1160 .align  32
1161 bn_flip_t4:
1162 .Loop_flip:
1163         ld      [%o1+0],        %o4
1164         sub     %o2,    1,      %o2
1165         ld      [%o1+4],        %o5
1166         add     %o1,    8,      %o1
1167         st      %o5,    [%o0+0]
1168         st      %o4,    [%o0+4]
1169         brnz    %o2,    .Loop_flip
1170         add     %o0,    8,      %o0
1171         retl
1172         nop
1173 .type   bn_flip_t4, #function
1174 .size   bn_flip_t4, .-bn_flip_t4
1175
1176 .globl  bn_flip_n_scatter5_t4
1177 .align  32
1178 bn_flip_n_scatter5_t4:
1179         sll     %o3,    3,      %o3
1180         srl     %o1,    1,      %o1
1181         add     %o3,    %o2,    %o2     ! &pwrtbl[pwr]
1182         sub     %o1,    1,      %o1
1183 .Loop_flip_n_scatter5:
1184         ld      [%o0+0],        %o4     ! inp[i]
1185         ld      [%o0+4],        %o5
1186         add     %o0,    8,      %o0
1187         sllx    %o5,    32,     %o5
1188         or      %o4,    %o5,    %o5
1189         stx     %o5,    [%o2]
1190         add     %o2,    32*8,   %o2
1191         brnz    %o1,    .Loop_flip_n_scatter5
1192         sub     %o1,    1,      %o1
1193         retl
1194         nop
1195 .type   bn_flip_n_scatter5_t4, #function
1196 .size   bn_flip_n_scatter5_t4, .-bn_flip_n_scatter5_t4
1197
1198 .globl  bn_gather5_t4
1199 .align  32
1200 bn_gather5_t4:
1201 ___
1202         &load_ccr("%o2","%o3","%g1");
1203 $code.=<<___;
1204         sub     %o1,    1,      %o1
1205 .Loop_gather5:
1206 ___
1207         &load_b("%o2","%g1");
1208 $code.=<<___;
1209         stx     %g1,    [%o0]
1210         add     %o0,    8,      %o0
1211         brnz    %o1,    .Loop_gather5
1212         sub     %o1,    1,      %o1
1213
1214         retl
1215         nop
1216 .type   bn_gather5_t4, #function
1217 .size   bn_gather5_t4, .-bn_gather5_t4
1218
1219 .asciz  "Montgomery Multiplication for SPARC T4, David S. Miller, Andy Polyakov"
1220 .align  4
1221 ___
1222
1223 &emit_assembler();
1224
1225 close STDOUT;