3 # Implemented as a Perl wrapper as we want to support several different
4 # architectures with single file. We pick up the target based on the
5 # file name we are asked to generate.
7 # It should be noted though that this perl code is nothing like
8 # <openssl>/crypto/perlasm/x86*. In this case perl is used pretty much
9 # as pre-processor to cover for platform differences in name decoration,
10 # linker tables, 32-/64-bit instruction sets...
12 # As you might know there're several PowerPC ABI in use. Most notably
13 # Linux and AIX use different 32-bit ABIs. Good news are that these ABIs
14 # are similar enough to implement leaf(!) functions, which would be ABI
15 # neutral. And that's what you find here: ABI neutral leaf functions.
16 # In case you wonder what that is...
20 # MEASUREMENTS WITH cc ON a 200 MhZ PowerPC 604e.
22 # The following is the performance of 32-bit compiler
25 # OpenSSL 0.9.6c 21 dec 2001
26 # built on: Tue Jun 11 11:06:51 EDT 2002
27 # options:bn(64,32) ...
28 #compiler: cc -DTHREADS -DAIX -DB_ENDIAN -DBN_LLONG -O3
29 # sign verify sign/s verify/s
30 #rsa 512 bits 0.0098s 0.0009s 102.0 1170.6
31 #rsa 1024 bits 0.0507s 0.0026s 19.7 387.5
32 #rsa 2048 bits 0.3036s 0.0085s 3.3 117.1
33 #rsa 4096 bits 2.0040s 0.0299s 0.5 33.4
34 #dsa 512 bits 0.0087s 0.0106s 114.3 94.5
35 #dsa 1024 bits 0.0256s 0.0313s 39.0 32.0
37 # Same bechmark with this assembler code:
39 #rsa 512 bits 0.0056s 0.0005s 178.6 2049.2
40 #rsa 1024 bits 0.0283s 0.0015s 35.3 674.1
41 #rsa 2048 bits 0.1744s 0.0050s 5.7 201.2
42 #rsa 4096 bits 1.1644s 0.0179s 0.9 55.7
43 #dsa 512 bits 0.0052s 0.0062s 191.6 162.0
44 #dsa 1024 bits 0.0149s 0.0180s 67.0 55.5
46 # Number of operations increases by at almost 75%
48 # Here are performance numbers for 64-bit compiler
51 # OpenSSL 0.9.6g [engine] 9 Aug 2002
52 # built on: Fri Apr 18 16:59:20 EDT 2003
53 # options:bn(64,64) ...
54 # compiler: cc -DTHREADS -D_REENTRANT -q64 -DB_ENDIAN -O3
55 # sign verify sign/s verify/s
56 #rsa 512 bits 0.0028s 0.0003s 357.1 3844.4
57 #rsa 1024 bits 0.0148s 0.0008s 67.5 1239.7
58 #rsa 2048 bits 0.0963s 0.0028s 10.4 353.0
59 #rsa 4096 bits 0.6538s 0.0102s 1.5 98.1
60 #dsa 512 bits 0.0026s 0.0032s 382.5 313.7
61 #dsa 1024 bits 0.0081s 0.0099s 122.8 100.6
63 # Same benchmark with this assembler code:
65 #rsa 512 bits 0.0020s 0.0002s 510.4 6273.7
66 #rsa 1024 bits 0.0088s 0.0005s 114.1 2128.3
67 #rsa 2048 bits 0.0540s 0.0016s 18.5 622.5
68 #rsa 4096 bits 0.3700s 0.0058s 2.7 171.0
69 #dsa 512 bits 0.0016s 0.0020s 610.7 507.1
70 #dsa 1024 bits 0.0047s 0.0058s 212.5 173.2
72 # Again, performance increases by at about 75%
74 # Mac OS X, Apple G5 1.8GHz (Note this is 32 bit code)
75 # OpenSSL 0.9.7c 30 Sep 2003
79 #rsa 512 bits 0.0011s 0.0001s 906.1 11012.5
80 #rsa 1024 bits 0.0060s 0.0003s 166.6 3363.1
81 #rsa 2048 bits 0.0370s 0.0010s 27.1 982.4
82 #rsa 4096 bits 0.2426s 0.0036s 4.1 280.4
83 #dsa 512 bits 0.0010s 0.0012s 1038.1 841.5
84 #dsa 1024 bits 0.0030s 0.0037s 329.6 269.7
85 #dsa 2048 bits 0.0101s 0.0127s 98.9 78.6
87 # Same benchmark with this assembler code:
89 #rsa 512 bits 0.0007s 0.0001s 1416.2 16645.9
90 #rsa 1024 bits 0.0036s 0.0002s 274.4 5380.6
91 #rsa 2048 bits 0.0222s 0.0006s 45.1 1589.5
92 #rsa 4096 bits 0.1469s 0.0022s 6.8 449.6
93 #dsa 512 bits 0.0006s 0.0007s 1664.2 1376.2
94 #dsa 1024 bits 0.0018s 0.0023s 545.0 442.2
95 #dsa 2048 bits 0.0061s 0.0075s 163.5 132.8
97 # Performance increase of ~60%
99 # If you have comments or suggestions to improve code send
100 # me a note at schari@us.ibm.com
105 if ($flavour =~ /32/) {
111 $LDU= "lwzu"; # load and update
113 $STU= "stwu"; # store and update
114 $UMULL= "mullw"; # unsigned multiply low
115 $UMULH= "mulhwu"; # unsigned multiply high
116 $UDIV= "divwu"; # unsigned divide
117 $UCMPI= "cmplwi"; # unsigned compare with immediate
118 $UCMP= "cmplw"; # unsigned compare
119 $CNTLZ= "cntlzw"; # count leading zeros
120 $SHL= "slw"; # shift left
121 $SHR= "srw"; # unsigned shift right
122 $SHRI= "srwi"; # unsigned shift right by immediate
123 $SHLI= "slwi"; # shift left by immediate
124 $CLRU= "clrlwi"; # clear upper bits
125 $INSR= "insrwi"; # insert right
126 $ROTL= "rotlwi"; # rotate left by immediate
127 $TR= "tw"; # conditional trap
128 } elsif ($flavour =~ /64/) {
133 # same as above, but 64-bit mnemonics...
135 $LDU= "ldu"; # load and update
137 $STU= "stdu"; # store and update
138 $UMULL= "mulld"; # unsigned multiply low
139 $UMULH= "mulhdu"; # unsigned multiply high
140 $UDIV= "divdu"; # unsigned divide
141 $UCMPI= "cmpldi"; # unsigned compare with immediate
142 $UCMP= "cmpld"; # unsigned compare
143 $CNTLZ= "cntlzd"; # count leading zeros
144 $SHL= "sld"; # shift left
145 $SHR= "srd"; # unsigned shift right
146 $SHRI= "srdi"; # unsigned shift right by immediate
147 $SHLI= "sldi"; # shift left by immediate
148 $CLRU= "clrldi"; # clear upper bits
149 $INSR= "insrdi"; # insert right
150 $ROTL= "rotldi"; # rotate left by immediate
151 $TR= "td"; # conditional trap
152 } else { die "nonsense $flavour"; }
154 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
155 ( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
156 ( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
157 die "can't locate ppc-xlate.pl";
159 open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
162 #--------------------------------------------------------------------
169 # Created by: Suresh Chari
170 # IBM Thomas J. Watson Research Library
174 # Description: Optimized assembly routines for OpenSSL crypto
175 # on the 32 bitPowerPC platform.
180 # 2. Fixed bn_add,bn_sub and bn_div_words, added comments,
181 # cleaned up code. Also made a single version which can
182 # be used for both the AIX and Linux compilers. See NOTE
184 # 12/05/03 Suresh Chari
185 # (with lots of help from) Andy Polyakov
187 # 1. Initial version 10/20/02 Suresh Chari
190 # The following file works for the xlc,cc
193 # NOTE: To get the file to link correctly with the gcc compiler
194 # you have to change the names of the routines and remove
195 # the first .(dot) character. This should automatically
196 # be done in the build process.
198 # Hand optimized assembly code for the following routines
211 # NOTE: It is possible to optimize this code more for
212 # specific PowerPC or Power architectures. On the Northstar
213 # architecture the optimizations in this file do
214 # NOT provide much improvement.
216 # If you have comments or suggestions to improve code send
217 # me a note at schari\@us.ibm.com
219 #--------------------------------------------------------------------------
221 # Defines to be used in the assembly code.
223 #.set r0,0 # we use it as storage for value of 0
224 #.set SP,1 # preserved
225 #.set RTOC,2 # preserved
226 #.set r3,3 # 1st argument/return value
227 #.set r4,4 # 2nd argument/volatile register
228 #.set r5,5 # 3rd argument/volatile register
236 #.set r13,13 # not used, nor any other "below" it...
238 # Declare function names to be global
239 # NOTE: For gcc these names MUST be changed to remove
240 # the first . i.e. for example change ".bn_sqr_comba4"
241 # to "bn_sqr_comba4". This should be automatically done
244 .globl .bn_sqr_comba4
245 .globl .bn_sqr_comba8
246 .globl .bn_mul_comba4
247 .globl .bn_mul_comba8
253 .globl .bn_mul_add_words
260 # NOTE: The following label name should be changed to
261 # "bn_sqr_comba4" i.e. remove the first dot
262 # for the gcc compiler. This should be automatically
269 # Optimized version of bn_sqr_comba4.
271 # void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
275 # Freely use registers r5,r6,r7,r8,r9,r10,r11 as follows:
277 # r5,r6 are the two BN_ULONGs being multiplied.
278 # r7,r8 are the results of the 32x32 giving 64 bit multiply.
279 # r9,r10, r11 are the equivalents of c1,c2, c3.
280 # Here's the assembly
283 xor r0,r0,r0 # set r0 = 0. Used in the addze
286 #sqr_add_c(a,0,c1,c2,c3)
289 $UMULH r10,r5,r5 #in first iteration. No need
290 #to add since c1=c2=c3=0.
291 # Note c3(r11) is NOT set to 0
294 $ST r9,`0*$BNSZ`(r3) # r[0]=c1;
295 # sqr_add_c2(a,1,0,c2,c3,c1);
300 addc r7,r7,r7 # compute (r7,r8)=2*(r7,r8)
302 addze r9,r0 # catch carry if any.
303 # r9= r0(=0) and carry
305 addc r10,r7,r10 # now add to temp result.
306 addze r11,r8 # r8 added to r11 which is 0
309 $ST r10,`1*$BNSZ`(r3) #r[1]=c2;
310 #sqr_add_c(a,1,c3,c1,c2)
316 #sqr_add_c2(a,2,0,c3,c1,c2)
328 $ST r11,`2*$BNSZ`(r3) #r[2]=c3
329 #sqr_add_c2(a,3,0,c1,c2,c3);
340 #sqr_add_c2(a,2,1,c1,c2,c3);
352 $ST r9,`3*$BNSZ`(r3) #r[3]=c1
353 #sqr_add_c(a,2,c2,c3,c1);
359 #sqr_add_c2(a,3,1,c2,c3,c1);
370 $ST r10,`4*$BNSZ`(r3) #r[4]=c2
371 #sqr_add_c2(a,3,2,c3,c1,c2);
382 $ST r11,`5*$BNSZ`(r3) #r[5] = c3
383 #sqr_add_c(a,3,c1,c2,c3);
389 $ST r9,`6*$BNSZ`(r3) #r[6]=c1
390 $ST r10,`7*$BNSZ`(r3) #r[7]=c2
393 .byte 0,12,0x14,0,0,0,2,0
397 # NOTE: The following label name should be changed to
398 # "bn_sqr_comba8" i.e. remove the first dot
399 # for the gcc compiler. This should be automatically
406 # This is an optimized version of the bn_sqr_comba8 routine.
407 # Tightly uses the adde instruction
410 # void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
414 # Freely use registers r5,r6,r7,r8,r9,r10,r11 as follows:
416 # r5,r6 are the two BN_ULONGs being multiplied.
417 # r7,r8 are the results of the 32x32 giving 64 bit multiply.
418 # r9,r10, r11 are the equivalents of c1,c2, c3.
420 # Possible optimization of loading all 8 longs of a into registers
421 # doesnt provide any speedup
424 xor r0,r0,r0 #set r0 = 0.Used in addze
427 #sqr_add_c(a,0,c1,c2,c3);
429 $UMULL r9,r5,r5 #1st iteration: no carries.
431 $ST r9,`0*$BNSZ`(r3) # r[0]=c1;
432 #sqr_add_c2(a,1,0,c2,c3,c1);
437 addc r10,r7,r10 #add the two register number
438 adde r11,r8,r0 # (r8,r7) to the three register
439 addze r9,r0 # number (r9,r11,r10).NOTE:r0=0
441 addc r10,r7,r10 #add the two register number
442 adde r11,r8,r11 # (r8,r7) to the three register
443 addze r9,r9 # number (r9,r11,r10).
445 $ST r10,`1*$BNSZ`(r3) # r[1]=c2
447 #sqr_add_c(a,1,c3,c1,c2);
453 #sqr_add_c2(a,2,0,c3,c1,c2);
466 $ST r11,`2*$BNSZ`(r3) #r[2]=c3
467 #sqr_add_c2(a,3,0,c1,c2,c3);
468 $LD r6,`3*$BNSZ`(r4) #r6 = a[3]. r5 is already a[0].
479 #sqr_add_c2(a,2,1,c1,c2,c3);
493 $ST r9,`3*$BNSZ`(r3) #r[3]=c1;
494 #sqr_add_c(a,2,c2,c3,c1);
501 #sqr_add_c2(a,3,1,c2,c3,c1);
513 #sqr_add_c2(a,4,0,c2,c3,c1);
526 $ST r10,`4*$BNSZ`(r3) #r[4]=c2;
527 #sqr_add_c2(a,5,0,c3,c1,c2);
539 #sqr_add_c2(a,4,1,c3,c1,c2);
552 #sqr_add_c2(a,3,2,c3,c1,c2);
565 $ST r11,`5*$BNSZ`(r3) #r[5]=c3;
566 #sqr_add_c(a,3,c1,c2,c3);
572 #sqr_add_c2(a,4,2,c1,c2,c3);
584 #sqr_add_c2(a,5,1,c1,c2,c3);
597 #sqr_add_c2(a,6,0,c1,c2,c3);
608 $ST r9,`6*$BNSZ`(r3) #r[6]=c1;
609 #sqr_add_c2(a,7,0,c2,c3,c1);
620 #sqr_add_c2(a,6,1,c2,c3,c1);
632 #sqr_add_c2(a,5,2,c2,c3,c1);
643 #sqr_add_c2(a,4,3,c2,c3,c1);
655 $ST r10,`7*$BNSZ`(r3) #r[7]=c2;
656 #sqr_add_c(a,4,c3,c1,c2);
662 #sqr_add_c2(a,5,3,c3,c1,c2);
672 #sqr_add_c2(a,6,2,c3,c1,c2);
684 #sqr_add_c2(a,7,1,c3,c1,c2);
695 $ST r11,`8*$BNSZ`(r3) #r[8]=c3;
696 #sqr_add_c2(a,7,2,c1,c2,c3);
707 #sqr_add_c2(a,6,3,c1,c2,c3);
718 #sqr_add_c2(a,5,4,c1,c2,c3);
729 $ST r9,`9*$BNSZ`(r3) #r[9]=c1;
730 #sqr_add_c(a,5,c2,c3,c1);
736 #sqr_add_c2(a,6,4,c2,c3,c1);
746 #sqr_add_c2(a,7,3,c2,c3,c1);
757 $ST r10,`10*$BNSZ`(r3) #r[10]=c2;
758 #sqr_add_c2(a,7,4,c3,c1,c2);
768 #sqr_add_c2(a,6,5,c3,c1,c2);
779 $ST r11,`11*$BNSZ`(r3) #r[11]=c3;
780 #sqr_add_c(a,6,c1,c2,c3);
786 #sqr_add_c2(a,7,5,c1,c2,c3)
796 $ST r9,`12*$BNSZ`(r3) #r[12]=c1;
798 #sqr_add_c2(a,7,6,c2,c3,c1)
808 $ST r10,`13*$BNSZ`(r3) #r[13]=c2;
809 #sqr_add_c(a,7,c3,c1,c2);
814 $ST r11,`14*$BNSZ`(r3) #r[14]=c3;
815 $ST r9, `15*$BNSZ`(r3) #r[15]=c1;
820 .byte 0,12,0x14,0,0,0,2,0
824 # NOTE: The following label name should be changed to
825 # "bn_mul_comba4" i.e. remove the first dot
826 # for the gcc compiler. This should be automatically
833 # This is an optimized version of the bn_mul_comba4 routine.
835 # void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
839 # r6, r7 are the 2 BN_ULONGs being multiplied.
840 # r8, r9 are the results of the 32x32 giving 64 multiply.
841 # r10, r11, r12 are the equivalents of c1, c2, and c3.
843 xor r0,r0,r0 #r0=0. Used in addze below.
844 #mul_add_c(a[0],b[0],c1,c2,c3);
849 $ST r10,`0*$BNSZ`(r3) #r[0]=c1
850 #mul_add_c(a[0],b[1],c2,c3,c1);
857 #mul_add_c(a[1],b[0],c2,c3,c1);
858 $LD r6, `1*$BNSZ`(r4)
859 $LD r7, `0*$BNSZ`(r5)
865 $ST r11,`1*$BNSZ`(r3) #r[1]=c2
866 #mul_add_c(a[2],b[0],c3,c1,c2);
873 #mul_add_c(a[1],b[1],c3,c1,c2);
881 #mul_add_c(a[0],b[2],c3,c1,c2);
889 $ST r12,`2*$BNSZ`(r3) #r[2]=c3
890 #mul_add_c(a[0],b[3],c1,c2,c3);
897 #mul_add_c(a[1],b[2],c1,c2,c3);
905 #mul_add_c(a[2],b[1],c1,c2,c3);
913 #mul_add_c(a[3],b[0],c1,c2,c3);
921 $ST r10,`3*$BNSZ`(r3) #r[3]=c1
922 #mul_add_c(a[3],b[1],c2,c3,c1);
929 #mul_add_c(a[2],b[2],c2,c3,c1);
937 #mul_add_c(a[1],b[3],c2,c3,c1);
945 $ST r11,`4*$BNSZ`(r3) #r[4]=c2
946 #mul_add_c(a[2],b[3],c3,c1,c2);
953 #mul_add_c(a[3],b[2],c3,c1,c2);
961 $ST r12,`5*$BNSZ`(r3) #r[5]=c3
962 #mul_add_c(a[3],b[3],c1,c2,c3);
969 $ST r10,`6*$BNSZ`(r3) #r[6]=c1
970 $ST r11,`7*$BNSZ`(r3) #r[7]=c2
973 .byte 0,12,0x14,0,0,0,3,0
977 # NOTE: The following label name should be changed to
978 # "bn_mul_comba8" i.e. remove the first dot
979 # for the gcc compiler. This should be automatically
986 # Optimized version of the bn_mul_comba8 routine.
988 # void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
992 # r6, r7 are the 2 BN_ULONGs being multiplied.
993 # r8, r9 are the results of the 32x32 giving 64 multiply.
994 # r10, r11, r12 are the equivalents of c1, c2, and c3.
996 xor r0,r0,r0 #r0=0. Used in addze below.
998 #mul_add_c(a[0],b[0],c1,c2,c3);
999 $LD r6,`0*$BNSZ`(r4) #a[0]
1000 $LD r7,`0*$BNSZ`(r5) #b[0]
1003 $ST r10,`0*$BNSZ`(r3) #r[0]=c1;
1004 #mul_add_c(a[0],b[1],c2,c3,c1);
1005 $LD r7,`1*$BNSZ`(r5)
1009 addze r12,r9 # since we didnt set r12 to zero before.
1011 #mul_add_c(a[1],b[0],c2,c3,c1);
1012 $LD r6,`1*$BNSZ`(r4)
1013 $LD r7,`0*$BNSZ`(r5)
1019 $ST r11,`1*$BNSZ`(r3) #r[1]=c2;
1020 #mul_add_c(a[2],b[0],c3,c1,c2);
1021 $LD r6,`2*$BNSZ`(r4)
1027 #mul_add_c(a[1],b[1],c3,c1,c2);
1028 $LD r6,`1*$BNSZ`(r4)
1029 $LD r7,`1*$BNSZ`(r5)
1035 #mul_add_c(a[0],b[2],c3,c1,c2);
1036 $LD r6,`0*$BNSZ`(r4)
1037 $LD r7,`2*$BNSZ`(r5)
1043 $ST r12,`2*$BNSZ`(r3) #r[2]=c3;
1044 #mul_add_c(a[0],b[3],c1,c2,c3);
1045 $LD r7,`3*$BNSZ`(r5)
1051 #mul_add_c(a[1],b[2],c1,c2,c3);
1052 $LD r6,`1*$BNSZ`(r4)
1053 $LD r7,`2*$BNSZ`(r5)
1060 #mul_add_c(a[2],b[1],c1,c2,c3);
1061 $LD r6,`2*$BNSZ`(r4)
1062 $LD r7,`1*$BNSZ`(r5)
1068 #mul_add_c(a[3],b[0],c1,c2,c3);
1069 $LD r6,`3*$BNSZ`(r4)
1070 $LD r7,`0*$BNSZ`(r5)
1076 $ST r10,`3*$BNSZ`(r3) #r[3]=c1;
1077 #mul_add_c(a[4],b[0],c2,c3,c1);
1078 $LD r6,`4*$BNSZ`(r4)
1084 #mul_add_c(a[3],b[1],c2,c3,c1);
1085 $LD r6,`3*$BNSZ`(r4)
1086 $LD r7,`1*$BNSZ`(r5)
1092 #mul_add_c(a[2],b[2],c2,c3,c1);
1093 $LD r6,`2*$BNSZ`(r4)
1094 $LD r7,`2*$BNSZ`(r5)
1100 #mul_add_c(a[1],b[3],c2,c3,c1);
1101 $LD r6,`1*$BNSZ`(r4)
1102 $LD r7,`3*$BNSZ`(r5)
1108 #mul_add_c(a[0],b[4],c2,c3,c1);
1109 $LD r6,`0*$BNSZ`(r4)
1110 $LD r7,`4*$BNSZ`(r5)
1116 $ST r11,`4*$BNSZ`(r3) #r[4]=c2;
1117 #mul_add_c(a[0],b[5],c3,c1,c2);
1118 $LD r7,`5*$BNSZ`(r5)
1124 #mul_add_c(a[1],b[4],c3,c1,c2);
1125 $LD r6,`1*$BNSZ`(r4)
1126 $LD r7,`4*$BNSZ`(r5)
1132 #mul_add_c(a[2],b[3],c3,c1,c2);
1133 $LD r6,`2*$BNSZ`(r4)
1134 $LD r7,`3*$BNSZ`(r5)
1140 #mul_add_c(a[3],b[2],c3,c1,c2);
1141 $LD r6,`3*$BNSZ`(r4)
1142 $LD r7,`2*$BNSZ`(r5)
1148 #mul_add_c(a[4],b[1],c3,c1,c2);
1149 $LD r6,`4*$BNSZ`(r4)
1150 $LD r7,`1*$BNSZ`(r5)
1156 #mul_add_c(a[5],b[0],c3,c1,c2);
1157 $LD r6,`5*$BNSZ`(r4)
1158 $LD r7,`0*$BNSZ`(r5)
1164 $ST r12,`5*$BNSZ`(r3) #r[5]=c3;
1165 #mul_add_c(a[6],b[0],c1,c2,c3);
1166 $LD r6,`6*$BNSZ`(r4)
1172 #mul_add_c(a[5],b[1],c1,c2,c3);
1173 $LD r6,`5*$BNSZ`(r4)
1174 $LD r7,`1*$BNSZ`(r5)
1180 #mul_add_c(a[4],b[2],c1,c2,c3);
1181 $LD r6,`4*$BNSZ`(r4)
1182 $LD r7,`2*$BNSZ`(r5)
1188 #mul_add_c(a[3],b[3],c1,c2,c3);
1189 $LD r6,`3*$BNSZ`(r4)
1190 $LD r7,`3*$BNSZ`(r5)
1196 #mul_add_c(a[2],b[4],c1,c2,c3);
1197 $LD r6,`2*$BNSZ`(r4)
1198 $LD r7,`4*$BNSZ`(r5)
1204 #mul_add_c(a[1],b[5],c1,c2,c3);
1205 $LD r6,`1*$BNSZ`(r4)
1206 $LD r7,`5*$BNSZ`(r5)
1212 #mul_add_c(a[0],b[6],c1,c2,c3);
1213 $LD r6,`0*$BNSZ`(r4)
1214 $LD r7,`6*$BNSZ`(r5)
1220 $ST r10,`6*$BNSZ`(r3) #r[6]=c1;
1221 #mul_add_c(a[0],b[7],c2,c3,c1);
1222 $LD r7,`7*$BNSZ`(r5)
1228 #mul_add_c(a[1],b[6],c2,c3,c1);
1229 $LD r6,`1*$BNSZ`(r4)
1230 $LD r7,`6*$BNSZ`(r5)
1236 #mul_add_c(a[2],b[5],c2,c3,c1);
1237 $LD r6,`2*$BNSZ`(r4)
1238 $LD r7,`5*$BNSZ`(r5)
1244 #mul_add_c(a[3],b[4],c2,c3,c1);
1245 $LD r6,`3*$BNSZ`(r4)
1246 $LD r7,`4*$BNSZ`(r5)
1252 #mul_add_c(a[4],b[3],c2,c3,c1);
1253 $LD r6,`4*$BNSZ`(r4)
1254 $LD r7,`3*$BNSZ`(r5)
1260 #mul_add_c(a[5],b[2],c2,c3,c1);
1261 $LD r6,`5*$BNSZ`(r4)
1262 $LD r7,`2*$BNSZ`(r5)
1268 #mul_add_c(a[6],b[1],c2,c3,c1);
1269 $LD r6,`6*$BNSZ`(r4)
1270 $LD r7,`1*$BNSZ`(r5)
1276 #mul_add_c(a[7],b[0],c2,c3,c1);
1277 $LD r6,`7*$BNSZ`(r4)
1278 $LD r7,`0*$BNSZ`(r5)
1284 $ST r11,`7*$BNSZ`(r3) #r[7]=c2;
1285 #mul_add_c(a[7],b[1],c3,c1,c2);
1286 $LD r7,`1*$BNSZ`(r5)
1292 #mul_add_c(a[6],b[2],c3,c1,c2);
1293 $LD r6,`6*$BNSZ`(r4)
1294 $LD r7,`2*$BNSZ`(r5)
1300 #mul_add_c(a[5],b[3],c3,c1,c2);
1301 $LD r6,`5*$BNSZ`(r4)
1302 $LD r7,`3*$BNSZ`(r5)
1308 #mul_add_c(a[4],b[4],c3,c1,c2);
1309 $LD r6,`4*$BNSZ`(r4)
1310 $LD r7,`4*$BNSZ`(r5)
1316 #mul_add_c(a[3],b[5],c3,c1,c2);
1317 $LD r6,`3*$BNSZ`(r4)
1318 $LD r7,`5*$BNSZ`(r5)
1324 #mul_add_c(a[2],b[6],c3,c1,c2);
1325 $LD r6,`2*$BNSZ`(r4)
1326 $LD r7,`6*$BNSZ`(r5)
1332 #mul_add_c(a[1],b[7],c3,c1,c2);
1333 $LD r6,`1*$BNSZ`(r4)
1334 $LD r7,`7*$BNSZ`(r5)
1340 $ST r12,`8*$BNSZ`(r3) #r[8]=c3;
1341 #mul_add_c(a[2],b[7],c1,c2,c3);
1342 $LD r6,`2*$BNSZ`(r4)
1348 #mul_add_c(a[3],b[6],c1,c2,c3);
1349 $LD r6,`3*$BNSZ`(r4)
1350 $LD r7,`6*$BNSZ`(r5)
1356 #mul_add_c(a[4],b[5],c1,c2,c3);
1357 $LD r6,`4*$BNSZ`(r4)
1358 $LD r7,`5*$BNSZ`(r5)
1364 #mul_add_c(a[5],b[4],c1,c2,c3);
1365 $LD r6,`5*$BNSZ`(r4)
1366 $LD r7,`4*$BNSZ`(r5)
1372 #mul_add_c(a[6],b[3],c1,c2,c3);
1373 $LD r6,`6*$BNSZ`(r4)
1374 $LD r7,`3*$BNSZ`(r5)
1380 #mul_add_c(a[7],b[2],c1,c2,c3);
1381 $LD r6,`7*$BNSZ`(r4)
1382 $LD r7,`2*$BNSZ`(r5)
1388 $ST r10,`9*$BNSZ`(r3) #r[9]=c1;
1389 #mul_add_c(a[7],b[3],c2,c3,c1);
1390 $LD r7,`3*$BNSZ`(r5)
1396 #mul_add_c(a[6],b[4],c2,c3,c1);
1397 $LD r6,`6*$BNSZ`(r4)
1398 $LD r7,`4*$BNSZ`(r5)
1404 #mul_add_c(a[5],b[5],c2,c3,c1);
1405 $LD r6,`5*$BNSZ`(r4)
1406 $LD r7,`5*$BNSZ`(r5)
1412 #mul_add_c(a[4],b[6],c2,c3,c1);
1413 $LD r6,`4*$BNSZ`(r4)
1414 $LD r7,`6*$BNSZ`(r5)
1420 #mul_add_c(a[3],b[7],c2,c3,c1);
1421 $LD r6,`3*$BNSZ`(r4)
1422 $LD r7,`7*$BNSZ`(r5)
1428 $ST r11,`10*$BNSZ`(r3) #r[10]=c2;
1429 #mul_add_c(a[4],b[7],c3,c1,c2);
1430 $LD r6,`4*$BNSZ`(r4)
1436 #mul_add_c(a[5],b[6],c3,c1,c2);
1437 $LD r6,`5*$BNSZ`(r4)
1438 $LD r7,`6*$BNSZ`(r5)
1444 #mul_add_c(a[6],b[5],c3,c1,c2);
1445 $LD r6,`6*$BNSZ`(r4)
1446 $LD r7,`5*$BNSZ`(r5)
1452 #mul_add_c(a[7],b[4],c3,c1,c2);
1453 $LD r6,`7*$BNSZ`(r4)
1454 $LD r7,`4*$BNSZ`(r5)
1460 $ST r12,`11*$BNSZ`(r3) #r[11]=c3;
1461 #mul_add_c(a[7],b[5],c1,c2,c3);
1462 $LD r7,`5*$BNSZ`(r5)
1468 #mul_add_c(a[6],b[6],c1,c2,c3);
1469 $LD r6,`6*$BNSZ`(r4)
1470 $LD r7,`6*$BNSZ`(r5)
1476 #mul_add_c(a[5],b[7],c1,c2,c3);
1477 $LD r6,`5*$BNSZ`(r4)
1478 $LD r7,`7*$BNSZ`(r5)
1484 $ST r10,`12*$BNSZ`(r3) #r[12]=c1;
1485 #mul_add_c(a[6],b[7],c2,c3,c1);
1486 $LD r6,`6*$BNSZ`(r4)
1492 #mul_add_c(a[7],b[6],c2,c3,c1);
1493 $LD r6,`7*$BNSZ`(r4)
1494 $LD r7,`6*$BNSZ`(r5)
1500 $ST r11,`13*$BNSZ`(r3) #r[13]=c2;
1501 #mul_add_c(a[7],b[7],c3,c1,c2);
1502 $LD r7,`7*$BNSZ`(r5)
1507 $ST r12,`14*$BNSZ`(r3) #r[14]=c3;
1508 $ST r10,`15*$BNSZ`(r3) #r[15]=c1;
1511 .byte 0,12,0x14,0,0,0,3,0
1515 # NOTE: The following label name should be changed to
1516 # "bn_sub_words" i.e. remove the first dot
1517 # for the gcc compiler. This should be automatically
1524 # Handcoded version of bn_sub_words
1526 #BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
1533 # Note: No loop unrolling done since this is not a performance
1536 xor r0,r0,r0 #set r0 = 0
1538 # check for r6 = 0 AND set carry bit.
1540 subfc. r7,r0,r6 # If r6 is 0 then result is 0.
1541 # if r6 > 0 then result !=0
1542 # In either case carry bit is set.
1543 beq Lppcasm_sub_adios
1548 Lppcasm_sub_mainloop:
1551 subfe r6,r8,r7 # r6 = r7+carry bit + onescomplement(r8)
1552 # if carry = 1 this is r7-r8. Else it
1553 # is r7-r8 -1 as we need.
1555 bdnz- Lppcasm_sub_mainloop
1557 subfze r3,r0 # if carry bit is set then r3 = 0 else -1
1558 andi. r3,r3,1 # keep only last bit.
1561 .byte 0,12,0x14,0,0,0,4,0
1565 # NOTE: The following label name should be changed to
1566 # "bn_add_words" i.e. remove the first dot
1567 # for the gcc compiler. This should be automatically
1574 # Handcoded version of bn_add_words
1576 #BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
1583 # Note: No loop unrolling done since this is not a performance
1588 # check for r6 = 0. Is this needed?
1590 addic. r6,r6,0 #test r6 and clear carry bit.
1591 beq Lppcasm_add_adios
1596 Lppcasm_add_mainloop:
1601 bdnz- Lppcasm_add_mainloop
1603 addze r3,r0 #return carry bit.
1606 .byte 0,12,0x14,0,0,0,4,0
1610 # NOTE: The following label name should be changed to
1611 # "bn_div_words" i.e. remove the first dot
1612 # for the gcc compiler. This should be automatically
1619 # This is a cleaned up version of code generated by
1620 # the AIX compiler. The only optimization is to use
1621 # the PPC instruction to count leading zeros instead
1622 # of call to num_bits_word. Since this was compiled
1623 # only at level -O2 we can possibly squeeze it more?
1629 $UCMPI 0,r5,0 # compare r5 and 0
1630 bne Lppcasm_div1 # proceed if d!=0
1631 li r3,-1 # d=0 return -1
1636 $CNTLZ. r7,r5 #r7 = num leading 0s in d.
1637 beq Lppcasm_div2 #proceed if no leading zeros
1638 subf r8,r7,r8 #r8 = BN_num_bits_word(d)
1639 $SHR. r9,r3,r8 #are there any bits above r8'th?
1640 $TR 16,r9,r0 #if there're, signal to dump core...
1642 $UCMP 0,r3,r5 #h>=d?
1643 blt Lppcasm_div3 #goto Lppcasm_div3 if not
1644 subf r3,r5,r3 #h-=d ;
1645 Lppcasm_div3: #r7 = BN_BITS2-i. so r7=i
1646 cmpi 0,0,r7,0 # is (i == 0)?
1648 $SHL r3,r3,r7 # h = (h<< i)
1649 $SHR r8,r4,r8 # r8 = (l >> BN_BITS2 -i)
1650 $SHL r5,r5,r7 # d<<=i
1651 or r3,r3,r8 # h = (h<<i)|(l>>(BN_BITS2-i))
1652 $SHL r4,r4,r7 # l <<=i
1654 $SHRI r9,r5,`$BITS/2` # r9 = dh
1655 # dl will be computed when needed
1656 # as it saves registers.
1658 mtctr r6 #counter will be in count.
1659 Lppcasm_divouterloop:
1660 $SHRI r8,r3,`$BITS/2` #r8 = (h>>BN_BITS4)
1661 $SHRI r11,r4,`$BITS/2` #r11= (l&BN_MASK2h)>>BN_BITS4
1662 # compute here for innerloop.
1663 $UCMP 0,r8,r9 # is (h>>BN_BITS4)==dh
1664 bne Lppcasm_div5 # goto Lppcasm_div5 if not
1667 $CLRU r8,r8,`$BITS/2` #q = BN_MASK2l
1670 $UDIV r8,r3,r9 #q = h/dh
1672 $UMULL r12,r9,r8 #th = q*dh
1673 $CLRU r10,r5,`$BITS/2` #r10=dl
1674 $UMULL r6,r8,r10 #tl = q*dl
1676 Lppcasm_divinnerloop:
1677 subf r10,r12,r3 #t = h -th
1678 $SHRI r7,r10,`$BITS/2` #r7= (t &BN_MASK2H), sort of...
1679 addic. r7,r7,0 #test if r7 == 0. used below.
1680 # now want to compute
1681 # r7 = (t<<BN_BITS4)|((l&BN_MASK2h)>>BN_BITS4)
1682 # the following 2 instructions do that
1683 $SHLI r7,r10,`$BITS/2` # r7 = (t<<BN_BITS4)
1684 or r7,r7,r11 # r7|=((l&BN_MASK2h)>>BN_BITS4)
1685 $UCMP cr1,r6,r7 # compare (tl <= r7)
1686 bne Lppcasm_divinnerexit
1687 ble cr1,Lppcasm_divinnerexit
1689 subf r12,r9,r12 #th -=dh
1690 $CLRU r10,r5,`$BITS/2` #r10=dl. t is no longer needed in loop.
1691 subf r6,r10,r6 #tl -=dl
1692 b Lppcasm_divinnerloop
1693 Lppcasm_divinnerexit:
1694 $SHRI r10,r6,`$BITS/2` #t=(tl>>BN_BITS4)
1695 $SHLI r11,r6,`$BITS/2` #tl=(tl<<BN_BITS4)&BN_MASK2h;
1696 $UCMP cr1,r4,r11 # compare l and tl
1697 add r12,r12,r10 # th+=t
1698 bge cr1,Lppcasm_div7 # if (l>=tl) goto Lppcasm_div7
1699 addi r12,r12,1 # th++
1701 subf r11,r11,r4 #r11=l-tl
1702 $UCMP cr1,r3,r12 #compare h and th
1703 bge cr1,Lppcasm_div8 #if (h>=th) goto Lppcasm_div8
1707 subf r12,r12,r3 #r12 = h-th
1708 $SHLI r4,r11,`$BITS/2` #l=(l&BN_MASK2l)<<BN_BITS4
1710 # h = ((h<<BN_BITS4)|(l>>BN_BITS4))&BN_MASK2
1711 # the following 2 instructions will do this.
1712 $INSR r11,r12,`$BITS/2`,`$BITS/2` # r11 is the value we want rotated $BITS/2.
1713 $ROTL r3,r11,`$BITS/2` # rotate by $BITS/2 and store in r3
1714 bdz Lppcasm_div9 #if (count==0) break ;
1715 $SHLI r0,r8,`$BITS/2` #ret =q<<BN_BITS4
1716 b Lppcasm_divouterloop
1721 .byte 0,12,0x14,0,0,0,3,0
1725 # NOTE: The following label name should be changed to
1726 # "bn_sqr_words" i.e. remove the first dot
1727 # for the gcc compiler. This should be automatically
1733 # Optimized version of bn_sqr_words
1735 # void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
1744 # No unrolling done here. Not performance critical.
1746 addic. r5,r5,0 #test r5.
1747 beq Lppcasm_sqr_adios
1751 Lppcasm_sqr_mainloop:
1752 #sqr(r[0],r[1],a[0]);
1758 bdnz- Lppcasm_sqr_mainloop
1762 .byte 0,12,0x14,0,0,0,3,0
1766 # NOTE: The following label name should be changed to
1767 # "bn_mul_words" i.e. remove the first dot
1768 # for the gcc compiler. This should be automatically
1775 # BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
1782 xor r12,r12,r12 # used for carry
1783 rlwinm. r7,r5,30,2,31 # num >> 2
1787 #mul(rp[0],ap[0],w,c1);
1788 $LD r8,`0*$BNSZ`(r4)
1792 #addze r10,r10 #carry is NOT ignored.
1793 #will be taken care of
1794 #in second spin below
1796 $ST r9,`0*$BNSZ`(r3)
1797 #mul(rp[1],ap[1],w,c1);
1798 $LD r8,`1*$BNSZ`(r4)
1803 $ST r11,`1*$BNSZ`(r3)
1804 #mul(rp[2],ap[2],w,c1);
1805 $LD r8,`2*$BNSZ`(r4)
1810 $ST r9,`2*$BNSZ`(r3)
1811 #mul_add(rp[3],ap[3],w,c1);
1812 $LD r8,`3*$BNSZ`(r4)
1816 addze r12,r12 #this spin we collect carry into
1818 $ST r11,`3*$BNSZ`(r3)
1820 addi r3,r3,`4*$BNSZ`
1821 addi r4,r4,`4*$BNSZ`
1822 bdnz- Lppcasm_mw_LOOP
1827 #mul(rp[0],ap[0],w,c1);
1828 $LD r8,`0*$BNSZ`(r4)
1833 $ST r9,`0*$BNSZ`(r3)
1841 #mul(rp[1],ap[1],w,c1);
1842 $LD r8,`1*$BNSZ`(r4)
1847 $ST r9,`1*$BNSZ`(r3)
1854 #mul_add(rp[2],ap[2],w,c1);
1855 $LD r8,`2*$BNSZ`(r4)
1860 $ST r9,`2*$BNSZ`(r3)
1867 .byte 0,12,0x14,0,0,0,4,0
1871 # NOTE: The following label name should be changed to
1872 # "bn_mul_add_words" i.e. remove the first dot
1873 # for the gcc compiler. This should be automatically
1880 # BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
1887 # empirical evidence suggests that unrolled version performs best!!
1889 xor r0,r0,r0 #r0 = 0
1890 xor r12,r12,r12 #r12 = 0 . used for carry
1891 rlwinm. r7,r5,30,2,31 # num >> 2
1892 beq Lppcasm_maw_leftover # if (num < 4) go LPPCASM_maw_leftover
1894 Lppcasm_maw_mainloop:
1895 #mul_add(rp[0],ap[0],w,c1);
1896 $LD r8,`0*$BNSZ`(r4)
1897 $LD r11,`0*$BNSZ`(r3)
1900 addc r9,r9,r12 #r12 is carry.
1904 #the above instruction addze
1905 #is NOT needed. Carry will NOT
1906 #be ignored. It's not affected
1907 #by multiply and will be collected
1909 $ST r9,`0*$BNSZ`(r3)
1911 #mul_add(rp[1],ap[1],w,c1);
1912 $LD r8,`1*$BNSZ`(r4)
1913 $LD r9,`1*$BNSZ`(r3)
1916 adde r11,r11,r10 #r10 is carry.
1920 $ST r11,`1*$BNSZ`(r3)
1922 #mul_add(rp[2],ap[2],w,c1);
1923 $LD r8,`2*$BNSZ`(r4)
1925 $LD r11,`2*$BNSZ`(r3)
1931 $ST r9,`2*$BNSZ`(r3)
1933 #mul_add(rp[3],ap[3],w,c1);
1934 $LD r8,`3*$BNSZ`(r4)
1936 $LD r9,`3*$BNSZ`(r3)
1942 $ST r11,`3*$BNSZ`(r3)
1943 addi r3,r3,`4*$BNSZ`
1944 addi r4,r4,`4*$BNSZ`
1945 bdnz- Lppcasm_maw_mainloop
1947 Lppcasm_maw_leftover:
1949 beq Lppcasm_maw_adios
1952 #mul_add(rp[0],ap[0],w,c1);
1964 bdz Lppcasm_maw_adios
1965 #mul_add(rp[1],ap[1],w,c1);
1976 bdz Lppcasm_maw_adios
1977 #mul_add(rp[2],ap[2],w,c1);
1992 .byte 0,12,0x14,0,0,0,4,0
1996 $data =~ s/\`([^\`]*)\`/eval $1/gem;