Index: gcc/gmp/mpn/x86/k6/sqr_basecase.asm |
diff --git a/gcc/gmp/mpn/x86/k6/sqr_basecase.asm b/gcc/gmp/mpn/x86/k6/sqr_basecase.asm |
deleted file mode 100644 |
index 3392d38812e3e87b6de4909011ecce29cfc8a61c..0000000000000000000000000000000000000000 |
--- a/gcc/gmp/mpn/x86/k6/sqr_basecase.asm |
+++ /dev/null |
@@ -1,669 +0,0 @@ |
-dnl AMD K6 mpn_sqr_basecase -- square an mpn number. |
- |
-dnl Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc. |
-dnl |
-dnl This file is part of the GNU MP Library. |
-dnl |
-dnl The GNU MP Library is free software; you can redistribute it and/or |
-dnl modify it under the terms of the GNU Lesser General Public License as |
-dnl published by the Free Software Foundation; either version 3 of the |
-dnl License, or (at your option) any later version. |
-dnl |
-dnl The GNU MP Library is distributed in the hope that it will be useful, |
-dnl but WITHOUT ANY WARRANTY; without even the implied warranty of |
-dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
-dnl Lesser General Public License for more details. |
-dnl |
-dnl You should have received a copy of the GNU Lesser General Public License |
-dnl along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. |
- |
-include(`../config.m4') |
- |
- |
-C K6: approx 4.7 cycles per cross product, or 9.2 cycles per triangular |
-C product (measured on the speed difference between 17 and 33 limbs, |
-C which is roughly the Karatsuba recursing range). |
- |
- |
-dnl SQR_KARATSUBA_THRESHOLD_MAX is the maximum SQR_KARATSUBA_THRESHOLD this |
-dnl code supports. This value is used only by the tune program to know |
-dnl what it can go up to. (An attempt to compile with a bigger value will |
-dnl trigger some m4_assert()s in the code, making the build fail.) |
-dnl |
-dnl The value is determined by requiring the displacements in the unrolled |
-dnl addmul to fit in single bytes. This means a maximum UNROLL_COUNT of |
-dnl 63, giving a maximum SQR_KARATSUBA_THRESHOLD of 66. |
- |
-deflit(SQR_KARATSUBA_THRESHOLD_MAX, 66) |
- |
- |
-dnl Allow a value from the tune program to override config.m4. |
- |
-ifdef(`SQR_KARATSUBA_THRESHOLD_OVERRIDE', |
-`define(`SQR_KARATSUBA_THRESHOLD',SQR_KARATSUBA_THRESHOLD_OVERRIDE)') |
- |
- |
-dnl UNROLL_COUNT is the number of code chunks in the unrolled addmul. The |
-dnl number required is determined by SQR_KARATSUBA_THRESHOLD, since |
-dnl mpn_sqr_basecase only needs to handle sizes < SQR_KARATSUBA_THRESHOLD. |
-dnl |
-dnl The first addmul is the biggest, and this takes the second least |
-dnl significant limb and multiplies it by the third least significant and |
-dnl up. Hence for a maximum operand size of SQR_KARATSUBA_THRESHOLD-1 |
-dnl limbs, UNROLL_COUNT needs to be SQR_KARATSUBA_THRESHOLD-3. |
- |
-m4_config_gmp_mparam(`SQR_KARATSUBA_THRESHOLD') |
-deflit(UNROLL_COUNT, eval(SQR_KARATSUBA_THRESHOLD-3)) |
- |
- |
-C void mpn_sqr_basecase (mp_ptr dst, mp_srcptr src, mp_size_t size); |
-C |
-C The algorithm is essentially the same as mpn/generic/sqr_basecase.c, but a |
-C lot of function call overheads are avoided, especially when the given size |
-C is small. |
-C |
-C The code size might look a bit excessive, but not all of it is executed |
-C and so won't fill up the code cache. The 1x1, 2x2 and 3x3 special cases |
-C clearly apply only to those sizes; mid sizes like 10x10 only need part of |
-C the unrolled addmul; and big sizes like 35x35 that do need all of it will |
-C at least be getting value for money, because 35x35 spends something like |
-C 5780 cycles here. |
-C |
-C Different values of UNROLL_COUNT give slightly different speeds, between |
-C 9.0 and 9.2 c/tri-prod measured on the difference between 17 and 33 limbs. |
-C This isn't a big difference, but it's presumably some alignment effect |
-C which if understood could give a simple speedup. |
- |
-defframe(PARAM_SIZE,12) |
-defframe(PARAM_SRC, 8) |
-defframe(PARAM_DST, 4) |
- |
- TEXT |
- ALIGN(32) |
-PROLOGUE(mpn_sqr_basecase) |
-deflit(`FRAME',0) |
- |
- movl PARAM_SIZE, %ecx |
- movl PARAM_SRC, %eax |
- |
- cmpl $2, %ecx |
- je L(two_limbs) |
- |
- movl PARAM_DST, %edx |
- ja L(three_or_more) |
- |
- |
-C ----------------------------------------------------------------------------- |
-C one limb only |
- C eax src |
- C ebx |
- C ecx size |
- C edx dst |
- |
- movl (%eax), %eax |
- movl %edx, %ecx |
- |
- mull %eax |
- |
- movl %eax, (%ecx) |
- movl %edx, 4(%ecx) |
- ret |
- |
- |
-C ----------------------------------------------------------------------------- |
- ALIGN(16) |
-L(two_limbs): |
- C eax src |
- C ebx |
- C ecx size |
- C edx dst |
- |
- pushl %ebx |
- movl %eax, %ebx C src |
-deflit(`FRAME',4) |
- |
- movl (%ebx), %eax |
- movl PARAM_DST, %ecx |
- |
- mull %eax C src[0]^2 |
- |
- movl %eax, (%ecx) |
- movl 4(%ebx), %eax |
- |
- movl %edx, 4(%ecx) |
- |
- mull %eax C src[1]^2 |
- |
- movl %eax, 8(%ecx) |
- movl (%ebx), %eax |
- |
- movl %edx, 12(%ecx) |
- movl 4(%ebx), %edx |
- |
- mull %edx C src[0]*src[1] |
- |
- addl %eax, 4(%ecx) |
- |
- adcl %edx, 8(%ecx) |
- adcl $0, 12(%ecx) |
- |
- popl %ebx |
- addl %eax, 4(%ecx) |
- |
- adcl %edx, 8(%ecx) |
- adcl $0, 12(%ecx) |
- |
- ret |
- |
- |
-C ----------------------------------------------------------------------------- |
-L(three_or_more): |
-deflit(`FRAME',0) |
- cmpl $4, %ecx |
- jae L(four_or_more) |
- |
- |
-C ----------------------------------------------------------------------------- |
-C three limbs |
- C eax src |
- C ecx size |
- C edx dst |
- |
- pushl %ebx |
- movl %eax, %ebx C src |
- |
- movl (%ebx), %eax |
- movl %edx, %ecx C dst |
- |
- mull %eax C src[0] ^ 2 |
- |
- movl %eax, (%ecx) |
- movl 4(%ebx), %eax |
- |
- movl %edx, 4(%ecx) |
- pushl %esi |
- |
- mull %eax C src[1] ^ 2 |
- |
- movl %eax, 8(%ecx) |
- movl 8(%ebx), %eax |
- |
- movl %edx, 12(%ecx) |
- pushl %edi |
- |
- mull %eax C src[2] ^ 2 |
- |
- movl %eax, 16(%ecx) |
- movl (%ebx), %eax |
- |
- movl %edx, 20(%ecx) |
- movl 4(%ebx), %edx |
- |
- mull %edx C src[0] * src[1] |
- |
- movl %eax, %esi |
- movl (%ebx), %eax |
- |
- movl %edx, %edi |
- movl 8(%ebx), %edx |
- |
- pushl %ebp |
- xorl %ebp, %ebp |
- |
- mull %edx C src[0] * src[2] |
- |
- addl %eax, %edi |
- movl 4(%ebx), %eax |
- |
- adcl %edx, %ebp |
- |
- movl 8(%ebx), %edx |
- |
- mull %edx C src[1] * src[2] |
- |
- addl %eax, %ebp |
- |
- adcl $0, %edx |
- |
- |
- C eax will be dst[5] |
- C ebx |
- C ecx dst |
- C edx dst[4] |
- C esi dst[1] |
- C edi dst[2] |
- C ebp dst[3] |
- |
- xorl %eax, %eax |
- addl %esi, %esi |
- adcl %edi, %edi |
- adcl %ebp, %ebp |
- adcl %edx, %edx |
- adcl $0, %eax |
- |
- addl %esi, 4(%ecx) |
- adcl %edi, 8(%ecx) |
- adcl %ebp, 12(%ecx) |
- |
- popl %ebp |
- popl %edi |
- |
- adcl %edx, 16(%ecx) |
- |
- popl %esi |
- popl %ebx |
- |
- adcl %eax, 20(%ecx) |
- ASSERT(nc) |
- |
- ret |
- |
- |
-C ----------------------------------------------------------------------------- |
- |
-defframe(SAVE_EBX, -4) |
-defframe(SAVE_ESI, -8) |
-defframe(SAVE_EDI, -12) |
-defframe(SAVE_EBP, -16) |
-defframe(VAR_COUNTER,-20) |
-defframe(VAR_JMP, -24) |
-deflit(STACK_SPACE, 24) |
- |
- ALIGN(16) |
-L(four_or_more): |
- |
- C eax src |
- C ebx |
- C ecx size |
- C edx dst |
- C esi |
- C edi |
- C ebp |
- |
-C First multiply src[0]*src[1..size-1] and store at dst[1..size]. |
-C |
-C A test was done calling mpn_mul_1 here to get the benefit of its unrolled |
-C loop, but this was only a tiny speedup; at 35 limbs it took 24 cycles off |
-C a 5780 cycle operation, which is not surprising since the loop here is 8 |
-C c/l and mpn_mul_1 is 6.25 c/l. |
- |
- subl $STACK_SPACE, %esp deflit(`FRAME',STACK_SPACE) |
- |
- movl %edi, SAVE_EDI |
- leal 4(%edx), %edi |
- |
- movl %ebx, SAVE_EBX |
- leal 4(%eax), %ebx |
- |
- movl %esi, SAVE_ESI |
- xorl %esi, %esi |
- |
- movl %ebp, SAVE_EBP |
- |
- C eax |
- C ebx src+4 |
- C ecx size |
- C edx |
- C esi |
- C edi dst+4 |
- C ebp |
- |
- movl (%eax), %ebp C multiplier |
- leal -1(%ecx), %ecx C size-1, and pad to a 16 byte boundary |
- |
- |
- ALIGN(16) |
-L(mul_1): |
- C eax scratch |
- C ebx src ptr |
- C ecx counter |
- C edx scratch |
- C esi carry |
- C edi dst ptr |
- C ebp multiplier |
- |
- movl (%ebx), %eax |
- addl $4, %ebx |
- |
- mull %ebp |
- |
- addl %esi, %eax |
- movl $0, %esi |
- |
- adcl %edx, %esi |
- |
- movl %eax, (%edi) |
- addl $4, %edi |
- |
- loop L(mul_1) |
- |
- |
-C Addmul src[n]*src[n+1..size-1] at dst[2*n-1...], for each n=1..size-2. |
-C |
-C The last two addmuls, which are the bottom right corner of the product |
-C triangle, are left to the end. These are src[size-3]*src[size-2,size-1] |
-C and src[size-2]*src[size-1]. If size is 4 then it's only these corner |
-C cases that need to be done. |
-C |
-C The unrolled code is the same as mpn_addmul_1(), see that routine for some |
-C comments. |
-C |
-C VAR_COUNTER is the outer loop, running from -(size-4) to -1, inclusive. |
-C |
-C VAR_JMP is the computed jump into the unrolled code, stepped by one code |
-C chunk each outer loop. |
-C |
-C K6 doesn't do any branch prediction on indirect jumps, which is good |
-C actually because it's a different target each time. The unrolled addmul |
-C is about 3 cycles/limb faster than a simple loop, so the 6 cycle cost of |
-C the indirect jump is quickly recovered. |
- |
- |
-dnl This value is also implicitly encoded in a shift and add. |
-dnl |
-deflit(CODE_BYTES_PER_LIMB, 15) |
- |
-dnl With the unmodified &src[size] and &dst[size] pointers, the |
-dnl displacements in the unrolled code fit in a byte for UNROLL_COUNT |
-dnl values up to 31. Above that an offset must be added to them. |
-dnl |
-deflit(OFFSET, |
-ifelse(eval(UNROLL_COUNT>31),1, |
-eval((UNROLL_COUNT-31)*4), |
-0)) |
- |
- C eax |
- C ebx &src[size] |
- C ecx |
- C edx |
- C esi carry |
- C edi &dst[size] |
- C ebp |
- |
- movl PARAM_SIZE, %ecx |
- movl %esi, (%edi) |
- |
- subl $4, %ecx |
- jz L(corner) |
- |
- movl %ecx, %edx |
-ifelse(OFFSET,0,, |
-` subl $OFFSET, %ebx') |
- |
- shll $4, %ecx |
-ifelse(OFFSET,0,, |
-` subl $OFFSET, %edi') |
- |
- negl %ecx |
- |
-ifdef(`PIC',` |
- call L(pic_calc) |
-L(here): |
-',` |
- leal L(unroll_inner_end)-eval(2*CODE_BYTES_PER_LIMB)(%ecx,%edx), %ecx |
-') |
- negl %edx |
- |
- |
- C The calculated jump mustn't be before the start of the available |
- C code. This is the limitation UNROLL_COUNT puts on the src operand |
- C size, but checked here using the jump address directly. |
- C |
- ASSERT(ae,` |
- movl_text_address( L(unroll_inner_start), %eax) |
- cmpl %eax, %ecx |
- ') |
- |
- |
-C ----------------------------------------------------------------------------- |
- ALIGN(16) |
-L(unroll_outer_top): |
- C eax |
- C ebx &src[size], constant |
- C ecx VAR_JMP |
- C edx VAR_COUNTER, limbs, negative |
- C esi high limb to store |
- C edi dst ptr, high of last addmul |
- C ebp |
- |
- movl -12+OFFSET(%ebx,%edx,4), %ebp C multiplier |
- movl %edx, VAR_COUNTER |
- |
- movl -8+OFFSET(%ebx,%edx,4), %eax C first limb of multiplicand |
- |
- mull %ebp |
- |
- testb $1, %cl |
- |
- movl %edx, %esi C high carry |
- movl %ecx, %edx C jump |
- |
- movl %eax, %ecx C low carry |
- leal CODE_BYTES_PER_LIMB(%edx), %edx |
- |
- movl %edx, VAR_JMP |
- leal 4(%edi), %edi |
- |
- C A branch-free version of this using some xors was found to be a |
- C touch slower than just a conditional jump, despite the jump |
- C switching between taken and not taken on every loop. |
- |
-ifelse(eval(UNROLL_COUNT%2),0, |
- jz,jnz) L(unroll_noswap) |
- movl %esi, %eax C high,low carry other way around |
- |
- movl %ecx, %esi |
- movl %eax, %ecx |
-L(unroll_noswap): |
- |
- jmp *%edx |
- |
- |
- C Must be on an even address here so the low bit of the jump address |
- C will indicate which way around ecx/esi should start. |
- C |
- C An attempt was made at padding here to get the end of the unrolled |
- C code to come out on a good alignment, to save padding before |
- C L(corner). This worked, but turned out to run slower than just an |
- C ALIGN(2). The reason for this is not clear, it might be related |
- C to the different speeds on different UNROLL_COUNTs noted above. |
- |
- ALIGN(2) |
- |
-L(unroll_inner_start): |
- C eax scratch |
- C ebx src |
- C ecx carry low |
- C edx scratch |
- C esi carry high |
- C edi dst |
- C ebp multiplier |
- C |
- C 15 code bytes each limb |
- C ecx/esi swapped on each chunk |
- |
-forloop(`i', UNROLL_COUNT, 1, ` |
- deflit(`disp_src', eval(-i*4 + OFFSET)) |
- deflit(`disp_dst', eval(disp_src - 4)) |
- |
- m4_assert(`disp_src>=-128 && disp_src<128') |
- m4_assert(`disp_dst>=-128 && disp_dst<128') |
- |
-ifelse(eval(i%2),0,` |
-Zdisp( movl, disp_src,(%ebx), %eax) |
- mull %ebp |
-Zdisp( addl, %esi, disp_dst,(%edi)) |
- adcl %eax, %ecx |
- movl %edx, %esi |
- jadcl0( %esi) |
-',` |
- dnl this one comes out last |
-Zdisp( movl, disp_src,(%ebx), %eax) |
- mull %ebp |
-Zdisp( addl, %ecx, disp_dst,(%edi)) |
- adcl %eax, %esi |
- movl %edx, %ecx |
- jadcl0( %ecx) |
-') |
-') |
-L(unroll_inner_end): |
- |
- addl %esi, -4+OFFSET(%edi) |
- |
- movl VAR_COUNTER, %edx |
- jadcl0( %ecx) |
- |
- movl %ecx, m4_empty_if_zero(OFFSET)(%edi) |
- movl VAR_JMP, %ecx |
- |
- incl %edx |
- jnz L(unroll_outer_top) |
- |
- |
-ifelse(OFFSET,0,,` |
- addl $OFFSET, %ebx |
- addl $OFFSET, %edi |
-') |
- |
- |
-C ----------------------------------------------------------------------------- |
- ALIGN(16) |
-L(corner): |
- C ebx &src[size] |
- C edi &dst[2*size-5] |
- |
- movl -12(%ebx), %ebp |
- |
- movl -8(%ebx), %eax |
- movl %eax, %ecx |
- |
- mull %ebp |
- |
- addl %eax, -4(%edi) |
- adcl $0, %edx |
- |
- movl -4(%ebx), %eax |
- movl %edx, %esi |
- movl %eax, %ebx |
- |
- mull %ebp |
- |
- addl %esi, %eax |
- adcl $0, %edx |
- |
- addl %eax, (%edi) |
- adcl $0, %edx |
- |
- movl %edx, %esi |
- movl %ebx, %eax |
- |
- mull %ecx |
- |
- addl %esi, %eax |
- movl %eax, 4(%edi) |
- |
- adcl $0, %edx |
- |
- movl %edx, 8(%edi) |
- |
- |
-C ----------------------------------------------------------------------------- |
-C Left shift of dst[1..2*size-2], the bit shifted out becomes dst[2*size-1]. |
-C The loop measures about 6 cycles/iteration, though it looks like it should |
-C decode in 5. |
- |
-L(lshift_start): |
- movl PARAM_SIZE, %ecx |
- |
- movl PARAM_DST, %edi |
- subl $1, %ecx C size-1 and clear carry |
- |
- movl PARAM_SRC, %ebx |
- movl %ecx, %edx |
- |
- xorl %eax, %eax C ready for adcl |
- |
- |
- ALIGN(16) |
-L(lshift): |
- C eax |
- C ebx src (for later use) |
- C ecx counter, decrementing |
- C edx size-1 (for later use) |
- C esi |
- C edi dst, incrementing |
- C ebp |
- |
- rcll 4(%edi) |
- rcll 8(%edi) |
- leal 8(%edi), %edi |
- loop L(lshift) |
- |
- |
- adcl %eax, %eax |
- |
- movl %eax, 4(%edi) C dst most significant limb |
- movl (%ebx), %eax C src[0] |
- |
- leal 4(%ebx,%edx,4), %ebx C &src[size] |
- subl %edx, %ecx C -(size-1) |
- |
- |
-C ----------------------------------------------------------------------------- |
-C Now add in the squares on the diagonal, src[0]^2, src[1]^2, ..., |
-C src[size-1]^2. dst[0] hasn't yet been set at all yet, and just gets the |
-C low limb of src[0]^2. |
- |
- |
- mull %eax |
- |
- movl %eax, (%edi,%ecx,8) C dst[0] |
- |
- |
- ALIGN(16) |
-L(diag): |
- C eax scratch |
- C ebx &src[size] |
- C ecx counter, negative |
- C edx carry |
- C esi scratch |
- C edi dst[2*size-2] |
- C ebp |
- |
- movl (%ebx,%ecx,4), %eax |
- movl %edx, %esi |
- |
- mull %eax |
- |
- addl %esi, 4(%edi,%ecx,8) |
- adcl %eax, 8(%edi,%ecx,8) |
- adcl $0, %edx |
- |
- incl %ecx |
- jnz L(diag) |
- |
- |
- movl SAVE_EBX, %ebx |
- movl SAVE_ESI, %esi |
- |
- addl %edx, 4(%edi) C dst most significant limb |
- |
- movl SAVE_EDI, %edi |
- movl SAVE_EBP, %ebp |
- addl $FRAME, %esp |
- ret |
- |
- |
- |
-C ----------------------------------------------------------------------------- |
-ifdef(`PIC',` |
-L(pic_calc): |
- C See mpn/x86/README about old gas bugs |
- addl (%esp), %ecx |
- addl $L(unroll_inner_end)-L(here)-eval(2*CODE_BYTES_PER_LIMB), %ecx |
- addl %edx, %ecx |
- ret_internal |
-') |
- |
- |
-EPILOGUE() |