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

数学计算

开发平台:

Unix_Linux

  1. dnl  Intel Pentium-4 mpn_divrem_1 -- mpn by limb division.
  2. dnl  Copyright 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation,
  3. dnl  Inc.
  4. dnl
  5. dnl  This file is part of the GNU MP Library.
  6. dnl
  7. dnl  The GNU MP Library is free software; you can redistribute it and/or
  8. dnl  modify it under the terms of the GNU Lesser General Public License as
  9. dnl  published by the Free Software Foundation; either version 3 of the
  10. dnl  License, or (at your option) any later version.
  11. dnl
  12. dnl  The GNU MP Library is distributed in the hope that it will be useful,
  13. dnl  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. dnl  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. dnl  Lesser General Public License for more details.
  16. dnl
  17. dnl  You should have received a copy of the GNU Lesser General Public License
  18. dnl  along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.
  19. include(`../config.m4')
  20. C P4: 32 cycles/limb integer part, 30 cycles/limb fraction part.
  21. C mp_limb_t mpn_divrem_1 (mp_ptr dst, mp_size_t xsize,
  22. C                         mp_srcptr src, mp_size_t size,
  23. C                         mp_limb_t divisor);
  24. C mp_limb_t mpn_divrem_1c (mp_ptr dst, mp_size_t xsize,
  25. C                          mp_srcptr src, mp_size_t size,
  26. C                          mp_limb_t divisor, mp_limb_t carry);
  27. C mp_limb_t mpn_preinv_divrem_1 (mp_ptr dst, mp_size_t xsize,
  28. C                                mp_srcptr src, mp_size_t size,
  29. C                                mp_limb_t divisor, mp_limb_t inverse,
  30. C                                unsigned shift);
  31. C
  32. C Algorithm:
  33. C
  34. C The method and nomenclature follow part 8 of "Division by Invariant
  35. C Integers using Multiplication" by Granlund and Montgomery, reference in
  36. C gmp.texi.
  37. C
  38. C "m" is written for what is m' in the paper, and "d" for d_norm, which
  39. C won't cause any confusion since it's only the normalized divisor that's of
  40. C any use in the code.  "b" is written for 2^N, the size of a limb, N being
  41. C 32 here.
  42. C
  43. C The step "sdword dr = n - 2^N*d + (2^N-1-q1) * d" is instead done as
  44. C "n-d - q1*d".  This rearrangement gives the same two-limb answer but lets
  45. C us have just a psubq on the dependent chain.
  46. C
  47. C For reference, the way the k7 code uses "n-(q1+1)*d" would not suit here,
  48. C detecting an overflow of q1+1 when q1=0xFFFFFFFF would cost too much.
  49. C
  50. C Notes:
  51. C
  52. C mpn_divrem_1 and mpn_preinv_divrem_1 avoid one division if the src high
  53. C limb is less than the divisor.  mpn_divrem_1c doesn't check for a zero
  54. C carry, since in normal circumstances that will be a very rare event.
  55. C
  56. C The test for skipping a division is branch free (once size>=1 is tested).
  57. C The store to the destination high limb is 0 when a divide is skipped, or
  58. C if it's not skipped then a copy of the src high limb is stored.  The
  59. C latter is in case src==dst.
  60. C
  61. C There's a small bias towards expecting xsize==0, by having code for
  62. C xsize==0 in a straight line and xsize!=0 under forward jumps.
  63. C
  64. C Enhancements:
  65. C
  66. C The loop measures 32 cycles, but the dependent chain would suggest it
  67. C could be done with 30.  Not sure where to start looking for the extras.
  68. C
  69. C Alternatives:
  70. C
  71. C If the divisor is normalized (high bit set) then a division step can
  72. C always be skipped, since the high destination limb is always 0 or 1 in
  73. C that case.  It doesn't seem worth checking for this though, since it
  74. C probably occurs infrequently.
  75. dnl  MUL_THRESHOLD is the value of xsize+size at which the multiply by
  76. dnl  inverse method is used, rather than plain "divl"s.  Minimum value 1.
  77. dnl
  78. dnl  The inverse takes about 80-90 cycles to calculate, but after that the
  79. dnl  multiply is 32 c/l versus division at about 58 c/l.
  80. dnl
  81. dnl  At 4 limbs the div is a touch faster than the mul (and of course
  82. dnl  simpler), so start the mul from 5 limbs.
  83. deflit(MUL_THRESHOLD, 5)
  84. defframe(PARAM_PREINV_SHIFT,   28)  dnl mpn_preinv_divrem_1
  85. defframe(PARAM_PREINV_INVERSE, 24)  dnl mpn_preinv_divrem_1
  86. defframe(PARAM_CARRY,  24)          dnl mpn_divrem_1c
  87. defframe(PARAM_DIVISOR,20)
  88. defframe(PARAM_SIZE,   16)
  89. defframe(PARAM_SRC,    12)
  90. defframe(PARAM_XSIZE,  8)
  91. defframe(PARAM_DST,    4)
  92. dnl  re-use parameter space
  93. define(SAVE_ESI,`PARAM_SIZE')
  94. define(SAVE_EBP,`PARAM_SRC')
  95. define(SAVE_EDI,`PARAM_DIVISOR')
  96. define(SAVE_EBX,`PARAM_DST')
  97. TEXT
  98. ALIGN(16)
  99. PROLOGUE(mpn_preinv_divrem_1)
  100. deflit(`FRAME',0)
  101. movl PARAM_SIZE, %ecx
  102. xorl %edx, %edx C carry if can't skip a div
  103. movl %esi, SAVE_ESI
  104. movl PARAM_SRC, %esi
  105. movl %ebp, SAVE_EBP
  106. movl PARAM_DIVISOR, %ebp
  107. movl %edi, SAVE_EDI
  108. movl PARAM_DST, %edi
  109. movl -4(%esi,%ecx,4), %eax C src high limb
  110. movl %ebx, SAVE_EBX
  111. movl PARAM_XSIZE, %ebx
  112. movd PARAM_PREINV_INVERSE, %mm4
  113. movd PARAM_PREINV_SHIFT, %mm7  C l
  114. cmpl %ebp, %eax C high cmp divisor
  115. cmovc( %eax, %edx) C high is carry if high<divisor
  116. movd %edx, %mm0 C carry
  117. movd %edx, %mm1 C carry
  118. movl $0, %edx
  119. movd %ebp, %mm5 C d
  120. cmovnc( %eax, %edx) C 0 if skip div, src high if not
  121. C (the latter in case src==dst)
  122. leal -4(%edi,%ebx,4), %edi C &dst[xsize-1]
  123. movl %edx, (%edi,%ecx,4) C dst high limb
  124. sbbl $0, %ecx C skip one division if high<divisor
  125. movl $32, %eax
  126. subl PARAM_PREINV_SHIFT, %eax
  127. psllq %mm7, %mm5 C d normalized
  128. leal (%edi,%ecx,4), %edi C &dst[xsize+size-1]
  129. leal -4(%esi,%ecx,4), %esi C &src[size-1]
  130. movd %eax, %mm6 C 32-l
  131. jmp L(start_preinv)
  132. EPILOGUE()
  133. ALIGN(16)
  134. PROLOGUE(mpn_divrem_1c)
  135. deflit(`FRAME',0)
  136. movl PARAM_CARRY, %edx
  137. movl PARAM_SIZE, %ecx
  138. movl %esi, SAVE_ESI
  139. movl PARAM_SRC, %esi
  140. movl %ebp, SAVE_EBP
  141. movl PARAM_DIVISOR, %ebp
  142. movl %edi, SAVE_EDI
  143. movl PARAM_DST, %edi
  144. movl %ebx, SAVE_EBX
  145. movl PARAM_XSIZE, %ebx
  146. leal -4(%edi,%ebx,4), %edi C &dst[xsize-1]
  147. jmp L(start_1c)
  148. EPILOGUE()
  149. ALIGN(16)
  150. PROLOGUE(mpn_divrem_1)
  151. deflit(`FRAME',0)
  152. movl PARAM_SIZE, %ecx
  153. xorl %edx, %edx C initial carry (if can't skip a div)
  154. movl %esi, SAVE_ESI
  155. movl PARAM_SRC, %esi
  156. movl %ebp, SAVE_EBP
  157. movl PARAM_DIVISOR, %ebp
  158. movl %edi, SAVE_EDI
  159. movl PARAM_DST, %edi
  160. movl %ebx, SAVE_EBX
  161. movl PARAM_XSIZE, %ebx
  162. leal -4(%edi,%ebx,4), %edi C &dst[xsize-1]
  163. orl %ecx, %ecx C size
  164. jz L(no_skip_div) C if size==0
  165. movl -4(%esi,%ecx,4), %eax C src high limb
  166. cmpl %ebp, %eax C high cmp divisor
  167. cmovnc( %eax, %edx) C 0 if skip div, src high if not
  168. movl %edx, (%edi,%ecx,4) C dst high limb
  169. movl $0, %edx
  170. cmovc( %eax, %edx) C high is carry if high<divisor
  171. sbbl $0, %ecx C size-1 if high<divisor
  172. L(no_skip_div):
  173. L(start_1c):
  174. C eax
  175. C ebx xsize
  176. C ecx size
  177. C edx carry
  178. C esi src
  179. C edi &dst[xsize-1]
  180. C ebp divisor
  181. leal (%ebx,%ecx), %eax C size+xsize
  182. leal -4(%esi,%ecx,4), %esi C &src[size-1]
  183. leal (%edi,%ecx,4), %edi C &dst[size+xsize-1]
  184. cmpl $MUL_THRESHOLD, %eax
  185. jae L(mul_by_inverse)
  186. orl %ecx, %ecx
  187. jz L(divide_no_integer) C if size==0
  188. L(divide_integer):
  189. C eax scratch (quotient)
  190. C ebx xsize
  191. C ecx counter
  192. C edx carry
  193. C esi src, decrementing
  194. C edi dst, decrementing
  195. C ebp divisor
  196. movl (%esi), %eax
  197. subl $4, %esi
  198. divl %ebp
  199. movl %eax, (%edi)
  200. subl $4, %edi
  201. subl $1, %ecx
  202. jnz L(divide_integer)
  203. L(divide_no_integer):
  204. orl %ebx, %ebx
  205. jnz L(divide_fraction) C if xsize!=0
  206. L(divide_done):
  207. movl SAVE_ESI, %esi
  208. movl SAVE_EDI, %edi
  209. movl SAVE_EBX, %ebx
  210. movl SAVE_EBP, %ebp
  211. movl %edx, %eax
  212. ret
  213. L(divide_fraction):
  214. C eax scratch (quotient)
  215. C ebx counter
  216. C ecx
  217. C edx carry
  218. C esi
  219. C edi dst, decrementing
  220. C ebp divisor
  221. movl $0, %eax
  222. divl %ebp
  223. movl %eax, (%edi)
  224. subl $4, %edi
  225. subl $1, %ebx
  226. jnz L(divide_fraction)
  227. jmp L(divide_done)
  228. C -----------------------------------------------------------------------------
  229. L(mul_by_inverse):
  230. C eax
  231. C ebx xsize
  232. C ecx size
  233. C edx carry
  234. C esi &src[size-1]
  235. C edi &dst[size+xsize-1]
  236. C ebp divisor
  237. bsrl %ebp, %eax C 31-l
  238. movd %edx, %mm0 C carry
  239. movd %edx, %mm1 C carry
  240. movl %ecx, %edx C size
  241. movl $31, %ecx
  242. C
  243. xorl %eax, %ecx C l = leading zeros on d
  244. addl $1, %eax
  245. shll %cl, %ebp C d normalized
  246. movd %ecx, %mm7 C l
  247. movl %edx, %ecx C size
  248. movd %eax, %mm6 C 32-l
  249. movl $-1, %edx
  250. movl $-1, %eax
  251. C
  252. subl %ebp, %edx C (b-d)-1 so  edx:eax = b*(b-d)-1
  253. divl %ebp C floor (b*(b-d)-1 / d)
  254. movd %ebp, %mm5 C d
  255. C
  256. movd %eax, %mm4 C m
  257. L(start_preinv):
  258. C eax inverse
  259. C ebx xsize
  260. C ecx size
  261. C edx
  262. C esi &src[size-1]
  263. C edi &dst[size+xsize-1]
  264. C ebp
  265. C
  266. C mm0 carry
  267. C mm1 carry
  268. C mm2
  269. C mm4 m
  270. C mm5 d
  271. C mm6 31-l
  272. C mm7 l
  273. psllq %mm7, %mm0 C n2 = carry << l, for size==0
  274. subl $1, %ecx
  275. jb L(integer_none)
  276. movd (%esi), %mm0 C src high limb
  277. punpckldq %mm1, %mm0
  278. psrlq %mm6, %mm0 C n2 = high (carry:srchigh << l)
  279. jz L(integer_last)
  280. C The dependent chain here consists of
  281. C
  282. C 2   paddd    n1+n2
  283. C 8   pmuludq  m*(n1+n2)
  284. C 2   paddq    n2:nadj + m*(n1+n2)
  285. C 2   psrlq    q1
  286. C 8   pmuludq  d*q1
  287. C 2   psubq    (n-d)-q1*d
  288. C 2   psrlq    high n-(q1+1)*d mask
  289. C 2   pand     d masked
  290. C 2   paddd    n2+d addback
  291. C --
  292. C 30
  293. C
  294. C But it seems to run at 32 cycles, so presumably there's something else
  295. C going on.
  296. ALIGN(16)
  297. L(integer_top):
  298. C eax
  299. C ebx
  300. C ecx counter, size-1 to 0
  301. C edx
  302. C esi src, decrementing
  303. C edi dst, decrementing
  304. C
  305. C mm0 n2
  306. C mm4 m
  307. C mm5 d
  308. C mm6 32-l
  309. C mm7 l
  310. ASSERT(b,`C n2<d
  311.  movd %mm0, %eax
  312.  movd %mm5, %edx
  313.  cmpl %edx, %eax')
  314. movd -4(%esi), %mm1 C next src limbs
  315. movd (%esi), %mm2
  316. leal -4(%esi), %esi
  317. punpckldq %mm2, %mm1
  318. psrlq %mm6, %mm1 C n10
  319. movq %mm1, %mm2 C n10
  320. movq %mm1, %mm3 C n10
  321. psrad $31, %mm1 C -n1
  322. pand %mm5, %mm1 C -n1 & d
  323. paddd %mm2, %mm1 C nadj = n10+(-n1&d), ignore overflow
  324. psrld $31, %mm2 C n1
  325. paddd %mm0, %mm2 C n2+n1
  326. punpckldq %mm0, %mm1 C n2:nadj
  327. pmuludq %mm4, %mm2 C m*(n2+n1)
  328. C
  329. paddq %mm2, %mm1 C n2:nadj + m*(n2+n1)
  330. pxor %mm2, %mm2 C break dependency, saves 4 cycles
  331. pcmpeqd %mm2, %mm2 C FF...FF
  332. psrlq $63, %mm2 C 1
  333. psrlq $32, %mm1 C q1 = high(n2:nadj + m*(n2+n1))
  334. paddd %mm1, %mm2 C q1+1
  335. pmuludq %mm5, %mm1 C q1*d
  336. punpckldq %mm0, %mm3 C n = n2:n10
  337. pxor %mm0, %mm0
  338. psubq %mm5, %mm3 C n - d
  339. C
  340. psubq %mm1, %mm3 C n - (q1+1)*d
  341. por %mm3, %mm0 C copy remainder -> new n2
  342. psrlq $32, %mm3 C high n - (q1+1)*d, 0 or -1
  343. ASSERT(be,`C 0 or -1
  344.  movd %mm3, %eax
  345.  addl $1, %eax
  346.  cmpl $1, %eax')
  347. paddd %mm3, %mm2 C q
  348. pand %mm5, %mm3 C mask & d
  349. paddd %mm3, %mm0 C addback if necessary
  350. movd %mm2, (%edi)
  351. leal -4(%edi), %edi
  352. subl $1, %ecx
  353. ja L(integer_top)
  354. L(integer_last):
  355. C eax
  356. C ebx xsize
  357. C ecx
  358. C edx
  359. C esi &src[0]
  360. C edi &dst[xsize]
  361. C
  362. C mm0 n2
  363. C mm4 m
  364. C mm5 d
  365. C mm6
  366. C mm7 l
  367. ASSERT(b,`C n2<d
  368.  movd %mm0, %eax
  369.  movd %mm5, %edx
  370.  cmpl %edx, %eax')
  371. movd (%esi), %mm1 C src[0]
  372. psllq %mm7, %mm1 C n10
  373. movq %mm1, %mm2 C n10
  374. movq %mm1, %mm3 C n10
  375. psrad $31, %mm1 C -n1
  376. pand %mm5, %mm1 C -n1 & d
  377. paddd %mm2, %mm1 C nadj = n10+(-n1&d), ignore overflow
  378. psrld $31, %mm2 C n1
  379. paddd %mm0, %mm2 C n2+n1
  380. punpckldq %mm0, %mm1 C n2:nadj
  381. pmuludq %mm4, %mm2 C m*(n2+n1)
  382. C
  383. paddq %mm2, %mm1 C n2:nadj + m*(n2+n1)
  384. pcmpeqd %mm2, %mm2 C FF...FF
  385. psrlq $63, %mm2 C 1
  386. psrlq $32, %mm1 C q1 = high(n2:nadj + m*(n2+n1))
  387. paddd %mm1, %mm2 C q1
  388. pmuludq %mm5, %mm1 C q1*d
  389. punpckldq %mm0, %mm3 C n
  390. psubq %mm5, %mm3 C n - d
  391. pxor %mm0, %mm0
  392. C
  393. psubq %mm1, %mm3 C n - (q1+1)*d
  394. por %mm3, %mm0 C remainder -> n2
  395. psrlq $32, %mm3 C high n - (q1+1)*d, 0 or -1
  396. ASSERT(be,`C 0 or -1
  397.  movd %mm3, %eax
  398.  addl $1, %eax
  399.  cmpl $1, %eax')
  400. paddd %mm3, %mm2 C q
  401. pand %mm5, %mm3 C mask & d
  402. paddd %mm3, %mm0 C addback if necessary
  403. movd %mm2, (%edi)
  404. leal -4(%edi), %edi
  405. L(integer_none):
  406. C eax
  407. C ebx xsize
  408. orl %ebx, %ebx
  409. jnz L(fraction_some) C if xsize!=0
  410. L(fraction_done):
  411. movl SAVE_EBP, %ebp
  412. psrld %mm7, %mm0 C remainder
  413. movl SAVE_EDI, %edi
  414. movd %mm0, %eax
  415. movl SAVE_ESI, %esi
  416. movl SAVE_EBX, %ebx
  417. emms
  418. ret
  419. C -----------------------------------------------------------------------------
  420. C
  421. L(fraction_some):
  422. C eax
  423. C ebx xsize
  424. C ecx
  425. C edx
  426. C esi
  427. C edi &dst[xsize-1]
  428. C ebp
  429. L(fraction_top):
  430. C eax
  431. C ebx counter, xsize iterations
  432. C ecx
  433. C edx
  434. C esi src, decrementing
  435. C edi dst, decrementing
  436. C
  437. C mm0 n2
  438. C mm4 m
  439. C mm5 d
  440. C mm6 32-l
  441. C mm7 l
  442. ASSERT(b,`C n2<d
  443.  movd %mm0, %eax
  444.  movd %mm5, %edx
  445.  cmpl %edx, %eax')
  446. movq %mm0, %mm1 C n2
  447. pmuludq %mm4, %mm0 C m*n2
  448. pcmpeqd %mm2, %mm2
  449. psrlq $63, %mm2
  450. C
  451. psrlq $32, %mm0 C high(m*n2)
  452. paddd %mm1, %mm0 C q1 = high(n2:0 + m*n2)
  453. paddd %mm0, %mm2 C q1+1
  454. pmuludq %mm5, %mm0 C q1*d
  455. psllq $32, %mm1 C n = n2:0
  456. psubq %mm5, %mm1 C n - d
  457. C
  458. psubq %mm0, %mm1 C r = n - (q1+1)*d
  459. pxor %mm0, %mm0
  460. por %mm1, %mm0 C r -> n2
  461. psrlq $32, %mm1 C high n - (q1+1)*d, 0 or -1
  462. ASSERT(be,`C 0 or -1
  463.  movd %mm1, %eax
  464.  addl $1, %eax
  465.  cmpl $1, %eax')
  466. paddd %mm1, %mm2 C q
  467. pand %mm5, %mm1 C mask & d
  468. paddd %mm1, %mm0 C addback if necessary
  469. movd %mm2, (%edi)
  470. leal -4(%edi), %edi
  471. subl $1, %ebx
  472. jne L(fraction_top)
  473. jmp L(fraction_done)
  474. EPILOGUE()