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

数学计算

开发平台:

Unix_Linux

  1. dnl  AMD K6 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 K6: approx 4.7 cycles per cross product, or 9.2 cycles per triangular
  20. C     product (measured on the speed difference between 17 and 33 limbs,
  21. C     which is roughly the Karatsuba recursing range).
  22. dnl  SQR_TOOM2_THRESHOLD_MAX is the maximum SQR_TOOM2_THRESHOLD this
  23. dnl  code supports.  This value is used only by the tune program to know
  24. dnl  what it can go up to.  (An attempt to compile with a bigger value will
  25. dnl  trigger some m4_assert()s in the code, making the build fail.)
  26. dnl
  27. dnl  The value is determined by requiring the displacements in the unrolled
  28. dnl  addmul to fit in single bytes.  This means a maximum UNROLL_COUNT of
  29. dnl  63, giving a maximum SQR_TOOM2_THRESHOLD of 66.
  30. deflit(SQR_TOOM2_THRESHOLD_MAX, 66)
  31. dnl  Allow a value from the tune program to override config.m4.
  32. ifdef(`SQR_TOOM2_THRESHOLD_OVERRIDE',
  33. `define(`SQR_TOOM2_THRESHOLD',SQR_TOOM2_THRESHOLD_OVERRIDE)')
  34. dnl  UNROLL_COUNT is the number of code chunks in the unrolled addmul.  The
  35. dnl  number required is determined by SQR_TOOM2_THRESHOLD, since
  36. dnl  mpn_sqr_basecase only needs to handle sizes < SQR_TOOM2_THRESHOLD.
  37. dnl
  38. dnl  The first addmul is the biggest, and this takes the second least
  39. dnl  significant limb and multiplies it by the third least significant and
  40. dnl  up.  Hence for a maximum operand size of SQR_TOOM2_THRESHOLD-1
  41. dnl  limbs, UNROLL_COUNT needs to be SQR_TOOM2_THRESHOLD-3.
  42. m4_config_gmp_mparam(`SQR_TOOM2_THRESHOLD')
  43. deflit(UNROLL_COUNT, eval(SQR_TOOM2_THRESHOLD-3))
  44. C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size);
  45. C
  46. C The algorithm is essentially the same as mpn/generic/sqr_basecase.c, but a
  47. C lot of function call overheads are avoided, especially when the given size
  48. C is small.
  49. C
  50. C The code size might look a bit excessive, but not all of it is executed
  51. C and so won't fill up the code cache.  The 1x1, 2x2 and 3x3 special cases
  52. C clearly apply only to those sizes; mid sizes like 10x10 only need part of
  53. C the unrolled addmul; and big sizes like 35x35 that do need all of it will
  54. C at least be getting value for money, because 35x35 spends something like
  55. C 5780 cycles here.
  56. C
  57. C Different values of UNROLL_COUNT give slightly different speeds, between
  58. C 9.0 and 9.2 c/tri-prod measured on the difference between 17 and 33 limbs.
  59. C This isn't a big difference, but it's presumably some alignment effect
  60. C which if understood could give a simple speedup.
  61. defframe(PARAM_SIZE,12)
  62. defframe(PARAM_SRC, 8)
  63. defframe(PARAM_DST, 4)
  64. TEXT
  65. ALIGN(32)
  66. PROLOGUE(mpn_sqr_basecase)
  67. deflit(`FRAME',0)
  68. movl PARAM_SIZE, %ecx
  69. movl PARAM_SRC, %eax
  70. cmpl $2, %ecx
  71. je L(two_limbs)
  72. movl PARAM_DST, %edx
  73. ja L(three_or_more)
  74. C -----------------------------------------------------------------------------
  75. C one limb only
  76. C eax src
  77. C ebx
  78. C ecx size
  79. C edx dst
  80. movl (%eax), %eax
  81. movl %edx, %ecx
  82. mull %eax
  83. movl %eax, (%ecx)
  84. movl %edx, 4(%ecx)
  85. ret
  86. C -----------------------------------------------------------------------------
  87. ALIGN(16)
  88. L(two_limbs):
  89. C eax src
  90. C ebx
  91. C ecx size
  92. C edx dst
  93. pushl %ebx
  94. movl %eax, %ebx C src
  95. deflit(`FRAME',4)
  96. movl (%ebx), %eax
  97. movl PARAM_DST, %ecx
  98. mull %eax C src[0]^2
  99. movl %eax, (%ecx)
  100. movl 4(%ebx), %eax
  101. movl %edx, 4(%ecx)
  102. mull %eax C src[1]^2
  103. movl %eax, 8(%ecx)
  104. movl (%ebx), %eax
  105. movl %edx, 12(%ecx)
  106. movl 4(%ebx), %edx
  107. mull %edx C src[0]*src[1]
  108. addl %eax, 4(%ecx)
  109. adcl %edx, 8(%ecx)
  110. adcl $0, 12(%ecx)
  111. popl %ebx
  112. addl %eax, 4(%ecx)
  113. adcl %edx, 8(%ecx)
  114. adcl $0, 12(%ecx)
  115. ret
  116. C -----------------------------------------------------------------------------
  117. L(three_or_more):
  118. deflit(`FRAME',0)
  119. cmpl $4, %ecx
  120. jae L(four_or_more)
  121. C -----------------------------------------------------------------------------
  122. C three limbs
  123. C eax src
  124. C ecx size
  125. C edx dst
  126. pushl %ebx
  127. movl %eax, %ebx C src
  128. movl (%ebx), %eax
  129. movl %edx, %ecx C dst
  130. mull %eax C src[0] ^ 2
  131. movl %eax, (%ecx)
  132. movl 4(%ebx), %eax
  133. movl %edx, 4(%ecx)
  134. pushl %esi
  135. mull %eax C src[1] ^ 2
  136. movl %eax, 8(%ecx)
  137. movl 8(%ebx), %eax
  138. movl %edx, 12(%ecx)
  139. pushl %edi
  140. mull %eax C src[2] ^ 2
  141. movl %eax, 16(%ecx)
  142. movl (%ebx), %eax
  143. movl %edx, 20(%ecx)
  144. movl 4(%ebx), %edx
  145. mull %edx C src[0] * src[1]
  146. movl %eax, %esi
  147. movl (%ebx), %eax
  148. movl %edx, %edi
  149. movl 8(%ebx), %edx
  150. pushl %ebp
  151. xorl %ebp, %ebp
  152. mull %edx C src[0] * src[2]
  153. addl %eax, %edi
  154. movl 4(%ebx), %eax
  155. adcl %edx, %ebp
  156. movl 8(%ebx), %edx
  157. mull %edx C src[1] * src[2]
  158. addl %eax, %ebp
  159. adcl $0, %edx
  160. C eax will be dst[5]
  161. C ebx
  162. C ecx dst
  163. C edx dst[4]
  164. C esi dst[1]
  165. C edi dst[2]
  166. C ebp dst[3]
  167. xorl %eax, %eax
  168. addl %esi, %esi
  169. adcl %edi, %edi
  170. adcl %ebp, %ebp
  171. adcl %edx, %edx
  172. adcl $0, %eax
  173. addl %esi, 4(%ecx)
  174. adcl %edi, 8(%ecx)
  175. adcl %ebp, 12(%ecx)
  176. popl %ebp
  177. popl %edi
  178. adcl %edx, 16(%ecx)
  179. popl %esi
  180. popl %ebx
  181. adcl %eax, 20(%ecx)
  182. ASSERT(nc)
  183. ret
  184. C -----------------------------------------------------------------------------
  185. defframe(SAVE_EBX,   -4)
  186. defframe(SAVE_ESI,   -8)
  187. defframe(SAVE_EDI,   -12)
  188. defframe(SAVE_EBP,   -16)
  189. defframe(VAR_COUNTER,-20)
  190. defframe(VAR_JMP,    -24)
  191. deflit(STACK_SPACE, 24)
  192. ALIGN(16)
  193. L(four_or_more):
  194. C eax src
  195. C ebx
  196. C ecx size
  197. C edx dst
  198. C esi
  199. C edi
  200. C ebp
  201. C First multiply src[0]*src[1..size-1] and store at dst[1..size].
  202. C
  203. C A test was done calling mpn_mul_1 here to get the benefit of its unrolled
  204. C loop, but this was only a tiny speedup; at 35 limbs it took 24 cycles off
  205. C a 5780 cycle operation, which is not surprising since the loop here is 8
  206. C c/l and mpn_mul_1 is 6.25 c/l.
  207. subl $STACK_SPACE, %esp deflit(`FRAME',STACK_SPACE)
  208. movl %edi, SAVE_EDI
  209. leal 4(%edx), %edi
  210. movl %ebx, SAVE_EBX
  211. leal 4(%eax), %ebx
  212. movl %esi, SAVE_ESI
  213. xorl %esi, %esi
  214. movl %ebp, SAVE_EBP
  215. C eax
  216. C ebx src+4
  217. C ecx size
  218. C edx
  219. C esi
  220. C edi dst+4
  221. C ebp
  222. movl (%eax), %ebp C multiplier
  223. leal -1(%ecx), %ecx C size-1, and pad to a 16 byte boundary
  224. ALIGN(16)
  225. L(mul_1):
  226. C eax scratch
  227. C ebx src ptr
  228. C ecx counter
  229. C edx scratch
  230. C esi carry
  231. C edi dst ptr
  232. C ebp multiplier
  233. movl (%ebx), %eax
  234. addl $4, %ebx
  235. mull %ebp
  236. addl %esi, %eax
  237. movl $0, %esi
  238. adcl %edx, %esi
  239. movl %eax, (%edi)
  240. addl $4, %edi
  241. loop L(mul_1)
  242. C Addmul src[n]*src[n+1..size-1] at dst[2*n-1...], for each n=1..size-2.
  243. C
  244. C The last two addmuls, which are the bottom right corner of the product
  245. C triangle, are left to the end.  These are src[size-3]*src[size-2,size-1]
  246. C and src[size-2]*src[size-1].  If size is 4 then it's only these corner
  247. C cases that need to be done.
  248. C
  249. C The unrolled code is the same as mpn_addmul_1(), see that routine for some
  250. C comments.
  251. C
  252. C VAR_COUNTER is the outer loop, running from -(size-4) to -1, inclusive.
  253. C
  254. C VAR_JMP is the computed jump into the unrolled code, stepped by one code
  255. C chunk each outer loop.
  256. C
  257. C K6 doesn't do any branch prediction on indirect jumps, which is good
  258. C actually because it's a different target each time.  The unrolled addmul
  259. C is about 3 cycles/limb faster than a simple loop, so the 6 cycle cost of
  260. C the indirect jump is quickly recovered.
  261. dnl  This value is also implicitly encoded in a shift and add.
  262. dnl
  263. deflit(CODE_BYTES_PER_LIMB, 15)
  264. dnl  With the unmodified &src[size] and &dst[size] pointers, the
  265. dnl  displacements in the unrolled code fit in a byte for UNROLL_COUNT
  266. dnl  values up to 31.  Above that an offset must be added to them.
  267. dnl
  268. deflit(OFFSET,
  269. ifelse(eval(UNROLL_COUNT>31),1,
  270. eval((UNROLL_COUNT-31)*4),
  271. 0))
  272. C eax
  273. C ebx &src[size]
  274. C ecx
  275. C edx
  276. C esi carry
  277. C edi &dst[size]
  278. C ebp
  279. movl PARAM_SIZE, %ecx
  280. movl %esi, (%edi)
  281. subl $4, %ecx
  282. jz L(corner)
  283. movl %ecx, %edx
  284. ifelse(OFFSET,0,,
  285. ` subl $OFFSET, %ebx')
  286. shll $4, %ecx
  287. ifelse(OFFSET,0,,
  288. ` subl $OFFSET, %edi')
  289. negl %ecx
  290. ifdef(`PIC',`
  291. call L(pic_calc)
  292. L(here):
  293. ',`
  294. leal L(unroll_inner_end)-eval(2*CODE_BYTES_PER_LIMB)(%ecx,%edx), %ecx
  295. ')
  296. negl %edx
  297. C The calculated jump mustn't be before the start of the available
  298. C code.  This is the limitation UNROLL_COUNT puts on the src operand
  299. C size, but checked here using the jump address directly.
  300. C
  301. ASSERT(ae,`
  302. movl_text_address( L(unroll_inner_start), %eax)
  303. cmpl %eax, %ecx
  304. ')
  305. C -----------------------------------------------------------------------------
  306. ALIGN(16)
  307. L(unroll_outer_top):
  308. C eax
  309. C ebx &src[size], constant
  310. C ecx VAR_JMP
  311. C edx VAR_COUNTER, limbs, negative
  312. C esi high limb to store
  313. C edi dst ptr, high of last addmul
  314. C ebp
  315. movl -12+OFFSET(%ebx,%edx,4), %ebp C multiplier
  316. movl %edx, VAR_COUNTER
  317. movl -8+OFFSET(%ebx,%edx,4), %eax C first limb of multiplicand
  318. mull %ebp
  319. testb $1, %cl
  320. movl %edx, %esi C high carry
  321. movl %ecx, %edx C jump
  322. movl %eax, %ecx C low carry
  323. leal CODE_BYTES_PER_LIMB(%edx), %edx
  324. movl %edx, VAR_JMP
  325. leal 4(%edi), %edi
  326. C A branch-free version of this using some xors was found to be a
  327. C touch slower than just a conditional jump, despite the jump
  328. C switching between taken and not taken on every loop.
  329. ifelse(eval(UNROLL_COUNT%2),0,
  330. jz,jnz) L(unroll_noswap)
  331. movl %esi, %eax C high,low carry other way around
  332. movl %ecx, %esi
  333. movl %eax, %ecx
  334. L(unroll_noswap):
  335. jmp *%edx
  336. C Must be on an even address here so the low bit of the jump address
  337. C will indicate which way around ecx/esi should start.
  338. C
  339. C An attempt was made at padding here to get the end of the unrolled
  340. C code to come out on a good alignment, to save padding before
  341. C L(corner).  This worked, but turned out to run slower than just an
  342. C ALIGN(2).  The reason for this is not clear, it might be related
  343. C to the different speeds on different UNROLL_COUNTs noted above.
  344. ALIGN(2)
  345. L(unroll_inner_start):
  346. C eax scratch
  347. C ebx src
  348. C ecx carry low
  349. C edx scratch
  350. C esi carry high
  351. C edi dst
  352. C ebp multiplier
  353. C
  354. C 15 code bytes each limb
  355. C ecx/esi swapped on each chunk
  356. forloop(`i', UNROLL_COUNT, 1, `
  357. deflit(`disp_src', eval(-i*4 + OFFSET))
  358. deflit(`disp_dst', eval(disp_src - 4))
  359. m4_assert(`disp_src>=-128 && disp_src<128')
  360. m4_assert(`disp_dst>=-128 && disp_dst<128')
  361. ifelse(eval(i%2),0,`
  362. Zdisp( movl, disp_src,(%ebx), %eax)
  363. mull %ebp
  364. Zdisp( addl, %esi, disp_dst,(%edi))
  365. adcl %eax, %ecx
  366. movl %edx, %esi
  367. jadcl0( %esi)
  368. ',`
  369. dnl  this one comes out last
  370. Zdisp( movl, disp_src,(%ebx), %eax)
  371. mull %ebp
  372. Zdisp( addl, %ecx, disp_dst,(%edi))
  373. adcl %eax, %esi
  374. movl %edx, %ecx
  375. jadcl0( %ecx)
  376. ')
  377. ')
  378. L(unroll_inner_end):
  379. addl %esi, -4+OFFSET(%edi)
  380. movl VAR_COUNTER, %edx
  381. jadcl0( %ecx)
  382. movl %ecx, m4_empty_if_zero(OFFSET)(%edi)
  383. movl VAR_JMP, %ecx
  384. incl %edx
  385. jnz L(unroll_outer_top)
  386. ifelse(OFFSET,0,,`
  387. addl $OFFSET, %ebx
  388. addl $OFFSET, %edi
  389. ')
  390. C -----------------------------------------------------------------------------
  391. ALIGN(16)
  392. L(corner):
  393. C ebx &src[size]
  394. C edi &dst[2*size-5]
  395. movl -12(%ebx), %ebp
  396. movl -8(%ebx), %eax
  397. movl %eax, %ecx
  398. mull %ebp
  399. addl %eax, -4(%edi)
  400. adcl $0, %edx
  401. movl -4(%ebx), %eax
  402. movl %edx, %esi
  403. movl %eax, %ebx
  404. mull %ebp
  405. addl %esi, %eax
  406. adcl $0, %edx
  407. addl %eax, (%edi)
  408. adcl $0, %edx
  409. movl %edx, %esi
  410. movl %ebx, %eax
  411. mull %ecx
  412. addl %esi, %eax
  413. movl %eax, 4(%edi)
  414. adcl $0, %edx
  415. movl %edx, 8(%edi)
  416. C -----------------------------------------------------------------------------
  417. C Left shift of dst[1..2*size-2], the bit shifted out becomes dst[2*size-1].
  418. C The loop measures about 6 cycles/iteration, though it looks like it should
  419. C decode in 5.
  420. L(lshift_start):
  421. movl PARAM_SIZE, %ecx
  422. movl PARAM_DST, %edi
  423. subl $1, %ecx C size-1 and clear carry
  424. movl PARAM_SRC, %ebx
  425. movl %ecx, %edx
  426. xorl %eax, %eax C ready for adcl
  427. ALIGN(16)
  428. L(lshift):
  429. C eax
  430. C ebx src (for later use)
  431. C ecx counter, decrementing
  432. C edx size-1 (for later use)
  433. C esi
  434. C edi dst, incrementing
  435. C ebp
  436. rcll 4(%edi)
  437. rcll 8(%edi)
  438. leal 8(%edi), %edi
  439. loop L(lshift)
  440. adcl %eax, %eax
  441. movl %eax, 4(%edi) C dst most significant limb
  442. movl (%ebx), %eax C src[0]
  443. leal 4(%ebx,%edx,4), %ebx C &src[size]
  444. subl %edx, %ecx C -(size-1)
  445. C -----------------------------------------------------------------------------
  446. C Now add in the squares on the diagonal, src[0]^2, src[1]^2, ...,
  447. C src[size-1]^2.  dst[0] hasn't yet been set at all yet, and just gets the
  448. C low limb of src[0]^2.
  449. mull %eax
  450. movl %eax, (%edi,%ecx,8) C dst[0]
  451. ALIGN(16)
  452. L(diag):
  453. C eax scratch
  454. C ebx &src[size]
  455. C ecx counter, negative
  456. C edx carry
  457. C esi scratch
  458. C edi dst[2*size-2]
  459. C ebp
  460. movl (%ebx,%ecx,4), %eax
  461. movl %edx, %esi
  462. mull %eax
  463. addl %esi, 4(%edi,%ecx,8)
  464. adcl %eax, 8(%edi,%ecx,8)
  465. adcl $0, %edx
  466. incl %ecx
  467. jnz L(diag)
  468. movl SAVE_EBX, %ebx
  469. movl SAVE_ESI, %esi
  470. addl %edx, 4(%edi) C dst most significant limb
  471. movl SAVE_EDI, %edi
  472. movl SAVE_EBP, %ebp
  473. addl $FRAME, %esp
  474. ret
  475. C -----------------------------------------------------------------------------
  476. ifdef(`PIC',`
  477. L(pic_calc):
  478. C See mpn/x86/README about old gas bugs
  479. addl (%esp), %ecx
  480. addl $L(unroll_inner_end)-L(here)-eval(2*CODE_BYTES_PER_LIMB), %ecx
  481. addl %edx, %ecx
  482. ret_internal
  483. ')
  484. EPILOGUE()