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

数学计算

开发平台:

Unix_Linux

  1. dnl  Intel P6 mpn_mul_basecase -- multiply two mpn numbers.
  2. dnl  Copyright 1999, 2000, 2001, 2002, 2003 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 P6: approx 6.5 cycles per cross product (16 limbs/loop unrolling).
  20. dnl  P6 UNROLL_COUNT cycles/product (approx)
  21. dnl           8           7
  22. dnl          16           6.5
  23. dnl          32           6.4
  24. dnl  Maximum possible with the current code is 32.
  25. deflit(UNROLL_COUNT, 16)
  26. C void mpn_mul_basecase (mp_ptr wp,
  27. C                        mp_srcptr xp, mp_size_t xsize,
  28. C                        mp_srcptr yp, mp_size_t ysize);
  29. C
  30. C This routine is essentially the same as mpn/generic/mul_basecase.c, but
  31. C it's faster because it does most of the mpn_addmul_1() startup
  32. C calculations only once.
  33. ifdef(`PIC',`
  34. deflit(UNROLL_THRESHOLD, 5)
  35. ',`
  36. deflit(UNROLL_THRESHOLD, 5)
  37. ')
  38. defframe(PARAM_YSIZE,20)
  39. defframe(PARAM_YP,   16)
  40. defframe(PARAM_XSIZE,12)
  41. defframe(PARAM_XP,   8)
  42. defframe(PARAM_WP,   4)
  43. TEXT
  44. ALIGN(16)
  45. PROLOGUE(mpn_mul_basecase)
  46. deflit(`FRAME',0)
  47. movl PARAM_XSIZE, %ecx
  48. movl PARAM_YP, %eax
  49. movl PARAM_XP, %edx
  50. movl (%eax), %eax C yp[0]
  51. cmpl $2, %ecx
  52. ja L(xsize_more_than_two)
  53. je L(two_by_something)
  54. C one limb by one limb
  55. mull (%edx)
  56. movl PARAM_WP, %ecx
  57. movl %eax, (%ecx)
  58. movl %edx, 4(%ecx)
  59. ret
  60. C -----------------------------------------------------------------------------
  61. L(two_by_something):
  62. deflit(`FRAME',0)
  63. dnl  re-use parameter space
  64. define(SAVE_EBX, `PARAM_XSIZE')
  65. define(SAVE_ESI, `PARAM_YSIZE')
  66. movl %ebx, SAVE_EBX
  67. cmpl $1, PARAM_YSIZE
  68. movl %eax, %ecx C yp[0]
  69. movl %esi, SAVE_ESI C save esi
  70. movl PARAM_WP, %ebx
  71. movl %edx, %esi C xp
  72. movl (%edx), %eax C xp[0]
  73. jne L(two_by_two)
  74. C two limbs by one limb
  75. C
  76. C eax xp[0]
  77. C ebx wp
  78. C ecx yp[0]
  79. C edx
  80. C esi xp
  81. mull %ecx
  82. movl %eax, (%ebx)
  83. movl 4(%esi), %eax
  84. movl %edx, %esi C carry
  85. mull %ecx
  86. addl %eax, %esi
  87. movl %esi, 4(%ebx)
  88. movl SAVE_ESI, %esi
  89. adcl $0, %edx
  90. movl %edx, 8(%ebx)
  91. movl SAVE_EBX, %ebx
  92. ret
  93. C -----------------------------------------------------------------------------
  94. ALIGN(16)
  95. L(two_by_two):
  96. C eax xp[0]
  97. C ebx wp
  98. C ecx yp[0]
  99. C edx
  100. C esi xp
  101. C edi
  102. C ebp
  103. dnl  more parameter space re-use
  104. define(SAVE_EDI, `PARAM_WP')
  105. mull %ecx C xp[0] * yp[0]
  106. movl %edi, SAVE_EDI
  107. movl %edx, %edi C carry, for wp[1]
  108. movl %eax, (%ebx)
  109. movl 4(%esi), %eax
  110. mull %ecx C xp[1] * yp[0]
  111. addl %eax, %edi
  112. movl PARAM_YP, %ecx
  113. adcl $0, %edx
  114. movl 4(%ecx), %ecx C yp[1]
  115. movl %edi, 4(%ebx)
  116. movl 4(%esi), %eax C xp[1]
  117. movl %edx, %edi C carry, for wp[2]
  118. mull %ecx C xp[1] * yp[1]
  119. addl %eax, %edi
  120. movl (%esi), %eax C xp[0]
  121. adcl $0, %edx
  122. movl %edx, %esi C carry, for wp[3]
  123. mull %ecx C xp[0] * yp[1]
  124. addl %eax, 4(%ebx)
  125. movl %esi, %eax
  126. adcl %edx, %edi
  127. movl SAVE_ESI, %esi
  128. movl %edi, 8(%ebx)
  129. adcl $0, %eax
  130. movl SAVE_EDI, %edi
  131. movl %eax, 12(%ebx)
  132. movl SAVE_EBX, %ebx
  133. ret
  134. C -----------------------------------------------------------------------------
  135. ALIGN(16)
  136. L(xsize_more_than_two):
  137. C The first limb of yp is processed with a simple mpn_mul_1 loop running at
  138. C about 6.2 c/l.  Unrolling this doesn't seem worthwhile since it's only run
  139. C once (whereas the addmul_1 below is run ysize-1 many times).  A call to
  140. C mpn_mul_1 would be slowed down by the parameter pushing and popping etc,
  141. C and doesn't seem likely to be worthwhile on the typical sizes reaching
  142. C here from the Karatsuba code.
  143. C eax yp[0]
  144. C ebx
  145. C ecx xsize
  146. C edx xp
  147. C esi
  148. C edi
  149. C ebp
  150. defframe(`SAVE_EBX',    -4)
  151. defframe(`SAVE_ESI',    -8)
  152. defframe(`SAVE_EDI',   -12)
  153. defframe(`SAVE_EBP',   -16)
  154. defframe(VAR_COUNTER,  -20)  dnl for use in the unroll case
  155. defframe(VAR_ADJUST,   -24)
  156. defframe(VAR_JMP,      -28)
  157. defframe(VAR_SWAP,     -32)
  158. defframe(VAR_XP_LOW,   -36)
  159. deflit(STACK_SPACE, 36)
  160. subl $STACK_SPACE, %esp
  161. deflit(`FRAME',STACK_SPACE)
  162. movl %edi, SAVE_EDI
  163. movl PARAM_WP, %edi
  164. movl %ebx, SAVE_EBX
  165. movl %ebp, SAVE_EBP
  166. movl %eax, %ebp
  167. movl %esi, SAVE_ESI
  168. xorl %ebx, %ebx
  169. leal (%edx,%ecx,4), %esi C xp end
  170. leal (%edi,%ecx,4), %edi C wp end of mul1
  171. negl %ecx
  172. L(mul1):
  173. C eax scratch
  174. C ebx carry
  175. C ecx counter, negative
  176. C edx scratch
  177. C esi xp end
  178. C edi wp end of mul1
  179. C ebp multiplier
  180. movl (%esi,%ecx,4), %eax
  181. mull %ebp
  182. addl %ebx, %eax
  183. movl %eax, (%edi,%ecx,4)
  184. movl $0, %ebx
  185. adcl %edx, %ebx
  186. incl %ecx
  187. jnz L(mul1)
  188. movl PARAM_YSIZE, %edx
  189. movl %ebx, (%edi) C final carry
  190. movl PARAM_XSIZE, %ecx
  191. decl %edx
  192. jz L(done) C if ysize==1
  193. cmpl $UNROLL_THRESHOLD, %ecx
  194. movl PARAM_YP, %eax
  195. jae L(unroll)
  196. C -----------------------------------------------------------------------------
  197. C simple addmul looping
  198. C
  199. C eax yp
  200. C ebx
  201. C ecx xsize
  202. C edx ysize-1
  203. C esi xp end
  204. C edi wp end of mul1
  205. C ebp
  206. leal 4(%eax,%edx,4), %ebp C yp end
  207. negl %ecx
  208. negl %edx
  209. movl %edx, PARAM_YSIZE C -(ysize-1)
  210. movl (%esi,%ecx,4), %eax C xp low limb
  211. incl %ecx
  212. movl %ecx, PARAM_XSIZE C -(xsize-1)
  213. xorl %ebx, %ebx C initial carry
  214. movl %ebp, PARAM_YP
  215. movl (%ebp,%edx,4), %ebp C yp second lowest limb - multiplier
  216. jmp L(simple_outer_entry)
  217. L(simple_outer_top):
  218. C ebp ysize counter, negative
  219. movl PARAM_YP, %edx
  220. movl PARAM_XSIZE, %ecx C -(xsize-1)
  221. xorl %ebx, %ebx C carry
  222. movl %ebp, PARAM_YSIZE
  223. addl $4, %edi C next position in wp
  224. movl (%edx,%ebp,4), %ebp C yp limb - multiplier
  225. movl -4(%esi,%ecx,4), %eax C xp low limb
  226. L(simple_outer_entry):
  227. L(simple_inner_top):
  228. C eax xp limb
  229. C ebx carry limb
  230. C ecx loop counter (negative)
  231. C edx scratch
  232. C esi xp end
  233. C edi wp end
  234. C ebp multiplier
  235. mull %ebp
  236. addl %eax, %ebx
  237. adcl $0, %edx
  238. addl %ebx, (%edi,%ecx,4)
  239. movl (%esi,%ecx,4), %eax
  240. adcl $0, %edx
  241. incl %ecx
  242. movl %edx, %ebx
  243. jnz L(simple_inner_top)
  244. C separate code for last limb so outer loop counter handling can be
  245. C interleaved
  246. mull %ebp
  247. movl PARAM_YSIZE, %ebp
  248. addl %eax, %ebx
  249. adcl $0, %edx
  250. addl %ebx, (%edi)
  251. adcl $0, %edx
  252. incl %ebp
  253. movl %edx, 4(%edi)
  254. jnz L(simple_outer_top)
  255. L(done):
  256. movl SAVE_EBX, %ebx
  257. movl SAVE_ESI, %esi
  258. movl SAVE_EDI, %edi
  259. movl SAVE_EBP, %ebp
  260. addl $FRAME, %esp
  261. ret
  262. C -----------------------------------------------------------------------------
  263. C
  264. C The unrolled loop is the same as in mpn_addmul_1, see that code for some
  265. C comments.
  266. C
  267. C VAR_ADJUST is the negative of how many limbs the leals in the inner loop
  268. C increment xp and wp.  This is used to adjust xp and wp, and is rshifted to
  269. C given an initial VAR_COUNTER at the top of the outer loop.
  270. C
  271. C VAR_COUNTER is for the unrolled loop, running from VAR_ADJUST/UNROLL_COUNT
  272. C up to -1, inclusive.
  273. C
  274. C VAR_JMP is the computed jump into the unrolled loop.
  275. C
  276. C VAR_SWAP is 0 if xsize odd or 0xFFFFFFFF if xsize even, used to swap the
  277. C initial ebx and ecx on entry to the unrolling.
  278. C
  279. C VAR_XP_LOW is the least significant limb of xp, which is needed at the
  280. C start of the unrolled loop.
  281. C
  282. C PARAM_YSIZE is the outer loop counter, going from -(ysize-1) up to -1,
  283. C inclusive.
  284. C
  285. C PARAM_YP is offset appropriately so that the PARAM_YSIZE counter can be
  286. C added to give the location of the next limb of yp, which is the multiplier
  287. C in the unrolled loop.
  288. C
  289. C The trick with the VAR_ADJUST value means it's only necessary to do one
  290. C fetch in the outer loop to take care of xp, wp and the inner loop counter.
  291. L(unroll):
  292. C eax yp
  293. C ebx
  294. C ecx xsize
  295. C edx ysize-1
  296. C esi xp end
  297. C edi wp end of mul1
  298. C ebp
  299. movl PARAM_XP, %esi
  300. movl 4(%eax), %ebp C multiplier (yp second limb)
  301. leal 4(%eax,%edx,4), %eax C yp adjust for ysize indexing
  302. movl %eax, PARAM_YP
  303. movl PARAM_WP, %edi
  304. negl %edx
  305. movl %edx, PARAM_YSIZE
  306. leal UNROLL_COUNT-2(%ecx), %ebx C (xsize-1)+UNROLL_COUNT-1
  307. decl %ecx C xsize-1
  308. movl (%esi), %eax C xp low limb
  309. andl $-UNROLL_MASK-1, %ebx
  310. negl %ecx C -(xsize-1)
  311. negl %ebx
  312. andl $UNROLL_MASK, %ecx
  313. movl %ebx, VAR_ADJUST
  314. movl %ecx, %edx
  315. shll $4, %ecx
  316. movl %eax, VAR_XP_LOW
  317. sarl $UNROLL_LOG2, %ebx
  318. negl %edx
  319. C 15 code bytes per limb
  320. ifdef(`PIC',`
  321. call L(pic_calc)
  322. L(unroll_here):
  323. ',`
  324. leal L(unroll_inner_entry) (%ecx,%edx,1), %ecx
  325. ')
  326. movl %ecx, VAR_JMP
  327. movl %edx, %ecx
  328. shll $31, %edx
  329. sarl $31, %edx C 0 or -1 as xsize odd or even
  330. leal 4(%edi,%ecx,4), %edi C wp and xp, adjust for unrolling,
  331. leal 4(%esi,%ecx,4), %esi C  and start at second limb
  332. movl %edx, VAR_SWAP
  333. jmp L(unroll_outer_entry)
  334. ifdef(`PIC',`
  335. L(pic_calc):
  336. C See mpn/x86/README about old gas bugs
  337. leal (%ecx,%edx,1), %ecx
  338. addl $L(unroll_inner_entry)-L(unroll_here), %ecx
  339. addl (%esp), %ecx
  340. ret_internal
  341. ')
  342. C --------------------------------------------------------------------------
  343. ALIGN(16)
  344. L(unroll_outer_top):
  345. C eax
  346. C ebx
  347. C ecx
  348. C edx
  349. C esi xp + offset
  350. C edi wp + offset
  351. C ebp ysize counter, negative
  352. movl VAR_ADJUST, %ebx
  353. movl PARAM_YP, %edx
  354. movl VAR_XP_LOW, %eax
  355. movl %ebp, PARAM_YSIZE C store incremented ysize counter
  356. leal eval(UNROLL_BYTES + 4) (%edi,%ebx,4), %edi
  357. leal (%esi,%ebx,4), %esi
  358. sarl $UNROLL_LOG2, %ebx
  359. movl (%edx,%ebp,4), %ebp C yp next multiplier
  360. L(unroll_outer_entry):
  361. mull %ebp
  362. movl %ebx, VAR_COUNTER
  363. movl %edx, %ebx C carry high
  364. movl %eax, %ecx C carry low
  365. xorl %edx, %eax
  366. movl VAR_JMP, %edx
  367. andl VAR_SWAP, %eax
  368. xorl %eax, %ebx C carries other way for odd index
  369. xorl %eax, %ecx
  370. jmp *%edx
  371. C -----------------------------------------------------------------------------
  372. L(unroll_inner_top):
  373. C eax xp limb
  374. C ebx carry high
  375. C ecx carry low
  376. C edx scratch
  377. C esi xp+8
  378. C edi wp
  379. C ebp yp multiplier limb
  380. C
  381. C VAR_COUNTER  loop counter, negative
  382. C
  383. C 15 bytes each limb
  384. addl $UNROLL_BYTES, %edi
  385. L(unroll_inner_entry):
  386. deflit(CHUNK_COUNT,2)
  387. forloop(`i', 0, UNROLL_COUNT/CHUNK_COUNT-1, `
  388. deflit(`disp0', eval(i*CHUNK_COUNT*4 ifelse(UNROLL_BYTES,256,-128)))
  389. deflit(`disp1', eval(disp0 + 4))
  390. Zdisp( movl, disp0,(%esi), %eax)
  391. mull %ebp
  392. Zdisp( addl, %ecx, disp0,(%edi))
  393. adcl %eax, %ebx C new carry low
  394. movl %edx, %ecx
  395. adcl $0, %ecx C new carry high
  396. movl disp1(%esi), %eax
  397. mull %ebp
  398. addl %ebx, disp1(%edi)
  399. adcl %eax, %ecx C new carry low
  400. movl %edx, %ebx
  401. adcl $0, %ebx C new carry high
  402. ')
  403. incl VAR_COUNTER
  404. leal UNROLL_BYTES(%esi), %esi
  405. jnz L(unroll_inner_top)
  406. C eax
  407. C ebx carry high
  408. C ecx carry low
  409. C edx
  410. C esi
  411. C edi wp, pointing at second last limb)
  412. C ebp
  413. deflit(`disp0', eval(UNROLL_BYTES ifelse(UNROLL_BYTES,256,-128)))
  414. deflit(`disp1', eval(disp0 + 4))
  415. movl PARAM_YSIZE, %ebp
  416. addl %ecx, disp0(%edi) C carry low
  417. adcl $0, %ebx
  418. incl %ebp
  419. movl %ebx, disp1(%edi) C carry high
  420. jnz L(unroll_outer_top)
  421. movl SAVE_ESI, %esi
  422. movl SAVE_EBP, %ebp
  423. movl SAVE_EDI, %edi
  424. movl SAVE_EBX, %ebx
  425. addl $FRAME, %esp
  426. ret
  427. EPILOGUE()