2 # Copyright 2004-2018 The OpenSSL Project Authors. All Rights Reserved.
4 # Licensed under the Apache License 2.0 (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
9 # Implemented as a Perl wrapper as we want to support several different
10 # architectures with single file. We pick up the target based on the
11 # file name we are asked to generate.
13 # It should be noted though that this perl code is nothing like
14 # <openssl>/crypto/perlasm/x86*. In this case perl is used pretty much
15 # as pre-processor to cover for platform differences in name decoration,
16 # linker tables, 32-/64-bit instruction sets...
18 # As you might know there're several PowerPC ABI in use. Most notably
19 # Linux and AIX use different 32-bit ABIs. Good news are that these ABIs
20 # are similar enough to implement leaf(!) functions, which would be ABI
21 # neutral. And that's what you find here: ABI neutral leaf functions.
22 # In case you wonder what that is...
26 # MEASUREMENTS WITH cc ON a 200 MhZ PowerPC 604e.
28 # The following is the performance of 32-bit compiler
31 # OpenSSL 0.9.6c 21 dec 2001
32 # built on: Tue Jun 11 11:06:51 EDT 2002
33 # options:bn(64,32) ...
34 #compiler: cc -DTHREADS -DAIX -DB_ENDIAN -DBN_LLONG -O3
35 # sign verify sign/s verify/s
36 #rsa 512 bits 0.0098s 0.0009s 102.0 1170.6
37 #rsa 1024 bits 0.0507s 0.0026s 19.7 387.5
38 #rsa 2048 bits 0.3036s 0.0085s 3.3 117.1
39 #rsa 4096 bits 2.0040s 0.0299s 0.5 33.4
40 #dsa 512 bits 0.0087s 0.0106s 114.3 94.5
41 #dsa 1024 bits 0.0256s 0.0313s 39.0 32.0
43 # Same benchmark with this assembler code:
45 #rsa 512 bits 0.0056s 0.0005s 178.6 2049.2
46 #rsa 1024 bits 0.0283s 0.0015s 35.3 674.1
47 #rsa 2048 bits 0.1744s 0.0050s 5.7 201.2
48 #rsa 4096 bits 1.1644s 0.0179s 0.9 55.7
49 #dsa 512 bits 0.0052s 0.0062s 191.6 162.0
50 #dsa 1024 bits 0.0149s 0.0180s 67.0 55.5
52 # Number of operations increases by at almost 75%
54 # Here are performance numbers for 64-bit compiler
57 # OpenSSL 0.9.6g [engine] 9 Aug 2002
58 # built on: Fri Apr 18 16:59:20 EDT 2003
59 # options:bn(64,64) ...
60 # compiler: cc -DTHREADS -D_REENTRANT -q64 -DB_ENDIAN -O3
61 # sign verify sign/s verify/s
62 #rsa 512 bits 0.0028s 0.0003s 357.1 3844.4
63 #rsa 1024 bits 0.0148s 0.0008s 67.5 1239.7
64 #rsa 2048 bits 0.0963s 0.0028s 10.4 353.0
65 #rsa 4096 bits 0.6538s 0.0102s 1.5 98.1
66 #dsa 512 bits 0.0026s 0.0032s 382.5 313.7
67 #dsa 1024 bits 0.0081s 0.0099s 122.8 100.6
69 # Same benchmark with this assembler code:
71 #rsa 512 bits 0.0020s 0.0002s 510.4 6273.7
72 #rsa 1024 bits 0.0088s 0.0005s 114.1 2128.3
73 #rsa 2048 bits 0.0540s 0.0016s 18.5 622.5
74 #rsa 4096 bits 0.3700s 0.0058s 2.7 171.0
75 #dsa 512 bits 0.0016s 0.0020s 610.7 507.1
76 #dsa 1024 bits 0.0047s 0.0058s 212.5 173.2
78 # Again, performance increases by at about 75%
80 # Mac OS X, Apple G5 1.8GHz (Note this is 32 bit code)
81 # OpenSSL 0.9.7c 30 Sep 2003
85 #rsa 512 bits 0.0011s 0.0001s 906.1 11012.5
86 #rsa 1024 bits 0.0060s 0.0003s 166.6 3363.1
87 #rsa 2048 bits 0.0370s 0.0010s 27.1 982.4
88 #rsa 4096 bits 0.2426s 0.0036s 4.1 280.4
89 #dsa 512 bits 0.0010s 0.0012s 1038.1 841.5
90 #dsa 1024 bits 0.0030s 0.0037s 329.6 269.7
91 #dsa 2048 bits 0.0101s 0.0127s 98.9 78.6
93 # Same benchmark with this assembler code:
95 #rsa 512 bits 0.0007s 0.0001s 1416.2 16645.9
96 #rsa 1024 bits 0.0036s 0.0002s 274.4 5380.6
97 #rsa 2048 bits 0.0222s 0.0006s 45.1 1589.5
98 #rsa 4096 bits 0.1469s 0.0022s 6.8 449.6
99 #dsa 512 bits 0.0006s 0.0007s 1664.2 1376.2
100 #dsa 1024 bits 0.0018s 0.0023s 545.0 442.2
101 #dsa 2048 bits 0.0061s 0.0075s 163.5 132.8
103 # Performance increase of ~60%
104 # Based on submission from Suresh N. Chari of IBM
108 if ($flavour =~ /32/) {
114 $LDU= "lwzu"; # load and update
116 $STU= "stwu"; # store and update
117 $UMULL= "mullw"; # unsigned multiply low
118 $UMULH= "mulhwu"; # unsigned multiply high
119 $UDIV= "divwu"; # unsigned divide
120 $UCMPI= "cmplwi"; # unsigned compare with immediate
121 $UCMP= "cmplw"; # unsigned compare
122 $CNTLZ= "cntlzw"; # count leading zeros
123 $SHL= "slw"; # shift left
124 $SHR= "srw"; # unsigned shift right
125 $SHRI= "srwi"; # unsigned shift right by immediate
126 $SHLI= "slwi"; # shift left by immediate
127 $CLRU= "clrlwi"; # clear upper bits
128 $INSR= "insrwi"; # insert right
129 $ROTL= "rotlwi"; # rotate left by immediate
130 $TR= "tw"; # conditional trap
131 } elsif ($flavour =~ /64/) {
136 # same as above, but 64-bit mnemonics...
138 $LDU= "ldu"; # load and update
140 $STU= "stdu"; # store and update
141 $UMULL= "mulld"; # unsigned multiply low
142 $UMULH= "mulhdu"; # unsigned multiply high
143 $UDIV= "divdu"; # unsigned divide
144 $UCMPI= "cmpldi"; # unsigned compare with immediate
145 $UCMP= "cmpld"; # unsigned compare
146 $CNTLZ= "cntlzd"; # count leading zeros
147 $SHL= "sld"; # shift left
148 $SHR= "srd"; # unsigned shift right
149 $SHRI= "srdi"; # unsigned shift right by immediate
150 $SHLI= "sldi"; # shift left by immediate
151 $CLRU= "clrldi"; # clear upper bits
152 $INSR= "insrdi"; # insert right
153 $ROTL= "rotldi"; # rotate left by immediate
154 $TR= "td"; # conditional trap
155 } else { die "nonsense $flavour"; }
157 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
158 ( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or
159 ( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or
160 die "can't locate ppc-xlate.pl";
162 open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
165 #--------------------------------------------------------------------
172 # Created by: Suresh Chari
173 # IBM Thomas J. Watson Research Library
177 # Description: Optimized assembly routines for OpenSSL crypto
178 # on the 32 bitPowerPC platform.
183 # 2. Fixed bn_add,bn_sub and bn_div_words, added comments,
184 # cleaned up code. Also made a single version which can
185 # be used for both the AIX and Linux compilers. See NOTE
187 # 12/05/03 Suresh Chari
188 # (with lots of help from) Andy Polyakov
190 # 1. Initial version 10/20/02 Suresh Chari
193 # The following file works for the xlc,cc
196 # NOTE: To get the file to link correctly with the gcc compiler
197 # you have to change the names of the routines and remove
198 # the first .(dot) character. This should automatically
199 # be done in the build process.
201 # Hand optimized assembly code for the following routines
214 # NOTE: It is possible to optimize this code more for
215 # specific PowerPC or Power architectures. On the Northstar
216 # architecture the optimizations in this file do
217 # NOT provide much improvement.
219 # If you have comments or suggestions to improve code send
220 # me a note at schari\@us.ibm.com
222 #--------------------------------------------------------------------------
224 # Defines to be used in the assembly code.
226 #.set r0,0 # we use it as storage for value of 0
227 #.set SP,1 # preserved
228 #.set RTOC,2 # preserved
229 #.set r3,3 # 1st argument/return value
230 #.set r4,4 # 2nd argument/volatile register
231 #.set r5,5 # 3rd argument/volatile register
239 #.set r13,13 # not used, nor any other "below" it...
241 # Declare function names to be global
242 # NOTE: For gcc these names MUST be changed to remove
243 # the first . i.e. for example change ".bn_sqr_comba4"
244 # to "bn_sqr_comba4". This should be automatically done
247 .globl .bn_sqr_comba4
248 .globl .bn_sqr_comba8
249 .globl .bn_mul_comba4
250 .globl .bn_mul_comba8
256 .globl .bn_mul_add_words
263 # NOTE: The following label name should be changed to
264 # "bn_sqr_comba4" i.e. remove the first dot
265 # for the gcc compiler. This should be automatically
272 # Optimized version of bn_sqr_comba4.
274 # void bn_sqr_comba4(BN_ULONG *r, BN_ULONG *a)
278 # Freely use registers r5,r6,r7,r8,r9,r10,r11 as follows:
280 # r5,r6 are the two BN_ULONGs being multiplied.
281 # r7,r8 are the results of the 32x32 giving 64 bit multiply.
282 # r9,r10, r11 are the equivalents of c1,c2, c3.
283 # Here's the assembly
286 xor r0,r0,r0 # set r0 = 0. Used in the addze
289 #sqr_add_c(a,0,c1,c2,c3)
292 $UMULH r10,r5,r5 #in first iteration. No need
293 #to add since c1=c2=c3=0.
294 # Note c3(r11) is NOT set to 0
297 $ST r9,`0*$BNSZ`(r3) # r[0]=c1;
298 # sqr_add_c2(a,1,0,c2,c3,c1);
303 addc r7,r7,r7 # compute (r7,r8)=2*(r7,r8)
305 addze r9,r0 # catch carry if any.
306 # r9= r0(=0) and carry
308 addc r10,r7,r10 # now add to temp result.
309 addze r11,r8 # r8 added to r11 which is 0
312 $ST r10,`1*$BNSZ`(r3) #r[1]=c2;
313 #sqr_add_c(a,1,c3,c1,c2)
319 #sqr_add_c2(a,2,0,c3,c1,c2)
331 $ST r11,`2*$BNSZ`(r3) #r[2]=c3
332 #sqr_add_c2(a,3,0,c1,c2,c3);
343 #sqr_add_c2(a,2,1,c1,c2,c3);
355 $ST r9,`3*$BNSZ`(r3) #r[3]=c1
356 #sqr_add_c(a,2,c2,c3,c1);
362 #sqr_add_c2(a,3,1,c2,c3,c1);
373 $ST r10,`4*$BNSZ`(r3) #r[4]=c2
374 #sqr_add_c2(a,3,2,c3,c1,c2);
385 $ST r11,`5*$BNSZ`(r3) #r[5] = c3
386 #sqr_add_c(a,3,c1,c2,c3);
392 $ST r9,`6*$BNSZ`(r3) #r[6]=c1
393 $ST r10,`7*$BNSZ`(r3) #r[7]=c2
396 .byte 0,12,0x14,0,0,0,2,0
398 .size .bn_sqr_comba4,.-.bn_sqr_comba4
401 # NOTE: The following label name should be changed to
402 # "bn_sqr_comba8" i.e. remove the first dot
403 # for the gcc compiler. This should be automatically
410 # This is an optimized version of the bn_sqr_comba8 routine.
411 # Tightly uses the adde instruction
414 # void bn_sqr_comba8(BN_ULONG *r, BN_ULONG *a)
418 # Freely use registers r5,r6,r7,r8,r9,r10,r11 as follows:
420 # r5,r6 are the two BN_ULONGs being multiplied.
421 # r7,r8 are the results of the 32x32 giving 64 bit multiply.
422 # r9,r10, r11 are the equivalents of c1,c2, c3.
424 # Possible optimization of loading all 8 longs of a into registers
425 # doesn't provide any speedup
428 xor r0,r0,r0 #set r0 = 0.Used in addze
431 #sqr_add_c(a,0,c1,c2,c3);
433 $UMULL r9,r5,r5 #1st iteration: no carries.
435 $ST r9,`0*$BNSZ`(r3) # r[0]=c1;
436 #sqr_add_c2(a,1,0,c2,c3,c1);
441 addc r10,r7,r10 #add the two register number
442 adde r11,r8,r0 # (r8,r7) to the three register
443 addze r9,r0 # number (r9,r11,r10).NOTE:r0=0
445 addc r10,r7,r10 #add the two register number
446 adde r11,r8,r11 # (r8,r7) to the three register
447 addze r9,r9 # number (r9,r11,r10).
449 $ST r10,`1*$BNSZ`(r3) # r[1]=c2
451 #sqr_add_c(a,1,c3,c1,c2);
457 #sqr_add_c2(a,2,0,c3,c1,c2);
470 $ST r11,`2*$BNSZ`(r3) #r[2]=c3
471 #sqr_add_c2(a,3,0,c1,c2,c3);
472 $LD r6,`3*$BNSZ`(r4) #r6 = a[3]. r5 is already a[0].
483 #sqr_add_c2(a,2,1,c1,c2,c3);
497 $ST r9,`3*$BNSZ`(r3) #r[3]=c1;
498 #sqr_add_c(a,2,c2,c3,c1);
505 #sqr_add_c2(a,3,1,c2,c3,c1);
517 #sqr_add_c2(a,4,0,c2,c3,c1);
530 $ST r10,`4*$BNSZ`(r3) #r[4]=c2;
531 #sqr_add_c2(a,5,0,c3,c1,c2);
543 #sqr_add_c2(a,4,1,c3,c1,c2);
556 #sqr_add_c2(a,3,2,c3,c1,c2);
569 $ST r11,`5*$BNSZ`(r3) #r[5]=c3;
570 #sqr_add_c(a,3,c1,c2,c3);
576 #sqr_add_c2(a,4,2,c1,c2,c3);
588 #sqr_add_c2(a,5,1,c1,c2,c3);
601 #sqr_add_c2(a,6,0,c1,c2,c3);
612 $ST r9,`6*$BNSZ`(r3) #r[6]=c1;
613 #sqr_add_c2(a,7,0,c2,c3,c1);
624 #sqr_add_c2(a,6,1,c2,c3,c1);
636 #sqr_add_c2(a,5,2,c2,c3,c1);
647 #sqr_add_c2(a,4,3,c2,c3,c1);
659 $ST r10,`7*$BNSZ`(r3) #r[7]=c2;
660 #sqr_add_c(a,4,c3,c1,c2);
666 #sqr_add_c2(a,5,3,c3,c1,c2);
676 #sqr_add_c2(a,6,2,c3,c1,c2);
688 #sqr_add_c2(a,7,1,c3,c1,c2);
699 $ST r11,`8*$BNSZ`(r3) #r[8]=c3;
700 #sqr_add_c2(a,7,2,c1,c2,c3);
711 #sqr_add_c2(a,6,3,c1,c2,c3);
722 #sqr_add_c2(a,5,4,c1,c2,c3);
733 $ST r9,`9*$BNSZ`(r3) #r[9]=c1;
734 #sqr_add_c(a,5,c2,c3,c1);
740 #sqr_add_c2(a,6,4,c2,c3,c1);
750 #sqr_add_c2(a,7,3,c2,c3,c1);
761 $ST r10,`10*$BNSZ`(r3) #r[10]=c2;
762 #sqr_add_c2(a,7,4,c3,c1,c2);
772 #sqr_add_c2(a,6,5,c3,c1,c2);
783 $ST r11,`11*$BNSZ`(r3) #r[11]=c3;
784 #sqr_add_c(a,6,c1,c2,c3);
790 #sqr_add_c2(a,7,5,c1,c2,c3)
800 $ST r9,`12*$BNSZ`(r3) #r[12]=c1;
802 #sqr_add_c2(a,7,6,c2,c3,c1)
812 $ST r10,`13*$BNSZ`(r3) #r[13]=c2;
813 #sqr_add_c(a,7,c3,c1,c2);
818 $ST r11,`14*$BNSZ`(r3) #r[14]=c3;
819 $ST r9, `15*$BNSZ`(r3) #r[15]=c1;
824 .byte 0,12,0x14,0,0,0,2,0
826 .size .bn_sqr_comba8,.-.bn_sqr_comba8
829 # NOTE: The following label name should be changed to
830 # "bn_mul_comba4" i.e. remove the first dot
831 # for the gcc compiler. This should be automatically
838 # This is an optimized version of the bn_mul_comba4 routine.
840 # void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
844 # r6, r7 are the 2 BN_ULONGs being multiplied.
845 # r8, r9 are the results of the 32x32 giving 64 multiply.
846 # r10, r11, r12 are the equivalents of c1, c2, and c3.
848 xor r0,r0,r0 #r0=0. Used in addze below.
849 #mul_add_c(a[0],b[0],c1,c2,c3);
854 $ST r10,`0*$BNSZ`(r3) #r[0]=c1
855 #mul_add_c(a[0],b[1],c2,c3,c1);
862 #mul_add_c(a[1],b[0],c2,c3,c1);
863 $LD r6, `1*$BNSZ`(r4)
864 $LD r7, `0*$BNSZ`(r5)
870 $ST r11,`1*$BNSZ`(r3) #r[1]=c2
871 #mul_add_c(a[2],b[0],c3,c1,c2);
878 #mul_add_c(a[1],b[1],c3,c1,c2);
886 #mul_add_c(a[0],b[2],c3,c1,c2);
894 $ST r12,`2*$BNSZ`(r3) #r[2]=c3
895 #mul_add_c(a[0],b[3],c1,c2,c3);
902 #mul_add_c(a[1],b[2],c1,c2,c3);
910 #mul_add_c(a[2],b[1],c1,c2,c3);
918 #mul_add_c(a[3],b[0],c1,c2,c3);
926 $ST r10,`3*$BNSZ`(r3) #r[3]=c1
927 #mul_add_c(a[3],b[1],c2,c3,c1);
934 #mul_add_c(a[2],b[2],c2,c3,c1);
942 #mul_add_c(a[1],b[3],c2,c3,c1);
950 $ST r11,`4*$BNSZ`(r3) #r[4]=c2
951 #mul_add_c(a[2],b[3],c3,c1,c2);
958 #mul_add_c(a[3],b[2],c3,c1,c2);
966 $ST r12,`5*$BNSZ`(r3) #r[5]=c3
967 #mul_add_c(a[3],b[3],c1,c2,c3);
974 $ST r10,`6*$BNSZ`(r3) #r[6]=c1
975 $ST r11,`7*$BNSZ`(r3) #r[7]=c2
978 .byte 0,12,0x14,0,0,0,3,0
980 .size .bn_mul_comba4,.-.bn_mul_comba4
983 # NOTE: The following label name should be changed to
984 # "bn_mul_comba8" i.e. remove the first dot
985 # for the gcc compiler. This should be automatically
992 # Optimized version of the bn_mul_comba8 routine.
994 # void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b)
998 # r6, r7 are the 2 BN_ULONGs being multiplied.
999 # r8, r9 are the results of the 32x32 giving 64 multiply.
1000 # r10, r11, r12 are the equivalents of c1, c2, and c3.
1002 xor r0,r0,r0 #r0=0. Used in addze below.
1004 #mul_add_c(a[0],b[0],c1,c2,c3);
1005 $LD r6,`0*$BNSZ`(r4) #a[0]
1006 $LD r7,`0*$BNSZ`(r5) #b[0]
1009 $ST r10,`0*$BNSZ`(r3) #r[0]=c1;
1010 #mul_add_c(a[0],b[1],c2,c3,c1);
1011 $LD r7,`1*$BNSZ`(r5)
1015 addze r12,r9 # since we didn't set r12 to zero before.
1017 #mul_add_c(a[1],b[0],c2,c3,c1);
1018 $LD r6,`1*$BNSZ`(r4)
1019 $LD r7,`0*$BNSZ`(r5)
1025 $ST r11,`1*$BNSZ`(r3) #r[1]=c2;
1026 #mul_add_c(a[2],b[0],c3,c1,c2);
1027 $LD r6,`2*$BNSZ`(r4)
1033 #mul_add_c(a[1],b[1],c3,c1,c2);
1034 $LD r6,`1*$BNSZ`(r4)
1035 $LD r7,`1*$BNSZ`(r5)
1041 #mul_add_c(a[0],b[2],c3,c1,c2);
1042 $LD r6,`0*$BNSZ`(r4)
1043 $LD r7,`2*$BNSZ`(r5)
1049 $ST r12,`2*$BNSZ`(r3) #r[2]=c3;
1050 #mul_add_c(a[0],b[3],c1,c2,c3);
1051 $LD r7,`3*$BNSZ`(r5)
1057 #mul_add_c(a[1],b[2],c1,c2,c3);
1058 $LD r6,`1*$BNSZ`(r4)
1059 $LD r7,`2*$BNSZ`(r5)
1066 #mul_add_c(a[2],b[1],c1,c2,c3);
1067 $LD r6,`2*$BNSZ`(r4)
1068 $LD r7,`1*$BNSZ`(r5)
1074 #mul_add_c(a[3],b[0],c1,c2,c3);
1075 $LD r6,`3*$BNSZ`(r4)
1076 $LD r7,`0*$BNSZ`(r5)
1082 $ST r10,`3*$BNSZ`(r3) #r[3]=c1;
1083 #mul_add_c(a[4],b[0],c2,c3,c1);
1084 $LD r6,`4*$BNSZ`(r4)
1090 #mul_add_c(a[3],b[1],c2,c3,c1);
1091 $LD r6,`3*$BNSZ`(r4)
1092 $LD r7,`1*$BNSZ`(r5)
1098 #mul_add_c(a[2],b[2],c2,c3,c1);
1099 $LD r6,`2*$BNSZ`(r4)
1100 $LD r7,`2*$BNSZ`(r5)
1106 #mul_add_c(a[1],b[3],c2,c3,c1);
1107 $LD r6,`1*$BNSZ`(r4)
1108 $LD r7,`3*$BNSZ`(r5)
1114 #mul_add_c(a[0],b[4],c2,c3,c1);
1115 $LD r6,`0*$BNSZ`(r4)
1116 $LD r7,`4*$BNSZ`(r5)
1122 $ST r11,`4*$BNSZ`(r3) #r[4]=c2;
1123 #mul_add_c(a[0],b[5],c3,c1,c2);
1124 $LD r7,`5*$BNSZ`(r5)
1130 #mul_add_c(a[1],b[4],c3,c1,c2);
1131 $LD r6,`1*$BNSZ`(r4)
1132 $LD r7,`4*$BNSZ`(r5)
1138 #mul_add_c(a[2],b[3],c3,c1,c2);
1139 $LD r6,`2*$BNSZ`(r4)
1140 $LD r7,`3*$BNSZ`(r5)
1146 #mul_add_c(a[3],b[2],c3,c1,c2);
1147 $LD r6,`3*$BNSZ`(r4)
1148 $LD r7,`2*$BNSZ`(r5)
1154 #mul_add_c(a[4],b[1],c3,c1,c2);
1155 $LD r6,`4*$BNSZ`(r4)
1156 $LD r7,`1*$BNSZ`(r5)
1162 #mul_add_c(a[5],b[0],c3,c1,c2);
1163 $LD r6,`5*$BNSZ`(r4)
1164 $LD r7,`0*$BNSZ`(r5)
1170 $ST r12,`5*$BNSZ`(r3) #r[5]=c3;
1171 #mul_add_c(a[6],b[0],c1,c2,c3);
1172 $LD r6,`6*$BNSZ`(r4)
1178 #mul_add_c(a[5],b[1],c1,c2,c3);
1179 $LD r6,`5*$BNSZ`(r4)
1180 $LD r7,`1*$BNSZ`(r5)
1186 #mul_add_c(a[4],b[2],c1,c2,c3);
1187 $LD r6,`4*$BNSZ`(r4)
1188 $LD r7,`2*$BNSZ`(r5)
1194 #mul_add_c(a[3],b[3],c1,c2,c3);
1195 $LD r6,`3*$BNSZ`(r4)
1196 $LD r7,`3*$BNSZ`(r5)
1202 #mul_add_c(a[2],b[4],c1,c2,c3);
1203 $LD r6,`2*$BNSZ`(r4)
1204 $LD r7,`4*$BNSZ`(r5)
1210 #mul_add_c(a[1],b[5],c1,c2,c3);
1211 $LD r6,`1*$BNSZ`(r4)
1212 $LD r7,`5*$BNSZ`(r5)
1218 #mul_add_c(a[0],b[6],c1,c2,c3);
1219 $LD r6,`0*$BNSZ`(r4)
1220 $LD r7,`6*$BNSZ`(r5)
1226 $ST r10,`6*$BNSZ`(r3) #r[6]=c1;
1227 #mul_add_c(a[0],b[7],c2,c3,c1);
1228 $LD r7,`7*$BNSZ`(r5)
1234 #mul_add_c(a[1],b[6],c2,c3,c1);
1235 $LD r6,`1*$BNSZ`(r4)
1236 $LD r7,`6*$BNSZ`(r5)
1242 #mul_add_c(a[2],b[5],c2,c3,c1);
1243 $LD r6,`2*$BNSZ`(r4)
1244 $LD r7,`5*$BNSZ`(r5)
1250 #mul_add_c(a[3],b[4],c2,c3,c1);
1251 $LD r6,`3*$BNSZ`(r4)
1252 $LD r7,`4*$BNSZ`(r5)
1258 #mul_add_c(a[4],b[3],c2,c3,c1);
1259 $LD r6,`4*$BNSZ`(r4)
1260 $LD r7,`3*$BNSZ`(r5)
1266 #mul_add_c(a[5],b[2],c2,c3,c1);
1267 $LD r6,`5*$BNSZ`(r4)
1268 $LD r7,`2*$BNSZ`(r5)
1274 #mul_add_c(a[6],b[1],c2,c3,c1);
1275 $LD r6,`6*$BNSZ`(r4)
1276 $LD r7,`1*$BNSZ`(r5)
1282 #mul_add_c(a[7],b[0],c2,c3,c1);
1283 $LD r6,`7*$BNSZ`(r4)
1284 $LD r7,`0*$BNSZ`(r5)
1290 $ST r11,`7*$BNSZ`(r3) #r[7]=c2;
1291 #mul_add_c(a[7],b[1],c3,c1,c2);
1292 $LD r7,`1*$BNSZ`(r5)
1298 #mul_add_c(a[6],b[2],c3,c1,c2);
1299 $LD r6,`6*$BNSZ`(r4)
1300 $LD r7,`2*$BNSZ`(r5)
1306 #mul_add_c(a[5],b[3],c3,c1,c2);
1307 $LD r6,`5*$BNSZ`(r4)
1308 $LD r7,`3*$BNSZ`(r5)
1314 #mul_add_c(a[4],b[4],c3,c1,c2);
1315 $LD r6,`4*$BNSZ`(r4)
1316 $LD r7,`4*$BNSZ`(r5)
1322 #mul_add_c(a[3],b[5],c3,c1,c2);
1323 $LD r6,`3*$BNSZ`(r4)
1324 $LD r7,`5*$BNSZ`(r5)
1330 #mul_add_c(a[2],b[6],c3,c1,c2);
1331 $LD r6,`2*$BNSZ`(r4)
1332 $LD r7,`6*$BNSZ`(r5)
1338 #mul_add_c(a[1],b[7],c3,c1,c2);
1339 $LD r6,`1*$BNSZ`(r4)
1340 $LD r7,`7*$BNSZ`(r5)
1346 $ST r12,`8*$BNSZ`(r3) #r[8]=c3;
1347 #mul_add_c(a[2],b[7],c1,c2,c3);
1348 $LD r6,`2*$BNSZ`(r4)
1354 #mul_add_c(a[3],b[6],c1,c2,c3);
1355 $LD r6,`3*$BNSZ`(r4)
1356 $LD r7,`6*$BNSZ`(r5)
1362 #mul_add_c(a[4],b[5],c1,c2,c3);
1363 $LD r6,`4*$BNSZ`(r4)
1364 $LD r7,`5*$BNSZ`(r5)
1370 #mul_add_c(a[5],b[4],c1,c2,c3);
1371 $LD r6,`5*$BNSZ`(r4)
1372 $LD r7,`4*$BNSZ`(r5)
1378 #mul_add_c(a[6],b[3],c1,c2,c3);
1379 $LD r6,`6*$BNSZ`(r4)
1380 $LD r7,`3*$BNSZ`(r5)
1386 #mul_add_c(a[7],b[2],c1,c2,c3);
1387 $LD r6,`7*$BNSZ`(r4)
1388 $LD r7,`2*$BNSZ`(r5)
1394 $ST r10,`9*$BNSZ`(r3) #r[9]=c1;
1395 #mul_add_c(a[7],b[3],c2,c3,c1);
1396 $LD r7,`3*$BNSZ`(r5)
1402 #mul_add_c(a[6],b[4],c2,c3,c1);
1403 $LD r6,`6*$BNSZ`(r4)
1404 $LD r7,`4*$BNSZ`(r5)
1410 #mul_add_c(a[5],b[5],c2,c3,c1);
1411 $LD r6,`5*$BNSZ`(r4)
1412 $LD r7,`5*$BNSZ`(r5)
1418 #mul_add_c(a[4],b[6],c2,c3,c1);
1419 $LD r6,`4*$BNSZ`(r4)
1420 $LD r7,`6*$BNSZ`(r5)
1426 #mul_add_c(a[3],b[7],c2,c3,c1);
1427 $LD r6,`3*$BNSZ`(r4)
1428 $LD r7,`7*$BNSZ`(r5)
1434 $ST r11,`10*$BNSZ`(r3) #r[10]=c2;
1435 #mul_add_c(a[4],b[7],c3,c1,c2);
1436 $LD r6,`4*$BNSZ`(r4)
1442 #mul_add_c(a[5],b[6],c3,c1,c2);
1443 $LD r6,`5*$BNSZ`(r4)
1444 $LD r7,`6*$BNSZ`(r5)
1450 #mul_add_c(a[6],b[5],c3,c1,c2);
1451 $LD r6,`6*$BNSZ`(r4)
1452 $LD r7,`5*$BNSZ`(r5)
1458 #mul_add_c(a[7],b[4],c3,c1,c2);
1459 $LD r6,`7*$BNSZ`(r4)
1460 $LD r7,`4*$BNSZ`(r5)
1466 $ST r12,`11*$BNSZ`(r3) #r[11]=c3;
1467 #mul_add_c(a[7],b[5],c1,c2,c3);
1468 $LD r7,`5*$BNSZ`(r5)
1474 #mul_add_c(a[6],b[6],c1,c2,c3);
1475 $LD r6,`6*$BNSZ`(r4)
1476 $LD r7,`6*$BNSZ`(r5)
1482 #mul_add_c(a[5],b[7],c1,c2,c3);
1483 $LD r6,`5*$BNSZ`(r4)
1484 $LD r7,`7*$BNSZ`(r5)
1490 $ST r10,`12*$BNSZ`(r3) #r[12]=c1;
1491 #mul_add_c(a[6],b[7],c2,c3,c1);
1492 $LD r6,`6*$BNSZ`(r4)
1498 #mul_add_c(a[7],b[6],c2,c3,c1);
1499 $LD r6,`7*$BNSZ`(r4)
1500 $LD r7,`6*$BNSZ`(r5)
1506 $ST r11,`13*$BNSZ`(r3) #r[13]=c2;
1507 #mul_add_c(a[7],b[7],c3,c1,c2);
1508 $LD r7,`7*$BNSZ`(r5)
1513 $ST r12,`14*$BNSZ`(r3) #r[14]=c3;
1514 $ST r10,`15*$BNSZ`(r3) #r[15]=c1;
1517 .byte 0,12,0x14,0,0,0,3,0
1519 .size .bn_mul_comba8,.-.bn_mul_comba8
1522 # NOTE: The following label name should be changed to
1523 # "bn_sub_words" i.e. remove the first dot
1524 # for the gcc compiler. This should be automatically
1531 # Handcoded version of bn_sub_words
1533 #BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
1540 # Note: No loop unrolling done since this is not a performance
1543 xor r0,r0,r0 #set r0 = 0
1545 # check for r6 = 0 AND set carry bit.
1547 subfc. r7,r0,r6 # If r6 is 0 then result is 0.
1548 # if r6 > 0 then result !=0
1549 # In either case carry bit is set.
1550 beq Lppcasm_sub_adios
1555 Lppcasm_sub_mainloop:
1558 subfe r6,r8,r7 # r6 = r7+carry bit + onescomplement(r8)
1559 # if carry = 1 this is r7-r8. Else it
1560 # is r7-r8 -1 as we need.
1562 bdnz Lppcasm_sub_mainloop
1564 subfze r3,r0 # if carry bit is set then r3 = 0 else -1
1565 andi. r3,r3,1 # keep only last bit.
1568 .byte 0,12,0x14,0,0,0,4,0
1570 .size .bn_sub_words,.-.bn_sub_words
1573 # NOTE: The following label name should be changed to
1574 # "bn_add_words" i.e. remove the first dot
1575 # for the gcc compiler. This should be automatically
1582 # Handcoded version of bn_add_words
1584 #BN_ULONG bn_add_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n)
1591 # Note: No loop unrolling done since this is not a performance
1596 # check for r6 = 0. Is this needed?
1598 addic. r6,r6,0 #test r6 and clear carry bit.
1599 beq Lppcasm_add_adios
1604 Lppcasm_add_mainloop:
1609 bdnz Lppcasm_add_mainloop
1611 addze r3,r0 #return carry bit.
1614 .byte 0,12,0x14,0,0,0,4,0
1616 .size .bn_add_words,.-.bn_add_words
1619 # NOTE: The following label name should be changed to
1620 # "bn_div_words" i.e. remove the first dot
1621 # for the gcc compiler. This should be automatically
1628 # This is a cleaned up version of code generated by
1629 # the AIX compiler. The only optimization is to use
1630 # the PPC instruction to count leading zeros instead
1631 # of call to num_bits_word. Since this was compiled
1632 # only at level -O2 we can possibly squeeze it more?
1638 $UCMPI 0,r5,0 # compare r5 and 0
1639 bne Lppcasm_div1 # proceed if d!=0
1640 li r3,-1 # d=0 return -1
1645 $CNTLZ. r7,r5 #r7 = num leading 0s in d.
1646 beq Lppcasm_div2 #proceed if no leading zeros
1647 subf r8,r7,r8 #r8 = BN_num_bits_word(d)
1648 $SHR. r9,r3,r8 #are there any bits above r8'th?
1649 $TR 16,r9,r0 #if there're, signal to dump core...
1651 $UCMP 0,r3,r5 #h>=d?
1652 blt Lppcasm_div3 #goto Lppcasm_div3 if not
1653 subf r3,r5,r3 #h-=d ;
1654 Lppcasm_div3: #r7 = BN_BITS2-i. so r7=i
1655 cmpi 0,0,r7,0 # is (i == 0)?
1657 $SHL r3,r3,r7 # h = (h<< i)
1658 $SHR r8,r4,r8 # r8 = (l >> BN_BITS2 -i)
1659 $SHL r5,r5,r7 # d<<=i
1660 or r3,r3,r8 # h = (h<<i)|(l>>(BN_BITS2-i))
1661 $SHL r4,r4,r7 # l <<=i
1663 $SHRI r9,r5,`$BITS/2` # r9 = dh
1664 # dl will be computed when needed
1665 # as it saves registers.
1667 mtctr r6 #counter will be in count.
1668 Lppcasm_divouterloop:
1669 $SHRI r8,r3,`$BITS/2` #r8 = (h>>BN_BITS4)
1670 $SHRI r11,r4,`$BITS/2` #r11= (l&BN_MASK2h)>>BN_BITS4
1671 # compute here for innerloop.
1672 $UCMP 0,r8,r9 # is (h>>BN_BITS4)==dh
1673 bne Lppcasm_div5 # goto Lppcasm_div5 if not
1676 $CLRU r8,r8,`$BITS/2` #q = BN_MASK2l
1679 $UDIV r8,r3,r9 #q = h/dh
1681 $UMULL r12,r9,r8 #th = q*dh
1682 $CLRU r10,r5,`$BITS/2` #r10=dl
1683 $UMULL r6,r8,r10 #tl = q*dl
1685 Lppcasm_divinnerloop:
1686 subf r10,r12,r3 #t = h -th
1687 $SHRI r7,r10,`$BITS/2` #r7= (t &BN_MASK2H), sort of...
1688 addic. r7,r7,0 #test if r7 == 0. used below.
1689 # now want to compute
1690 # r7 = (t<<BN_BITS4)|((l&BN_MASK2h)>>BN_BITS4)
1691 # the following 2 instructions do that
1692 $SHLI r7,r10,`$BITS/2` # r7 = (t<<BN_BITS4)
1693 or r7,r7,r11 # r7|=((l&BN_MASK2h)>>BN_BITS4)
1694 $UCMP cr1,r6,r7 # compare (tl <= r7)
1695 bne Lppcasm_divinnerexit
1696 ble cr1,Lppcasm_divinnerexit
1698 subf r12,r9,r12 #th -=dh
1699 $CLRU r10,r5,`$BITS/2` #r10=dl. t is no longer needed in loop.
1700 subf r6,r10,r6 #tl -=dl
1701 b Lppcasm_divinnerloop
1702 Lppcasm_divinnerexit:
1703 $SHRI r10,r6,`$BITS/2` #t=(tl>>BN_BITS4)
1704 $SHLI r11,r6,`$BITS/2` #tl=(tl<<BN_BITS4)&BN_MASK2h;
1705 $UCMP cr1,r4,r11 # compare l and tl
1706 add r12,r12,r10 # th+=t
1707 bge cr1,Lppcasm_div7 # if (l>=tl) goto Lppcasm_div7
1708 addi r12,r12,1 # th++
1710 subf r11,r11,r4 #r11=l-tl
1711 $UCMP cr1,r3,r12 #compare h and th
1712 bge cr1,Lppcasm_div8 #if (h>=th) goto Lppcasm_div8
1716 subf r12,r12,r3 #r12 = h-th
1717 $SHLI r4,r11,`$BITS/2` #l=(l&BN_MASK2l)<<BN_BITS4
1719 # h = ((h<<BN_BITS4)|(l>>BN_BITS4))&BN_MASK2
1720 # the following 2 instructions will do this.
1721 $INSR r11,r12,`$BITS/2`,`$BITS/2` # r11 is the value we want rotated $BITS/2.
1722 $ROTL r3,r11,`$BITS/2` # rotate by $BITS/2 and store in r3
1723 bdz Lppcasm_div9 #if (count==0) break ;
1724 $SHLI r0,r8,`$BITS/2` #ret =q<<BN_BITS4
1725 b Lppcasm_divouterloop
1730 .byte 0,12,0x14,0,0,0,3,0
1732 .size .bn_div_words,.-.bn_div_words
1735 # NOTE: The following label name should be changed to
1736 # "bn_sqr_words" i.e. remove the first dot
1737 # for the gcc compiler. This should be automatically
1743 # Optimized version of bn_sqr_words
1745 # void bn_sqr_words(BN_ULONG *r, BN_ULONG *a, int n)
1754 # No unrolling done here. Not performance critical.
1756 addic. r5,r5,0 #test r5.
1757 beq Lppcasm_sqr_adios
1761 Lppcasm_sqr_mainloop:
1762 #sqr(r[0],r[1],a[0]);
1768 bdnz Lppcasm_sqr_mainloop
1772 .byte 0,12,0x14,0,0,0,3,0
1774 .size .bn_sqr_words,.-.bn_sqr_words
1777 # NOTE: The following label name should be changed to
1778 # "bn_mul_words" i.e. remove the first dot
1779 # for the gcc compiler. This should be automatically
1786 # BN_ULONG bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
1793 xor r12,r12,r12 # used for carry
1794 rlwinm. r7,r5,30,2,31 # num >> 2
1798 #mul(rp[0],ap[0],w,c1);
1799 $LD r8,`0*$BNSZ`(r4)
1803 #addze r10,r10 #carry is NOT ignored.
1804 #will be taken care of
1805 #in second spin below
1807 $ST r9,`0*$BNSZ`(r3)
1808 #mul(rp[1],ap[1],w,c1);
1809 $LD r8,`1*$BNSZ`(r4)
1814 $ST r11,`1*$BNSZ`(r3)
1815 #mul(rp[2],ap[2],w,c1);
1816 $LD r8,`2*$BNSZ`(r4)
1821 $ST r9,`2*$BNSZ`(r3)
1822 #mul_add(rp[3],ap[3],w,c1);
1823 $LD r8,`3*$BNSZ`(r4)
1827 addze r12,r12 #this spin we collect carry into
1829 $ST r11,`3*$BNSZ`(r3)
1831 addi r3,r3,`4*$BNSZ`
1832 addi r4,r4,`4*$BNSZ`
1833 bdnz Lppcasm_mw_LOOP
1838 #mul(rp[0],ap[0],w,c1);
1839 $LD r8,`0*$BNSZ`(r4)
1844 $ST r9,`0*$BNSZ`(r3)
1852 #mul(rp[1],ap[1],w,c1);
1853 $LD r8,`1*$BNSZ`(r4)
1858 $ST r9,`1*$BNSZ`(r3)
1865 #mul_add(rp[2],ap[2],w,c1);
1866 $LD r8,`2*$BNSZ`(r4)
1871 $ST r9,`2*$BNSZ`(r3)
1878 .byte 0,12,0x14,0,0,0,4,0
1880 .size .bn_mul_words,.-.bn_mul_words
1883 # NOTE: The following label name should be changed to
1884 # "bn_mul_add_words" i.e. remove the first dot
1885 # for the gcc compiler. This should be automatically
1892 # BN_ULONG bn_mul_add_words(BN_ULONG *rp, BN_ULONG *ap, int num, BN_ULONG w)
1899 # empirical evidence suggests that unrolled version performs best!!
1901 xor r0,r0,r0 #r0 = 0
1902 xor r12,r12,r12 #r12 = 0 . used for carry
1903 rlwinm. r7,r5,30,2,31 # num >> 2
1904 beq Lppcasm_maw_leftover # if (num < 4) go LPPCASM_maw_leftover
1906 Lppcasm_maw_mainloop:
1907 #mul_add(rp[0],ap[0],w,c1);
1908 $LD r8,`0*$BNSZ`(r4)
1909 $LD r11,`0*$BNSZ`(r3)
1912 addc r9,r9,r12 #r12 is carry.
1916 #the above instruction addze
1917 #is NOT needed. Carry will NOT
1918 #be ignored. It's not affected
1919 #by multiply and will be collected
1921 $ST r9,`0*$BNSZ`(r3)
1923 #mul_add(rp[1],ap[1],w,c1);
1924 $LD r8,`1*$BNSZ`(r4)
1925 $LD r9,`1*$BNSZ`(r3)
1928 adde r11,r11,r10 #r10 is carry.
1932 $ST r11,`1*$BNSZ`(r3)
1934 #mul_add(rp[2],ap[2],w,c1);
1935 $LD r8,`2*$BNSZ`(r4)
1937 $LD r11,`2*$BNSZ`(r3)
1943 $ST r9,`2*$BNSZ`(r3)
1945 #mul_add(rp[3],ap[3],w,c1);
1946 $LD r8,`3*$BNSZ`(r4)
1948 $LD r9,`3*$BNSZ`(r3)
1954 $ST r11,`3*$BNSZ`(r3)
1955 addi r3,r3,`4*$BNSZ`
1956 addi r4,r4,`4*$BNSZ`
1957 bdnz Lppcasm_maw_mainloop
1959 Lppcasm_maw_leftover:
1961 beq Lppcasm_maw_adios
1964 #mul_add(rp[0],ap[0],w,c1);
1976 bdz Lppcasm_maw_adios
1977 #mul_add(rp[1],ap[1],w,c1);
1988 bdz Lppcasm_maw_adios
1989 #mul_add(rp[2],ap[2],w,c1);
2004 .byte 0,12,0x14,0,0,0,4,0
2006 .size .bn_mul_add_words,.-.bn_mul_add_words
2009 $data =~ s/\`([^\`]*)\`/eval $1/gem;