rshift.asm
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:9k
源码类别:

数学计算

开发平台:

Unix_Linux

  1. dnl  Intel P5 mpn_rshift -- mpn right shift.
  2. dnl  Copyright 2000, 2002 Free Software Foundation, Inc.
  3. dnl
  4. dnl  This file is part of the GNU MP Library.
  5. dnl
  6. dnl  The GNU MP Library is free software; you can redistribute it and/or
  7. dnl  modify it under the terms of the GNU Lesser General Public License as
  8. dnl  published by the Free Software Foundation; either version 3 of the
  9. dnl  License, or (at your option) any later version.
  10. dnl
  11. dnl  The GNU MP Library is distributed in the hope that it will be useful,
  12. dnl  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14. dnl  Lesser General Public License for more details.
  15. dnl
  16. dnl  You should have received a copy of the GNU Lesser General Public License
  17. dnl  along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.
  18. include(`../config.m4')
  19. C P5: 1.75 cycles/limb.
  20. C mp_limb_t mpn_rshift (mp_ptr dst, mp_srcptr src, mp_size_t size,
  21. C                       unsigned shift);
  22. C
  23. C Shift src,size right by shift many bits and store the result in dst,size.
  24. C Zeros are shifted in at the left.  Return the bits shifted out at the
  25. C right.
  26. C
  27. C It takes 6 mmx instructions to process 2 limbs, making 1.5 cycles/limb,
  28. C and with a 4 limb loop and 1 cycle of loop overhead the total is 1.75 c/l.
  29. C
  30. C Full speed depends on source and destination being aligned.  Unaligned mmx
  31. C loads and stores on P5 don't pair and have a 2 cycle penalty.  Some hairy
  32. C setups and finish-ups are done to ensure alignment for the loop.
  33. C
  34. C MMX shifts work out a bit faster even for the simple loop.
  35. defframe(PARAM_SHIFT,16)
  36. defframe(PARAM_SIZE, 12)
  37. defframe(PARAM_SRC,  8)
  38. defframe(PARAM_DST,  4)
  39. deflit(`FRAME',0)
  40. dnl  Minimum 5, because the unrolled loop can't handle less.
  41. deflit(UNROLL_THRESHOLD, 5)
  42. TEXT
  43. ALIGN(8)
  44. PROLOGUE(mpn_rshift)
  45. pushl %ebx
  46. pushl %edi
  47. deflit(`FRAME',8)
  48. movl PARAM_SIZE, %eax
  49. movl PARAM_DST, %edx
  50. movl PARAM_SRC, %ebx
  51. movl PARAM_SHIFT, %ecx
  52. cmp $UNROLL_THRESHOLD, %eax
  53. jae L(unroll)
  54. decl %eax
  55. movl (%ebx), %edi C src low limb
  56. jnz L(simple)
  57. shrdl( %cl, %edi, %eax) C eax was decremented to zero
  58. shrl %cl, %edi
  59. movl %edi, (%edx) C dst low limb
  60. popl %edi C risk of data cache bank clash
  61. popl %ebx
  62. ret
  63. C -----------------------------------------------------------------------------
  64. ALIGN(8)
  65. L(simple):
  66. C eax size-1
  67. C ebx src
  68. C ecx shift
  69. C edx dst
  70. C esi
  71. C edi
  72. C ebp
  73. deflit(`FRAME',8)
  74. movd (%ebx), %mm5 C src[0]
  75. leal (%ebx,%eax,4), %ebx C &src[size-1]
  76. movd %ecx, %mm6 C rshift
  77. leal -4(%edx,%eax,4), %edx C &dst[size-2]
  78. psllq $32, %mm5
  79. negl %eax
  80. C This loop is 5 or 8 cycles, with every second load unaligned and a wasted
  81. C cycle waiting for the mm0 result to be ready.  For comparison a shrdl is 4
  82. C cycles and would be 8 in a simple loop.  Using mmx helps the return value
  83. C and last limb calculations too.
  84. L(simple_top):
  85. C eax counter, limbs, negative
  86. C ebx &src[size-1]
  87. C ecx return value
  88. C edx &dst[size-2]
  89. C
  90. C mm0 scratch
  91. C mm5 return value
  92. C mm6 shift
  93. movq (%ebx,%eax,4), %mm0
  94. incl %eax
  95. psrlq %mm6, %mm0
  96. movd %mm0, (%edx,%eax,4)
  97. jnz L(simple_top)
  98. movd (%ebx), %mm0
  99. psrlq %mm6, %mm5 C return value
  100. psrlq %mm6, %mm0
  101. popl %edi
  102. movd %mm5, %eax
  103. popl %ebx
  104. movd %mm0, 4(%edx)
  105. emms
  106. ret
  107. C -----------------------------------------------------------------------------
  108. ALIGN(8)
  109. L(unroll):
  110. C eax size
  111. C ebx src
  112. C ecx shift
  113. C edx dst
  114. C esi
  115. C edi
  116. C ebp
  117. deflit(`FRAME',8)
  118. movd (%ebx), %mm5 C src[0]
  119. movl $4, %edi
  120. movd %ecx, %mm6 C rshift
  121. testl %edi, %ebx
  122. psllq $32, %mm5
  123. jz L(start_src_aligned)
  124. C src isn't aligned, process low limb separately (marked xxx) and
  125. C step src and dst by one limb, making src aligned.
  126. C
  127. C source                  ebx
  128. C --+-------+-------+-------+
  129. C           |          xxx  |
  130. C --+-------+-------+-------+
  131. C         4mod8   0mod8   4mod8
  132. C
  133. C         dest            edx
  134. C         --+-------+-------+
  135. C           |       |  xxx  |
  136. C         --+-------+-------+
  137. movq (%ebx), %mm0 C unaligned load
  138. psrlq %mm6, %mm0
  139. addl $4, %ebx
  140. decl %eax
  141. movd %mm0, (%edx)
  142. addl $4, %edx
  143. L(start_src_aligned):
  144. movq (%ebx), %mm1
  145. testl %edi, %edx
  146. psrlq %mm6, %mm5 C retval
  147. jz L(start_dst_aligned)
  148. C dst isn't aligned, add 4 to make it so, and pretend the shift is
  149. C 32 bits extra.  Low limb of dst (marked xxx) handled here
  150. C separately.
  151. C
  152. C          source          ebx
  153. C          --+-------+-------+
  154. C            |      mm1      |
  155. C          --+-------+-------+
  156. C                  4mod8   0mod8
  157. C
  158. C  dest                    edx
  159. C  --+-------+-------+-------+
  160. C                    |  xxx  |
  161. C  --+-------+-------+-------+
  162. C          4mod8   0mod8   4mod8
  163. movq %mm1, %mm0
  164. addl $32, %ecx C new shift
  165. psrlq %mm6, %mm0
  166. movd %ecx, %mm6
  167. movd %mm0, (%edx)
  168. addl $4, %edx
  169. L(start_dst_aligned):
  170. movq 8(%ebx), %mm3
  171. negl %ecx
  172. movq %mm3, %mm2 C mm2 src qword
  173. addl $64, %ecx
  174. movd %ecx, %mm7
  175. psrlq %mm6, %mm1
  176. leal -12(%ebx,%eax,4), %ebx
  177. leal -20(%edx,%eax,4), %edx
  178. psllq %mm7, %mm3
  179. subl $7, %eax C size-7
  180. por %mm1, %mm3 C mm3 ready to store
  181. negl %eax C -(size-7)
  182. jns L(finish)
  183. C This loop is the important bit, the rest is just support.  Careful
  184. C instruction scheduling achieves the claimed 1.75 c/l.  The
  185. C relevant parts of the pairing rules are:
  186. C
  187. C - mmx loads and stores execute only in the U pipe
  188. C - only one mmx shift in a pair
  189. C - wait one cycle before storing an mmx register result
  190. C - the usual address generation interlock
  191. C
  192. C Two qword calculations are slightly interleaved.  The instructions
  193. C marked "C" belong to the second qword, and the "C prev" one is for
  194. C the second qword from the previous iteration.
  195. ALIGN(8)
  196. L(unroll_loop):
  197. C eax counter, limbs, negative
  198. C ebx &src[size-12]
  199. C ecx
  200. C edx &dst[size-12]
  201. C esi
  202. C edi
  203. C
  204. C mm0
  205. C mm1
  206. C mm2 src qword from -8(%ebx,%eax,4)
  207. C mm3 dst qword ready to store to -8(%edx,%eax,4)
  208. C
  209. C mm5 return value
  210. C mm6 rshift
  211. C mm7 lshift
  212. movq (%ebx,%eax,4), %mm0
  213. psrlq %mm6, %mm2
  214. movq %mm0, %mm1
  215. psllq %mm7, %mm0
  216. movq %mm3, -8(%edx,%eax,4) C prev
  217. por %mm2, %mm0
  218. movq 8(%ebx,%eax,4), %mm3 C
  219. psrlq %mm6, %mm1 C
  220. movq %mm0, (%edx,%eax,4)
  221. movq %mm3, %mm2 C
  222. psllq %mm7, %mm3 C
  223. addl $4, %eax
  224. por %mm1, %mm3 C
  225. js L(unroll_loop)
  226. L(finish):
  227. C eax 0 to 3 representing respectively 3 to 0 limbs remaining
  228. testb $2, %al
  229. jnz L(finish_no_two)
  230. movq (%ebx,%eax,4), %mm0
  231. psrlq %mm6, %mm2
  232. movq %mm0, %mm1
  233. psllq %mm7, %mm0
  234. movq %mm3, -8(%edx,%eax,4) C prev
  235. por %mm2, %mm0
  236. movq %mm1, %mm2
  237. movq %mm0, %mm3
  238. addl $2, %eax
  239. L(finish_no_two):
  240. C eax 2 or 3 representing respectively 1 or 0 limbs remaining
  241. C
  242. C mm2 src prev qword, from -8(%ebx,%eax,4)
  243. C mm3 dst qword, for -8(%edx,%eax,4)
  244. testb $1, %al
  245. popl %edi
  246. movd %mm5, %eax C retval
  247. jnz L(finish_zero)
  248. C One extra limb, destination was aligned.
  249. C
  250. C source                ebx
  251. C +-------+---------------+--
  252. C |       |      mm2      |
  253. C +-------+---------------+--
  254. C
  255. C dest                                  edx
  256. C +-------+---------------+---------------+--
  257. C |       |               |      mm3      |
  258. C +-------+---------------+---------------+--
  259. C
  260. C mm6 = shift
  261. C mm7 = ecx = 64-shift
  262. C One extra limb, destination was unaligned.
  263. C
  264. C source                ebx
  265. C +-------+---------------+--
  266. C |       |      mm2      |
  267. C +-------+---------------+--
  268. C
  269. C dest                          edx
  270. C +---------------+---------------+--
  271. C |               |      mm3      |
  272. C +---------------+---------------+--
  273. C
  274. C mm6 = shift+32
  275. C mm7 = ecx = 64-(shift+32)
  276. C In both cases there's one extra limb of src to fetch and combine
  277. C with mm2 to make a qword at 8(%edx), and in the aligned case
  278. C there's a further extra limb of dst to be formed.
  279. movd 8(%ebx), %mm0
  280. psrlq %mm6, %mm2
  281. movq %mm0, %mm1
  282. psllq %mm7, %mm0
  283. movq %mm3, (%edx)
  284. por %mm2, %mm0
  285. psrlq %mm6, %mm1
  286. andl $32, %ecx
  287. popl %ebx
  288. jz L(finish_one_unaligned)
  289. C dst was aligned, must store one extra limb
  290. movd %mm1, 16(%edx)
  291. L(finish_one_unaligned):
  292. movq %mm0, 8(%edx)
  293. emms
  294. ret
  295. L(finish_zero):
  296. C No extra limbs, destination was aligned.
  297. C
  298. C source        ebx
  299. C +---------------+--
  300. C |      mm2      |
  301. C +---------------+--
  302. C
  303. C dest                        edx+4
  304. C +---------------+---------------+--
  305. C |               |      mm3      |
  306. C +---------------+---------------+--
  307. C
  308. C mm6 = shift
  309. C mm7 = ecx = 64-shift
  310. C No extra limbs, destination was unaligned.
  311. C
  312. C source        ebx
  313. C +---------------+--
  314. C |      mm2      |
  315. C +---------------+--
  316. C
  317. C dest                edx+4
  318. C +-------+---------------+--
  319. C |       |      mm3      |
  320. C +-------+---------------+--
  321. C
  322. C mm6 = shift+32
  323. C mm7 = 64-(shift+32)
  324. C The movd for the unaligned case is clearly the same data as the
  325. C movq for the aligned case, it's just a choice between whether one
  326. C or two limbs should be written.
  327. movq %mm3, 4(%edx)
  328. psrlq %mm6, %mm2
  329. movd %mm2, 12(%edx)
  330. andl $32, %ecx
  331. popl %ebx
  332. jz L(finish_zero_unaligned)
  333. movq %mm2, 12(%edx)
  334. L(finish_zero_unaligned):
  335. emms
  336. ret
  337. EPILOGUE()