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

数学计算

开发平台:

Unix_Linux

  1. dnl  AMD K7 mpn_sqr_basecase -- square an mpn number.
  2. dnl  Copyright 1999, 2000, 2001, 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 K7: approx 2.3 cycles/crossproduct, or 4.55 cycles/triangular product
  20. C     (measured on the speed difference between 25 and 50 limbs, which is
  21. C     roughly the Karatsuba recursing range).
  22. dnl  These are the same as mpn/x86/k6/sqr_basecase.asm, see that code for
  23. dnl  some comments.
  24. deflit(SQR_TOOM2_THRESHOLD_MAX, 66)
  25. ifdef(`SQR_TOOM2_THRESHOLD_OVERRIDE',
  26. `define(`SQR_TOOM2_THRESHOLD',SQR_TOOM2_THRESHOLD_OVERRIDE)')
  27. m4_config_gmp_mparam(`SQR_TOOM2_THRESHOLD')
  28. deflit(UNROLL_COUNT, eval(SQR_TOOM2_THRESHOLD-3))
  29. C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size);
  30. C
  31. C With a SQR_TOOM2_THRESHOLD around 50 this code is about 1500 bytes,
  32. C which is quite a bit, but is considered good value since squares big
  33. C enough to use most of the code will be spending quite a few cycles in it.
  34. defframe(PARAM_SIZE,12)
  35. defframe(PARAM_SRC, 8)
  36. defframe(PARAM_DST, 4)
  37. TEXT
  38. ALIGN(32)
  39. PROLOGUE(mpn_sqr_basecase)
  40. deflit(`FRAME',0)
  41. movl PARAM_SIZE, %ecx
  42. movl PARAM_SRC, %eax
  43. cmpl $2, %ecx
  44. movl PARAM_DST, %edx
  45. je L(two_limbs)
  46. ja L(three_or_more)
  47. C------------------------------------------------------------------------------
  48. C one limb only
  49. C eax src
  50. C ecx size
  51. C edx dst
  52. movl (%eax), %eax
  53. movl %edx, %ecx
  54. mull %eax
  55. movl %edx, 4(%ecx)
  56. movl %eax, (%ecx)
  57. ret
  58. C------------------------------------------------------------------------------
  59. C
  60. C Using the read/modify/write "add"s seems to be faster than saving and
  61. C restoring registers.  Perhaps the loads for the first set hide under the
  62. C mul latency and the second gets store to load forwarding.
  63. ALIGN(16)
  64. L(two_limbs):
  65. C eax src
  66. C ebx
  67. C ecx size
  68. C edx dst
  69. deflit(`FRAME',0)
  70. pushl %ebx FRAME_pushl()
  71. movl %eax, %ebx C src
  72. movl (%eax), %eax
  73. movl %edx, %ecx C dst
  74. mull %eax C src[0]^2
  75. movl %eax, (%ecx) C dst[0]
  76. movl 4(%ebx), %eax
  77. movl %edx, 4(%ecx) C dst[1]
  78. mull %eax C src[1]^2
  79. movl %eax, 8(%ecx) C dst[2]
  80. movl (%ebx), %eax
  81. movl %edx, 12(%ecx) C dst[3]
  82. mull 4(%ebx) C src[0]*src[1]
  83. popl %ebx
  84. addl %eax, 4(%ecx)
  85. adcl %edx, 8(%ecx)
  86. adcl $0, 12(%ecx)
  87. ASSERT(nc)
  88. addl %eax, 4(%ecx)
  89. adcl %edx, 8(%ecx)
  90. adcl $0, 12(%ecx)
  91. ASSERT(nc)
  92. ret
  93. C------------------------------------------------------------------------------
  94. defframe(SAVE_EBX,  -4)
  95. defframe(SAVE_ESI,  -8)
  96. defframe(SAVE_EDI, -12)
  97. defframe(SAVE_EBP, -16)
  98. deflit(STACK_SPACE, 16)
  99. L(three_or_more):
  100. subl $STACK_SPACE, %esp
  101. cmpl $4, %ecx
  102. jae L(four_or_more)
  103. deflit(`FRAME',STACK_SPACE)
  104. C------------------------------------------------------------------------------
  105. C Three limbs
  106. C
  107. C Writing out the loads and stores separately at the end of this code comes
  108. C out about 10 cycles faster than using adcls to memory.
  109. C eax src
  110. C ecx size
  111. C edx dst
  112. movl %ebx, SAVE_EBX
  113. movl %eax, %ebx C src
  114. movl (%eax), %eax
  115. movl %edx, %ecx C dst
  116. movl %esi, SAVE_ESI
  117. movl %edi, SAVE_EDI
  118. mull %eax C src[0] ^ 2
  119. movl %eax, (%ecx)
  120. movl 4(%ebx), %eax
  121. movl %edx, 4(%ecx)
  122. mull %eax C src[1] ^ 2
  123. movl %eax, 8(%ecx)
  124. movl 8(%ebx), %eax
  125. movl %edx, 12(%ecx)
  126. mull %eax C src[2] ^ 2
  127. movl %eax, 16(%ecx)
  128. movl (%ebx), %eax
  129. movl %edx, 20(%ecx)
  130. mull 4(%ebx) C src[0] * src[1]
  131. movl %eax, %esi
  132. movl (%ebx), %eax
  133. movl %edx, %edi
  134. mull 8(%ebx) C src[0] * src[2]
  135. addl %eax, %edi
  136. movl %ebp, SAVE_EBP
  137. movl $0, %ebp
  138. movl 4(%ebx), %eax
  139. adcl %edx, %ebp
  140. mull 8(%ebx) C src[1] * src[2]
  141. xorl %ebx, %ebx
  142. addl %eax, %ebp
  143. adcl $0, %edx
  144. C eax
  145. C ebx zero, will be dst[5]
  146. C ecx dst
  147. C edx dst[4]
  148. C esi dst[1]
  149. C edi dst[2]
  150. C ebp dst[3]
  151. adcl $0, %edx
  152. addl %esi, %esi
  153. adcl %edi, %edi
  154. movl 4(%ecx), %eax
  155. adcl %ebp, %ebp
  156. adcl %edx, %edx
  157. adcl $0, %ebx
  158. addl %eax, %esi
  159. movl 8(%ecx), %eax
  160. adcl %eax, %edi
  161. movl 12(%ecx), %eax
  162. movl %esi, 4(%ecx)
  163. adcl %eax, %ebp
  164. movl 16(%ecx), %eax
  165. movl %edi, 8(%ecx)
  166. movl SAVE_ESI, %esi
  167. movl SAVE_EDI, %edi
  168. adcl %eax, %edx
  169. movl 20(%ecx), %eax
  170. movl %ebp, 12(%ecx)
  171. adcl %ebx, %eax
  172. ASSERT(nc)
  173. movl SAVE_EBX, %ebx
  174. movl SAVE_EBP, %ebp
  175. movl %edx, 16(%ecx)
  176. movl %eax, 20(%ecx)
  177. addl $FRAME, %esp
  178. ret
  179. C------------------------------------------------------------------------------
  180. L(four_or_more):
  181. C First multiply src[0]*src[1..size-1] and store at dst[1..size].
  182. C Further products are added in rather than stored.
  183. C eax src
  184. C ebx
  185. C ecx size
  186. C edx dst
  187. C esi
  188. C edi
  189. C ebp
  190. defframe(`VAR_COUNTER',-20)
  191. defframe(`VAR_JMP',    -24)
  192. deflit(EXTRA_STACK_SPACE, 8)
  193. movl %ebx, SAVE_EBX
  194. movl %edi, SAVE_EDI
  195. leal (%edx,%ecx,4), %edi C &dst[size]
  196. movl %esi, SAVE_ESI
  197. movl %ebp, SAVE_EBP
  198. leal (%eax,%ecx,4), %esi C &src[size]
  199. movl (%eax), %ebp C multiplier
  200. movl $0, %ebx
  201. decl %ecx
  202. negl %ecx
  203. subl $EXTRA_STACK_SPACE, %esp
  204. FRAME_subl_esp(EXTRA_STACK_SPACE)
  205. L(mul_1):
  206. C eax scratch
  207. C ebx carry
  208. C ecx counter
  209. C edx scratch
  210. C esi &src[size]
  211. C edi &dst[size]
  212. C ebp multiplier
  213. movl (%esi,%ecx,4), %eax
  214. mull %ebp
  215. addl %ebx, %eax
  216. movl %eax, (%edi,%ecx,4)
  217. movl $0, %ebx
  218. adcl %edx, %ebx
  219. incl %ecx
  220. jnz L(mul_1)
  221. C Add products src[n]*src[n+1..size-1] at dst[2*n-1...], for each n=1..size-2.
  222. C
  223. C The last two products, which are the bottom right corner of the product
  224. C triangle, are left to the end.  These are src[size-3]*src[size-2,size-1]
  225. C and src[size-2]*src[size-1].  If size is 4 then it's only these corner
  226. C cases that need to be done.
  227. C
  228. C The unrolled code is the same as in mpn_addmul_1, see that routine for
  229. C some comments.
  230. C
  231. C VAR_COUNTER is the outer loop, running from -size+4 to -1, inclusive.
  232. C
  233. C VAR_JMP is the computed jump into the unrolled code, stepped by one code
  234. C chunk each outer loop.
  235. C
  236. C K7 does branch prediction on indirect jumps, which is bad since it's a
  237. C different target each time.  There seems no way to avoid this.
  238. dnl  This value also hard coded in some shifts and adds
  239. deflit(CODE_BYTES_PER_LIMB, 17)
  240. dnl  With the unmodified &src[size] and &dst[size] pointers, the
  241. dnl  displacements in the unrolled code fit in a byte for UNROLL_COUNT
  242. dnl  values up to 31, but above that an offset must be added to them.
  243. deflit(OFFSET,
  244. ifelse(eval(UNROLL_COUNT>31),1,
  245. eval((UNROLL_COUNT-31)*4),
  246. 0))
  247. dnl  Because the last chunk of code is generated differently, a label placed
  248. dnl  at the end doesn't work.  Instead calculate the implied end using the
  249. dnl  start and how many chunks of code there are.
  250. deflit(UNROLL_INNER_END,
  251. `L(unroll_inner_start)+eval(UNROLL_COUNT*CODE_BYTES_PER_LIMB)')
  252. C eax
  253. C ebx carry
  254. C ecx
  255. C edx
  256. C esi &src[size]
  257. C edi &dst[size]
  258. C ebp
  259. movl PARAM_SIZE, %ecx
  260. movl %ebx, (%edi)
  261. subl $4, %ecx
  262. jz L(corner)
  263. negl %ecx
  264. ifelse(OFFSET,0,,`subl $OFFSET, %edi')
  265. ifelse(OFFSET,0,,`subl $OFFSET, %esi')
  266. movl %ecx, %edx
  267. shll $4, %ecx
  268. ifdef(`PIC',`
  269. call L(pic_calc)
  270. L(here):
  271. ',`
  272. leal UNROLL_INNER_END-eval(2*CODE_BYTES_PER_LIMB)(%ecx,%edx), %ecx
  273. ')
  274. C The calculated jump mustn't come out to before the start of the
  275. C code available.  This is the limit UNROLL_COUNT puts on the src
  276. C operand size, but checked here directly using the jump address.
  277. ASSERT(ae,
  278. `movl_text_address(L(unroll_inner_start), %eax)
  279. cmpl %eax, %ecx')
  280. C------------------------------------------------------------------------------
  281. ALIGN(16)
  282. L(unroll_outer_top):
  283. C eax
  284. C ebx high limb to store
  285. C ecx VAR_JMP
  286. C edx VAR_COUNTER, limbs, negative
  287. C esi &src[size], constant
  288. C edi dst ptr, high of last addmul
  289. C ebp
  290. movl -12+OFFSET(%esi,%edx,4), %ebp C next multiplier
  291. movl -8+OFFSET(%esi,%edx,4), %eax C first of multiplicand
  292. movl %edx, VAR_COUNTER
  293. mull %ebp
  294. define(cmovX,`ifelse(eval(UNROLL_COUNT%2),0,`cmovz($@)',`cmovnz($@)')')
  295. testb $1, %cl
  296. movl %edx, %ebx C high carry
  297. movl %ecx, %edx C jump
  298. movl %eax, %ecx C low carry
  299. cmovX( %ebx, %ecx) C high carry reverse
  300. cmovX( %eax, %ebx) C low carry reverse
  301. leal CODE_BYTES_PER_LIMB(%edx), %eax
  302. xorl %edx, %edx
  303. leal 4(%edi), %edi
  304. movl %eax, VAR_JMP
  305. jmp *%eax
  306. ifdef(`PIC',`
  307. L(pic_calc):
  308. addl (%esp), %ecx
  309. addl $UNROLL_INNER_END-eval(2*CODE_BYTES_PER_LIMB)-L(here), %ecx
  310. addl %edx, %ecx
  311. ret_internal
  312. ')
  313. C Must be an even address to preserve the significance of the low
  314. C bit of the jump address indicating which way around ecx/ebx should
  315. C start.
  316. ALIGN(2)
  317. L(unroll_inner_start):
  318. C eax next limb
  319. C ebx carry high
  320. C ecx carry low
  321. C edx scratch
  322. C esi src
  323. C edi dst
  324. C ebp multiplier
  325. forloop(`i', UNROLL_COUNT, 1, `
  326. deflit(`disp_src', eval(-i*4 + OFFSET))
  327. deflit(`disp_dst', eval(disp_src - 4))
  328. m4_assert(`disp_src>=-128 && disp_src<128')
  329. m4_assert(`disp_dst>=-128 && disp_dst<128')
  330. ifelse(eval(i%2),0,`
  331. Zdisp( movl, disp_src,(%esi), %eax)
  332. adcl %edx, %ebx
  333. mull %ebp
  334. Zdisp(  addl, %ecx, disp_dst,(%edi))
  335. movl $0, %ecx
  336. adcl %eax, %ebx
  337. ',`
  338. dnl  this bit comes out last
  339. Zdisp(  movl, disp_src,(%esi), %eax)
  340. adcl %edx, %ecx
  341. mull %ebp
  342. Zdisp( addl, %ebx, disp_dst,(%edi))
  343. ifelse(forloop_last,0,
  344. ` movl $0, %ebx')
  345. adcl %eax, %ecx
  346. ')
  347. ')
  348. C eax next limb
  349. C ebx carry high
  350. C ecx carry low
  351. C edx scratch
  352. C esi src
  353. C edi dst
  354. C ebp multiplier
  355. adcl $0, %edx
  356. addl %ecx, -4+OFFSET(%edi)
  357. movl VAR_JMP, %ecx
  358. adcl $0, %edx
  359. movl %edx, m4_empty_if_zero(OFFSET) (%edi)
  360. movl VAR_COUNTER, %edx
  361. incl %edx
  362. jnz L(unroll_outer_top)
  363. ifelse(OFFSET,0,,`
  364. addl $OFFSET, %esi
  365. addl $OFFSET, %edi
  366. ')
  367. C------------------------------------------------------------------------------
  368. L(corner):
  369. C esi &src[size]
  370. C edi &dst[2*size-5]
  371. movl -12(%esi), %ebp
  372. movl -8(%esi), %eax
  373. movl %eax, %ecx
  374. mull %ebp
  375. addl %eax, -4(%edi)
  376. movl -4(%esi), %eax
  377. adcl $0, %edx
  378. movl %edx, %ebx
  379. movl %eax, %esi
  380. mull %ebp
  381. addl %ebx, %eax
  382. adcl $0, %edx
  383. addl %eax, (%edi)
  384. movl %esi, %eax
  385. adcl $0, %edx
  386. movl %edx, %ebx
  387. mull %ecx
  388. addl %ebx, %eax
  389. movl %eax, 4(%edi)
  390. adcl $0, %edx
  391. movl %edx, 8(%edi)
  392. C Left shift of dst[1..2*size-2], high bit shifted out becomes dst[2*size-1].
  393. L(lshift_start):
  394. movl PARAM_SIZE, %eax
  395. movl PARAM_DST, %edi
  396. xorl %ecx, %ecx C clear carry
  397. leal (%edi,%eax,8), %edi
  398. notl %eax C -size-1, preserve carry
  399. leal 2(%eax), %eax C -(size-1)
  400. L(lshift):
  401. C eax counter, negative
  402. C ebx
  403. C ecx
  404. C edx
  405. C esi
  406. C edi dst, pointing just after last limb
  407. C ebp
  408. rcll -4(%edi,%eax,8)
  409. rcll (%edi,%eax,8)
  410. incl %eax
  411. jnz L(lshift)
  412. setc %al
  413. movl PARAM_SRC, %esi
  414. movl %eax, -4(%edi) C dst most significant limb
  415. movl PARAM_SIZE, %ecx
  416. C Now add in the squares on the diagonal, src[0]^2, src[1]^2, ...,
  417. C src[size-1]^2.  dst[0] hasn't yet been set at all yet, and just gets the
  418. C low limb of src[0]^2.
  419. movl (%esi), %eax C src[0]
  420. mull %eax
  421. leal (%esi,%ecx,4), %esi C src point just after last limb
  422. negl %ecx
  423. movl %eax, (%edi,%ecx,8) C dst[0]
  424. incl %ecx
  425. L(diag):
  426. C eax scratch
  427. C ebx scratch
  428. C ecx counter, negative
  429. C edx carry
  430. C esi src just after last limb
  431. C edi dst just after last limb
  432. C ebp
  433. movl (%esi,%ecx,4), %eax
  434. movl %edx, %ebx
  435. mull %eax
  436. addl %ebx, -4(%edi,%ecx,8)
  437. adcl %eax, (%edi,%ecx,8)
  438. adcl $0, %edx
  439. incl %ecx
  440. jnz L(diag)
  441. movl SAVE_ESI, %esi
  442. movl SAVE_EBX, %ebx
  443. addl %edx, -4(%edi) C dst most significant limb
  444. movl SAVE_EDI, %edi
  445. movl SAVE_EBP, %ebp
  446. addl $FRAME, %esp
  447. ret
  448. EPILOGUE()