3 # ====================================================================
4 # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
5 # project. The module is, however, dual licensed under OpenSSL and
6 # CRYPTOGAMS licenses depending on where you obtain it. For further
7 # details see http://www.openssl.org/~appro/cryptogams/.
8 # ====================================================================
12 # Performance improvement over vanilla C code varies from 85% to 45%
13 # depending on key length and benchmark. Unfortunately in this context
14 # these are not very impressive results [for code that utilizes "wide"
15 # 64x64=128-bit multiplication, which is not commonly available to C
16 # programmers], at least hand-coded bn_asm.c replacement is known to
17 # provide 30-40% better results for longest keys. Well, on a second
18 # thought it's not very surprising, because z-CPUs are single-issue
19 # and _strictly_ in-order execution, while bn_mul_mont is more or less
20 # dependent on CPU ability to pipe-line instructions and have several
21 # of them "in-flight" at the same time. I mean while other methods,
22 # for example Karatsuba, aim to minimize amount of multiplications at
23 # the cost of other operations increase, bn_mul_mont aim to neatly
24 # "overlap" multiplications and the other operations [and on most
25 # platforms even minimize the amount of the other operations, in
26 # particular references to memory]. But it's possible to improve this
27 # module performance by implementing dedicated squaring code-path and
28 # possibly by unrolling loops...
32 # Reschedule to minimize/avoid Address Generation Interlock hazard,
33 # make inner loops counter-based.
35 while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
36 open STDOUT,">$output";
42 $rp="%r2"; # BN_ULONG *rp,
43 $ap="%r3"; # const BN_ULONG *ap,
44 $bp="%r4"; # const BN_ULONG *bp,
45 $np="%r5"; # const BN_ULONG *np,
46 $n0="%r6"; # const BN_ULONG *n0,
47 #$num="160(%r15)" # int num);
64 .type bn_mul_mont,\@function
66 lgf $num,164($sp) # pull $num
67 sla $num,3 # $num to enumerate bytes
74 blr %r14 # if($num<16) return 0;
76 bhr %r14 # if($num>128) return 0;
80 lghi $rp,-160-8 # leave room for carry bit
84 la $sp,0($j,$rp) # alloca
85 stg %r0,0($sp) # back chain
87 sra $num,3 # restore $num
88 la $bp,0($j,$bp) # restore $bp
89 ahi $num,-1 # adjust $num for inner loop
90 lg $n0,0($n0) # pull n0
94 mlgr $ahi,$bi # ap[0]*bp[0]
97 lgr $mn0,$alo # "tp[0]"*n0
101 mlgr $nhi,$mn0 # np[0]*m1
102 algr $nlo,$alo # +="tp[0]"
112 mlgr $ahi,$bi # ap[j]*bp[0]
118 mlgr $nhi,$mn0 # np[j]*m1
121 alcgr $nhi,$NHI # +="tp[j]"
125 stg $nlo,160-8($j,$sp) # tp[j-1]=
131 alcgr $AHI,$AHI # upmost overflow bit
132 stg $NHI,160-8($j,$sp)
137 lg $bi,0($bp) # bp[i]
139 mlgr $ahi,$bi # ap[0]*bp[i]
140 alg $alo,160($sp) # +=tp[0]
145 msgr $mn0,$n0 # tp[0]*n0
147 lg $nlo,0($np) # np[0]
148 mlgr $nhi,$mn0 # np[0]*m1
149 algr $nlo,$alo # +="tp[0]"
159 mlgr $ahi,$bi # ap[j]*bp[i]
163 alg $alo,160($j,$sp)# +=tp[j]
167 mlgr $nhi,$mn0 # np[j]*m1
171 algr $nlo,$alo # +="tp[j]"
174 stg $nlo,160-8($j,$sp) # tp[j-1]=
181 alg $NHI,160($j,$sp)# accumulate previous upmost overflow bit
183 alcgr $AHI,$ahi # new upmost overflow bit
184 stg $NHI,160-8($j,$sp)
188 clg $bp,160+8+32($j,$sp) # compare to &bp[num]
191 lg $rp,160+8+16($j,$sp) # reincarnate rp
193 ahi $num,1 # restore $num, incidentally clears "borrow"
197 .Lsub: lg $alo,0($j,$ap)
203 slbgr $AHI,$ahi # handle upmost carry
209 ogr $ap,$np # ap=borrow?tp:rp
213 .Lcopy: lg $alo,0($j,$ap) # copy or in-place refresh
214 stg $j,160($j,$sp) # zap tp
219 la %r1,160+8+48($j,$sp)
221 lghi %r2,1 # signal "processed"
223 .size bn_mul_mont,.-bn_mul_mont
224 .string "Montgomery Multiplication for s390x, CRYPTOGAMS by <appro\@openssl.org>"