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