x86_64-mont.pl 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #!/usr/bin/env perl
  2. # ====================================================================
  3. # Written by Andy Polyakov <appro@fy.chalmers.se> for the OpenSSL
  4. # project. The module is, however, dual licensed under OpenSSL and
  5. # CRYPTOGAMS licenses depending on where you obtain it. For further
  6. # details see http://www.openssl.org/~appro/cryptogams/.
  7. # ====================================================================
  8. # October 2005.
  9. #
  10. # Montgomery multiplication routine for x86_64. While it gives modest
  11. # 9% improvement of rsa4096 sign on Opteron, rsa512 sign runs more
  12. # than twice, >2x, as fast. Most common rsa1024 sign is improved by
  13. # respectful 50%. It remains to be seen if loop unrolling and
  14. # dedicated squaring routine can provide further improvement...
  15. $output=shift;
  16. $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
  17. ( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or
  18. ( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
  19. die "can't locate x86_64-xlate.pl";
  20. open STDOUT,"| $^X $xlate $output";
  21. # int bn_mul_mont(
  22. $rp="%rdi"; # BN_ULONG *rp,
  23. $ap="%rsi"; # const BN_ULONG *ap,
  24. $bp="%rdx"; # const BN_ULONG *bp,
  25. $np="%rcx"; # const BN_ULONG *np,
  26. $n0="%r8"; # const BN_ULONG *n0,
  27. $num="%r9"; # int num);
  28. $lo0="%r10";
  29. $hi0="%r11";
  30. $bp="%r12"; # reassign $bp
  31. $hi1="%r13";
  32. $i="%r14";
  33. $j="%r15";
  34. $m0="%rbx";
  35. $m1="%rbp";
  36. $code=<<___;
  37. .text
  38. .globl bn_mul_mont
  39. .type bn_mul_mont,\@function,6
  40. .align 16
  41. bn_mul_mont:
  42. push %rbx
  43. push %rbp
  44. push %r12
  45. push %r13
  46. push %r14
  47. push %r15
  48. mov ${num}d,${num}d
  49. lea 2($num),%rax
  50. mov %rsp,%rbp
  51. neg %rax
  52. lea (%rsp,%rax,8),%rsp # tp=alloca(8*(num+2))
  53. and \$-1024,%rsp # minimize TLB usage
  54. mov %rbp,8(%rsp,$num,8) # tp[num+1]=%rsp
  55. mov %rdx,$bp # $bp reassigned, remember?
  56. mov ($n0),$n0 # pull n0[0] value
  57. xor $i,$i # i=0
  58. xor $j,$j # j=0
  59. mov ($bp),$m0 # m0=bp[0]
  60. mov ($ap),%rax
  61. mulq $m0 # ap[0]*bp[0]
  62. mov %rax,$lo0
  63. mov %rdx,$hi0
  64. imulq $n0,%rax # "tp[0]"*n0
  65. mov %rax,$m1
  66. mulq ($np) # np[0]*m1
  67. add $lo0,%rax # discarded
  68. adc \$0,%rdx
  69. mov %rdx,$hi1
  70. lea 1($j),$j # j++
  71. .L1st:
  72. mov ($ap,$j,8),%rax
  73. mulq $m0 # ap[j]*bp[0]
  74. add $hi0,%rax
  75. adc \$0,%rdx
  76. mov %rax,$lo0
  77. mov ($np,$j,8),%rax
  78. mov %rdx,$hi0
  79. mulq $m1 # np[j]*m1
  80. add $hi1,%rax
  81. lea 1($j),$j # j++
  82. adc \$0,%rdx
  83. add $lo0,%rax # np[j]*m1+ap[j]*bp[0]
  84. adc \$0,%rdx
  85. mov %rax,-16(%rsp,$j,8) # tp[j-1]
  86. cmp $num,$j
  87. mov %rdx,$hi1
  88. jl .L1st
  89. xor %rdx,%rdx
  90. add $hi0,$hi1
  91. adc \$0,%rdx
  92. mov $hi1,-8(%rsp,$num,8)
  93. mov %rdx,(%rsp,$num,8) # store upmost overflow bit
  94. lea 1($i),$i # i++
  95. .align 4
  96. .Louter:
  97. xor $j,$j # j=0
  98. mov ($bp,$i,8),$m0 # m0=bp[i]
  99. mov ($ap),%rax # ap[0]
  100. mulq $m0 # ap[0]*bp[i]
  101. add (%rsp),%rax # ap[0]*bp[i]+tp[0]
  102. adc \$0,%rdx
  103. mov %rax,$lo0
  104. mov %rdx,$hi0
  105. imulq $n0,%rax # tp[0]*n0
  106. mov %rax,$m1
  107. mulq ($np,$j,8) # np[0]*m1
  108. add $lo0,%rax # discarded
  109. mov 8(%rsp),$lo0 # tp[1]
  110. adc \$0,%rdx
  111. mov %rdx,$hi1
  112. lea 1($j),$j # j++
  113. .align 4
  114. .Linner:
  115. mov ($ap,$j,8),%rax
  116. mulq $m0 # ap[j]*bp[i]
  117. add $hi0,%rax
  118. adc \$0,%rdx
  119. add %rax,$lo0 # ap[j]*bp[i]+tp[j]
  120. mov ($np,$j,8),%rax
  121. adc \$0,%rdx
  122. mov %rdx,$hi0
  123. mulq $m1 # np[j]*m1
  124. add $hi1,%rax
  125. lea 1($j),$j # j++
  126. adc \$0,%rdx
  127. add $lo0,%rax # np[j]*m1+ap[j]*bp[i]+tp[j]
  128. adc \$0,%rdx
  129. mov (%rsp,$j,8),$lo0
  130. cmp $num,$j
  131. mov %rax,-16(%rsp,$j,8) # tp[j-1]
  132. mov %rdx,$hi1
  133. jl .Linner
  134. xor %rdx,%rdx
  135. add $hi0,$hi1
  136. adc \$0,%rdx
  137. add $lo0,$hi1 # pull upmost overflow bit
  138. adc \$0,%rdx
  139. mov $hi1,-8(%rsp,$num,8)
  140. mov %rdx,(%rsp,$num,8) # store upmost overflow bit
  141. lea 1($i),$i # i++
  142. cmp $num,$i
  143. jl .Louter
  144. lea (%rsp),$ap # borrow ap for tp
  145. lea -1($num),$j # j=num-1
  146. mov ($ap),%rax # tp[0]
  147. xor $i,$i # i=0 and clear CF!
  148. jmp .Lsub
  149. .align 16
  150. .Lsub: sbb ($np,$i,8),%rax
  151. mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i]
  152. dec $j # doesn't affect CF!
  153. mov 8($ap,$i,8),%rax # tp[i+1]
  154. lea 1($i),$i # i++
  155. jge .Lsub
  156. sbb \$0,%rax # handle upmost overflow bit
  157. and %rax,$ap
  158. not %rax
  159. mov $rp,$np
  160. and %rax,$np
  161. lea -1($num),$j
  162. or $np,$ap # ap=borrow?tp:rp
  163. .align 16
  164. .Lcopy: # copy or in-place refresh
  165. mov ($ap,$j,8),%rax
  166. mov %rax,($rp,$j,8) # rp[i]=tp[i]
  167. mov $i,(%rsp,$j,8) # zap temporary vector
  168. dec $j
  169. jge .Lcopy
  170. mov 8(%rsp,$num,8),%rsp # restore %rsp
  171. mov \$1,%rax
  172. pop %r15
  173. pop %r14
  174. pop %r13
  175. pop %r12
  176. pop %rbp
  177. pop %rbx
  178. ret
  179. .size bn_mul_mont,.-bn_mul_mont
  180. .asciz "Montgomery Multiplication for x86_64, CRYPTOGAMS by <appro\@openssl.org>"
  181. ___
  182. print $code;
  183. close STDOUT;